tensorflow 图像分类实战解析(上)

之前一直是想解决从规定的文件名列表里面读取图片并且放入TF训练的问题,stackoverflow上面找到了这个答案:http://stackoverflow.com/questions/37450620/tensorflow-image-classification,虽然并非是我最想达到的效果,但毕竟是一个有用的蓝本,在之后以这个为基础再进行改进吧,所以想把这一段代码深入理解一下。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import time
import math
import numpy
import numpy as np
import random
from PIL import Image

使用IPL库来读取图片,其实在这个框架里面就算使用pyplot.iamge来读取图片也没有什么问题
我对比了一些开源库对于读取图像这个问题的解决方案,能够跑的动的方案其实效果都不是非常理想。比如可以使用opencv来做读图图像的接口,YOLO-py中就是这么做的,大致代码如下:

import cv2
img = cv2.imread("xxx.jpg")
#you can do some cv2 process
img_arrayy = np.array(img).resize(imagePixes,1)
#do some tensorflow process
feeddict = {placeholder:im_array}

但是这些方法依然存在着内存消耗过大的问题(在较多训练样本的情况下,没有办法一次性导入大量样本,毕竟这些样本全部都存在于内存中)现在拟定的解决方案是按照batch分批次读取图片,这个在后续的更新中会把代码放出来

from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

# Basic model parameters as external flags.
flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_float('learning_rate', 0.01, 'Initial learning rate.')
flags.DEFINE_integer('max_steps', 2000, 'Number of steps to run trainer.')

flags.DEFINE_integer('hidden2', 32, 'Number of units in hidden layer 2.')
flags.DEFINE_integer('batch_size', 4, 'Batch size.  '
                     'Must divide evenly into the dataset sizes.')
flags.DEFINE_string('train_dir', '/home/air/_ImageScoring/database/subData1', 'Directory to put the training data.')
flags.DEFINE_boolean('fake_data', False, 'If true, uses fake data '
                     'for unit testing.')

类似G-flags的一种做法,但是似乎内部实现并非调用的G-flags,使用方法是flags.DEFINE_xxx(‘name’, default, ‘disccribe’)其中xxx是数据类型,如果和G-flags一样,那赢还是有float,int,string,bool等数据类型的。name为该变量的名字,default为默认值,describe为对于这个变量的描述。应该是还有一个函数用于控制台输入 的参数解析的,但是文档里并不介绍FLAGS里面的内容,所以现在姑且作为一个全局变量来使用,使用时候只要FLAGS.xxx就可以了。(理论上应该还有一个set方法和检测变量变化的方法,但是没有去深究)

NUM_CLASSES = 2
IMAGE_SIZE = 256
CHANNELS = 3
IMAGE_PIXELS = IMAGE_SIZE * IMAGE_SIZE * CHANNELS

图片的类别数目,图片大小(设定长宽相同)通道数目为3,并以此计算图片像素的数目。

def inference(images, hidden1_units, hidden2_units):

定义网络结构

  # Hidden 1
  with tf.name_scope('hidden1'):
    weights = tf.Variable(
        tf.truncated_normal([IMAGE_PIXELS, hidden1_units],
                            stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))),
        name='weights')

生成截尾正态分布的初始值作为第一层隐层的权值,其shape为
IMAGE_PIXELS X hidden1_units,实际就是一个二维矩阵。
但是现在不是特别明白为什么要用截尾正态分布来进行过权值的初始化。因为在theano里面,权值初始化是扇入扇出系数相关的一个均匀分布。http://www.cnblogs.com/liujshi/p/5616171.html 这篇资料也许可以说明一些问题,但是并不能说明这个问题的全部。

    biases = tf.Variable(tf.zeros([hidden1_units]),
                         name='biases')

全部初始化为0的偏置层

    hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)

relu激活层。现在神经网络里面,较多的用relu替代了sigmiod,解释可以参考下http://www.cnblogs.com/neopenx/p/4453161.html 这篇

  # Hidden 2
  with tf.name_scope('hidden2'):
    weights = tf.Variable(
        tf.truncated_normal([hidden1_units, hidden2_units],
                            stddev=1.0 / math.sqrt(float(hidden1_units))),
        name='weights')
    biases = tf.Variable(tf.zeros([hidden2_units]),
                         name='biases')
    hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
  # Linear
  with tf.name_scope('softmax_linear'):
    weights = tf.Variable(
        tf.truncated_normal([hidden2_units, NUM_CLASSES],
                            stddev=1.0 / math.sqrt(float(hidden2_units))),
        name='weights')

第二个隐层的权值
输出数目为class的数目

    biases = tf.Variable(tf.zeros([NUM_CLASSES]),
                         name='biases')
    logits = tf.matmul(hidden2, weights) + biases

使用罗杰斯特回归做预测

  return logits


def cal_loss(logits, labels):

定义loss

  labels = tf.to_int64(labels)
  cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
      logits, labels, name='xentropy')

使用交叉熵loss。交叉熵LOSS很有意思,想想最早使用的欧氏距离loss,其导数形式会存在一个个内层函数的单独求导,最终得到一个sigmiod的导数相乘的形式,问题就在于,偏差很大的时候,由于sigmiod函数的平坦性,导致其导数数值会非常小,最终那一计算。处于消除这个导数乘积项目的考虑,引入了交叉熵loss

  loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')
  return loss



def training(loss, learning_rate):
  optimizer = tf.train.GradientDescentOptimizer(learning_rate)

定义一个梯度下降的优化器