6.2. 模型接口建立
我们将模型接口都放在cifar_omdel.py文件当中,设计了四个函数,input()作为从cifar_data文件中数据的获取,inference()作为神经网络模型的建立,total_loss()计算模型的损失,train()来通过梯度下降训练减少损失
input代码
def input():
""" 获取输入数据 :return: image,label """
# 实例化
cfr = cifar_data.CifarRead()
# 生成张量
image_batch, lab_batch = cfr.read_tfrecords()
# 将目标值转换为one-hot编码格式
label = tf.one_hot(label_batch, depth=10, on_value=1.0)
return image_batch, label, label_batch
inference代码
在这里使用的卷积神经网络模型与前面一致,需要修改图像的通道数以及经过两次卷积池化变换后的图像大小。
def inference(image_batch):
""" 得到模型的输出 :return: 预测概率输出以及占位符 """
# 1、数据占位符建立
with tf.variable_scope("data"):
# 样本标签值
# y_label = tf.placeholder(tf.float32, [None, 10])
# 样本特征值
# x = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH * IMAGE_DEPTH])
# 改变形状,以提供给卷积层使用
x_image = tf.reshape(image_batch, [-1, 32, 32, 3])
# 2、卷积池化第一层
with tf.variable_scope("conv1"):
# 构建权重, 5*5, 3个输入通道,32个输出通道
w_conv1 = weight_variable([5, 5, 3, 32])
# 构建偏置, 个数位输出通道数
b_conv1 = bias_variable([32])
# 进行卷积,激活,指定滑动窗口,填充类型
y_relu1 = tf.nn.relu(tf.nn.conv2d(x_image, w_conv1, strides=[1, 1, 1, 1], padding="SAME") + b_conv1)
y_conv1 = tf.nn.max_pool(y_relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 3、卷积池化第二层
with tf.variable_scope("conv_pool2"):
# 构建权重, 5*5, 一个输入通道,32个输出通道
w_conv2 = weight_variable([5, 5, 32, 64])
# 构建偏置, 个数位输出通道数
b_conv2 = bias_variable([64])
# 进行卷积,激活,指定滑动窗口,填充类型
y_relu2 = tf.nn.relu(tf.nn.conv2d(y_conv1, w_conv2, strides=[1, 1, 1, 1], padding="SAME") + b_conv2)
y_conv2 = tf.nn.max_pool(y_relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 4、全连接第一层
with tf.variable_scope("FC1"):
# 构建权重,[7*7*64, 1024],根据前面的卷积池化后一步步计算的大小变换是32->16->8
w_fc1 = weight_variable([8 * 8 * 64, 1024])
# 构建偏置,个数位第一次全连接层输出个数
b_fc1 = bias_variable([1024])
y_reshape = tf.reshape(y_conv2, [-1, 8 * 8 * 64])
# 全连接结果激活
y_fc1 = tf.nn.relu(tf.matmul(y_reshape, w_fc1) + b_fc1)
# 5、全连接第二层
with tf.variable_scope("FC2"):
# droupout层
droup = tf.nn.dropout(y_fc1, 1.0)
# 构建权重,[1024, 10]
w_fc2 = weight_variable([1024, 10])
# 构建偏置 [10]
b_fc2 = bias_variable([10])
# 最后的全连接层
y_logit = tf.matmul(droup, w_fc2) + b_fc2
return y_logit
total_loss代码
def total_loss(y_label, y_logit):
""" 计算训练损失 :param y_label: 目标值 :param y_logit: 计算值 :return: 损失 """
with tf.variable_scope("loss"):
# softmax回归,以及计算交叉损失熵
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_label, logits=y_logit)
# 计算损失平均值
loss = tf.reduce_mean(cross_entropy)
return loss
train代码
def train(loss, y_label, y_logit, global_step):
""" 训练数据得出准确率 :param loss: 损失大小 :return: """
with tf.variable_scope("train"):
# 让学习率根据步伐,自动变换学习率,指定了每10步衰减基数为0.99,0.001为初始的学习率
lr = tf.train.exponential_decay(0.001,
global_step,
10,
0.99,
staircase=True)
# 优化器
train_op = tf.train.GradientDescentOptimizer(lr).minimize(loss, global_step=global_step)
# 计算准确率
equal_list = tf.equal(tf.argmax(y_logit, 1), tf.argmax(y_label, 1))
accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))
return train_op, accuracy
完整代码
import tensorflow as tf
import os
import cifar_data
#
#
from tensorflow.examples.tutorials.mnist import input_data
IMAGE_HEIGHT = 32
IMAGE_WIDTH = 32
IMAGE_DEPTH = 3
# 按照指定形状构建权重变量
def weight_variable(shape):
init = tf.truncated_normal(shape=shape, mean=0.0, stddev=1.0, dtype=tf.float32)
weight = tf.Variable(init)
return weight
# 按照制定形状构建偏置变量
def bias_variable(shape):
bias = tf.constant([1.0], shape=shape)
return tf.Variable(bias)
def inference(image_batch):
""" 得到模型的输出 :return: 预测概率输出以及占位符 """
# 1、数据占位符建立
with tf.variable_scope("data"):
# 样本标签值
# y_label = tf.placeholder(tf.float32, [None, 10])
# 样本特征值
# x = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH * IMAGE_DEPTH])
# 改变形状,以提供给卷积层使用
x_image = tf.reshape(image_batch, [-1, 32, 32, 3])
# 2、卷积池化第一层
with tf.variable_scope("conv1"):
# 构建权重, 5*5, 3个输入通道,32个输出通道
w_conv1 = weight_variable([5, 5, 3, 32])
# 构建偏置, 个数位输出通道数
b_conv1 = bias_variable([32])
# 进行卷积,激活,指定滑动窗口,填充类型
y_relu1 = tf.nn.relu(tf.nn.conv2d(x_image, w_conv1, strides=[1, 1, 1, 1], padding="SAME") + b_conv1)
y_conv1 = tf.nn.max_pool(y_relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 3、卷积池化第二层
with tf.variable_scope("conv_pool2"):
# 构建权重, 5*5, 一个输入通道,32个输出通道
w_conv2 = weight_variable([5, 5, 32, 64])
# 构建偏置, 个数位输出通道数
b_conv2 = bias_variable([64])
# 进行卷积,激活,指定滑动窗口,填充类型
y_relu2 = tf.nn.relu(tf.nn.conv2d(y_conv1, w_conv2, strides=[1, 1, 1, 1], padding="SAME") + b_conv2)
y_conv2 = tf.nn.max_pool(y_relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 4、全连接第一层
with tf.variable_scope("FC1"):
# 构建权重,[7*7*64, 1024],根据前面的卷积池化后一步步计算的大小变换是32->16->8
w_fc1 = weight_variable([8 * 8 * 64, 1024])
# 构建偏置,个数位第一次全连接层输出个数
b_fc1 = bias_variable([1024])
y_reshape = tf.reshape(y_conv2, [-1, 8 * 8 * 64])
# 全连接结果激活
y_fc1 = tf.nn.relu(tf.matmul(y_reshape, w_fc1) + b_fc1)
# 5、全连接第二层
with tf.variable_scope("FC2"):
# droupout层
droup = tf.nn.dropout(y_fc1, 1.0)
# 构建权重,[1024, 10]
w_fc2 = weight_variable([1024, 10])
# 构建偏置 [10]
b_fc2 = bias_variable([10])
# 最后的全连接层
y_logit = tf.matmul(droup, w_fc2) + b_fc2
return y_logit
def total_loss(y_label, y_logit):
""" 计算训练损失 :param y_label: 目标值 :param y_logit: 计算值 :return: 损失 """
with tf.variable_scope("loss"):
# 将y_label转换为one-hot编码形式
# y_onehot = tf.one_hot(y_label, depth=10, on_value=1.0)
# softmax回归,以及计算交叉损失熵
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_label, logits=y_logit)
# 计算损失平均值
loss = tf.reduce_mean(cross_entropy)
return loss
def train(loss, y_label, y_logit, global_step):
""" 训练数据得出准确率 :param loss: 损失大小 :return: """
with tf.variable_scope("train"):
# 让学习率根据步伐,自动变换学习率,指定了每10步衰减基数为0.99,0.001为初始的学习率
lr = tf.train.exponential_decay(0.001,
global_step,
10,
0.99,
staircase=True)
# 优化器
train_op = tf.train.GradientDescentOptimizer(lr).minimize(loss, global_step=global_step)
# 计算准确率
equal_list = tf.equal(tf.argmax(y_logit, 1), tf.argmax(y_label, 1))
accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))
return train_op, accuracy
def input():
""" 获取输入数据 :return: image,label """
# 实例化
cfr = cifar_data.CifarRead()
# 生成张量
image_batch, lab_batch = cfr.read_tfrecords()
# 将目标值转换为one-hot编码格式
label = tf.one_hot(label_batch, depth=10, on_value=1.0)
return image_batch, label, label_batch
6.3. 训练以及高级会话函数
主训练逻辑
我们将在cifar_train.py文件实现主要训练逻辑。在这里我们将使用一个新的会话函数,叫tf.train.MonitoredTrainingSession
优点: 1、它自动的建立events文件、checkpoint文件,以记录重要的信息。 2、可以定义钩子函数,可以自定义每批次的训练信息,训练的限制等等
注意:在这个里面我们需要添加一个全局步数,这个步数是每批次训练的时候进行+1计数,内部使用。
代码如下:
import tensorflow as tf
import cifar_model
import time
from datetime import datetime
def train():
# 在图中进行训练
with tf.Graph().as_default():
# 定义全局步数,必须得使用这个,否则会出现StopCounterHook错误
global_step = tf.contrib.framework.get_or_create_global_step()
# 获取数据
image, label, label_1 = cifar_model.input()
# 通过模型进行类别预测
y_logit = cifar_model.inference(image)
# 计算损失
loss = cifar_model.total_loss(label, y_logit)
# 进行优化器减少损失
train_op, accuracy = cifar_model.train(loss, label, y_logit, global_step)
# 通过钩子定义模型输出
class _LoggerHook(tf.train.SessionRunHook):
"""Logs loss and runtime."""
def begin(self):
self._step = -1
self._start_time = time.time()
def before_run(self, run_context):
self._step += 1
return tf.train.SessionRunArgs(loss, float(accuracy.eval())) # Asks for loss value.
def after_run(self, run_context, run_values):
if self._step % 10 == 0:
current_time = time.time()
duration = current_time - self._start_time
self._start_time = current_time
loss_value = run_values.results
examples_per_sec = 10 * 10 / duration
sec_per_batch = float(duration / 10)
format_str = ('%s: step %d, loss = %.2f (%.1f examples/sec; %.3f '
'sec/batch)')
print(format_str % (datetime.now(), self._step, loss_value,
examples_per_sec, sec_per_batch))
with tf.train.MonitoredTrainingSession(
checkpoint_dir="./cifartrain/train",
hooks=[tf.train.StopAtStepHook(last_step=500),# 定义执行的训练轮数也就是max_step,超过了就会报错
tf.train.NanTensorHook(loss),
_LoggerHook()],
config=tf.ConfigProto(
log_device_placement=False)) as mon_sess:
while not mon_sess.should_stop():
mon_sess.run(train_op)
def main(argv):
train()
if __name__ == "__main__":
tf.app.run()