tensorflow卷积神经网络例子
本文是对tensorflow教程中的cifar数据集卷积神经网络例子进行学习后的笔记,主要记录了一些相关方法的使用。
模型输入
模型的输入包括input()、distorted_inputs等一些操作,分别用于读取CIFAR图像并进行预处理。
文件处理流程:
- 统一裁剪到24 * 24像素大小,裁剪中央区域
- 近似白化处理,使得模型对动态范围变化不敏感
distorted_image = tf.random_crop(reshaped_image, [height, width,3])
float_image = tf.image.per_image_standardization(distorted_image)
对于训练集,可以采取一系列的随机变换方法来人为增加数据集的大小:
- 对图像进行左右翻转
- 随机变换图像的亮度
- 随机变换突袭那个的对比度
distorted_image = tf.image.random_flip_left_right(distorted_image)
distorted_image = tf.image.random_brightness(distorted_image, max_delta=63)
distorted_image = tf.image.random_contrast(distorted_image, lower=0.2, upper=1.8)
文件读取机制
在tensorflow中有一种文件读取是通过里那个队列的完成,一个是内存队列,一个是文件名队列。使用tf.string_input_producer(num_pochs, shuffle=False)来产生文件名队列,在tensorflow中内存队列不需要我们自己建立,我们只需要使用reader对象从文件名队列中读取数据就可以。需要注意的是,在我们使用tf.string_input_producer(num_pochs, shuffle=False)创建文件名队列的时候,整个系统还是处于停滞的状态,也就是说,我们的文件名还未真正加入到队列中,我们需要使用tf.train.start_queue_runners()之后才真正启动填充队列的线程。
可以参考以下一段简单的代码:
# --*- coding:utf-8 -*--
import os
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
train_dir = 'your path'
def get_files(file_dir):
cats = []
label_cats = []
dogs = []
label_dogs = []
for file in os.listdir(file_dir + '/cat'):
cats.append(file_dir + 'cat' + '/' + file)
label_cats.append(0)
for file in os.listdir(file_dir + '/dog'):
dogs.append(file_dir + 'dog' + '/' + file)
label_dogs.append(1)
#把cat和dog合起来组成一个list(img和lab)
image_list = np.hstack((cats, dogs))
label_list = np.hstack((label_cats, label_dogs))
#利用shuffle打乱顺序
temp = np.array([image_list, label_list])
temp = temp.transpose()
np.random.shuffle(temp)
#从打乱的temp中再取出list(img和lab)
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
label_list = [int(i) for i in label_list]
return image_list, label_list
BATCH_SIZE = 2
CAPACITY = 256
IMG_W = 208
IMG_H = 208
def get_batch(image, label, image_W, image_H, batch_size, capacity):
image = tf.cast(image, tf.string)
label = tf.cast(label, tf.int32)
#产生一个输入队列queue,因为img和lab是分开的,所以使用tf.train.slice_input_producer(),然后用tf.read_file()从队列中读取图像
input_queue = tf.train.slice_input_producer([image, label])
label = input_queue[1]
image_contents = tf.read_file(input_queue[0]) # read img from a queue
image = tf.image.decode_jpeg(image_contents, channels=3)
image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H)
#image = tf.image.per_image_standardization(image)
image = tf.image.random_flip_left_right(image)
image = tf.image.random_contrast(image,
lower=0.2, upper=1.8)
image_batch, label_batch = tf.train.batch([image, label],
batch_size=batch_size,
num_threads=32,
capacity=capacity)
# 重新排列label,行数为[batch_size]
label_batch = tf.reshape(label_batch, [batch_size])
#image_batch = tf.cast(image_batch, tf.float32)
return image_batch, label_batch
image_list, label_list = get_files(train_dir)
image_batch, label_batch = get_batch(image_list, label_list,IMG_W, IMG_H, BATCH_SIZE, CAPACITY)
with tf.Session() as sess:
i = 0
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
try:
while not coord.should_stop() and i < 20:
img, label = sess.run([image_batch, label_batch])
for j in np.arange(BATCH_SIZE):
print('label: %d' %label[j])
plt.imshow(img[j,:,:,:])
plt.show()
i += 1
except tf.errors.OutOfRangeError:
print('Done')
finally:
coord.request_stop()
coord.join(threads)
训练模型
模型的训练包括loss()和train()等一些操作,用于计算损失,计算梯度、进行变量更新以及呈现最终的结果。
logits = cifar10.inference(images)
# Calculate loss.
loss = cifar10.loss(logits=logits, labels=labels)
# Build a Graph that trains the model with one batch of examples and
# updates the model parameters.
train_op = cifar10.train(loss, global_step)
# Create a saver.
saver = tf.train.Saver(tf.all_variables())
- inference()
这部分主要是网络的设置,包括两个卷积层,三个局部连接层,用于构造分类模型。这部分代码全部采用的是tf.get_variable(),和tf.Variable()的主要区别在于tf.get_variable()可用于共享机制,若某变量名已存在,则返回该值,而后者不管是否存在都会返回新的变量。
import tensorflow as tf
with tf.variable_scope("scope1"):
w1 = tf.get_variable("w1", shape=[])
w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
w1_p = tf.get_variable("w1", shape=[])
w2_p = tf.Variable(1.0, name="w2")
print(w1 is w1_p, w2 is w2_p)
- loss()
此处定义的loss是交叉熵损失加上所有w的的L2正则。
tf.add_n(tf.get_collection('losses'), name='total_loss')
在tensorflow中,tensorflow的collection提供一个全局的存储机制,不会受到变量名生存空间的影响。一处保存,到处可取。也就是说,一个名称下,可以储存多个值。
- train()
# Compute gradients.
with tf.control_dependencies([loss_averages_op]):
opt = tf.train.GradientDescentOptimizer(lr)
grads = opt.compute_gradients(total_loss)
# Apply gradients.
apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
# Add histograms for trainable variables.
for var in tf.trainable_variables():
tf.summary.histogram(var.op.name, var)
# Add histograms for gradients.
for grad, var in grads:
if grad is not None:
tf.summary.histogram(var.op.name + '/gradients', grad)
# Track the moving averages of all trainable variables.
variable_averages = tf.train.ExponentialMovingAverage(
MOVING_AVERAGE_DECAY, global_step)
variables_averages_op = variable_averages.apply(tf.trainable_variables())
with tf.control_dependencies([apply_gradient_op, variables_averages_op]):
train_op = tf.no_op(name='train')
return train_op
tf.control_dependencies()设计是用来控制计算流图的,给图中的某些计算指定顺序。tf.no_op()表示什么也不做。比如模型训练的时候要执行a,b操作,可使用以下代码:
with tf.control_dependencies([a, b]):
c= tf.no_op(name='train')#tf.no_op;什么也不做
sess.run(c)
评估
训练脚本会为所有学习变量计算其移动均值,评估脚本则直接将所有学习到的模型参数替换成对应的移动均值。这一替代方式可以在评估过程中提升模型的性能。
# Restore the moving average version of the learned variables for eval.
variable_averages = tf.train.ExponentialMovingAverage(
cifar10.MOVING_AVERAGE_DECAY)
variables_to_restore = variable_averages.variables_to_restore()
saver = tf.train.Saver(variables_to_restore)
ExponentialMovingAverage 对每一个(待更新训练学习的)变量(variable)都会维护一个影子变量(shadow variable)。影子变量的初始值就是这个变量的初始值:
shadow_variable=decay∗shadow_variable+(1−decay)∗variable
decay 控制着模型更新的速度,越大越趋于稳定。实际运用中,decay 一般会设置为十分接近 1 的常数(0.99或0.999)。为了使得模型在训练的初始阶段更新得更快,ExponentialMovingAverage 还提供了 num_updates 参数来动态设置 decay 的大小
decay=min{decay,1+num_updates10+num_updates}
就此,我们就完成了整个卷积神经网络在CIFAR数据集上的分类预测。