LeNet
LeNet 早期用来识别手写体数字的图像的卷积神经网络
组成部分:
卷积层块
全连接层块


直接上代码--- 以下是LeNet 的代码
# -- encoding:utf-8 --
"""
Create on 19/5/25 10:06
"""
import os
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 定义外部传入的参数
tf.app.flags.DEFINE_bool(flag_name="is_train",
default_value=True,
docstring="给定是否是训练操作,True表示训练,False表示预测!!")
tf.app.flags.DEFINE_string(flag_name="checkpoint_dir",
default_value="./models_lenet",
docstring="给定模型存储的文件夹,默认为./models_lenet")
tf.app.flags.DEFINE_string(flag_name="logdir",
default_value="./graph_lenet",
docstring="给定模型日志存储的路径,默认为./graph_lenet")
tf.app.flags.DEFINE_integer(flag_name="batch_size",
default_value=8,
docstring="给定训练的时候每个批次的样本数目,默认为16.")
tf.app.flags.DEFINE_integer(flag_name="store_per_batch",
default_value=100,
docstring="给定每隔多少个批次进行一次模型持久化的操作,默认为100")
tf.app.flags.DEFINE_integer(flag_name="validation_per_batch",
default_value=100,
docstring="给定每隔多少个批次进行一次模型的验证操作,默认为100")
tf.app.flags.DEFINE_float(flag_name="learning_rate",
default_value=0.001,
docstring="给定模型的学习率,默认0.01")
FLAGS = tf.app.flags.FLAGS
def create_dir_with_not_exits(dir_path):
"""
如果文件的文件夹路径不存在,直接创建
:param dir_path:
:return:
"""
if not os.path.exists(dir_path):
os.makedirs(dir_path)
def create_model(input_x):
"""
构建模型
:param input_x: 占位符,格式为[None, 784]
:return:
"""
# 定义一个网络结构: input -> conv -> sigmoid -> pooling -> conv -> sigmoid -> pooling -> FC -> sigmoid -> FC
with tf.variable_scope("net",
initializer=tf.random_normal_initializer(0.0, 0.0001)):
with tf.variable_scope("Input"):
# 这里定义一些图像的处理方式,包括:格式转换、基础处理(大小、剪切...)
net = tf.reshape(input_x, shape=[-1, 28, 28, 1])
print(net.get_shape())
# 可视化图像
tf.summary.image(name='image', tensor=net, max_outputs=5)
with tf.variable_scope("Conv1"):
filter = tf.get_variable(name='w', shape=[5, 5, 1, 20])
bias = tf.get_variable(name='b', shape=[20])
net = tf.nn.conv2d(input=net, filter=filter, strides=[1, 1, 1, 1], padding='VALID')
net = tf.nn.bias_add(net, bias)
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Sigmoid1"):
net = tf.nn.sigmoid(net)
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Pooling1"):
# ksize:池化的窗口形状;strides:窗口的滑动大小。
net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Conv2"):
filter = tf.get_variable(name='w', shape=[5, 5, 20, 50])
bias = tf.get_variable(name='b', shape=[50])
net = tf.nn.conv2d(input=net, filter=filter, strides=[1, 1, 1, 1], padding='VALID')
net = tf.nn.bias_add(net, bias)
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Sigmoid2"):
net = tf.nn.sigmoid(net)
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Pooling2"):
net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
print(net.get_shape())
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("FC1"):
shape = net.get_shape()
dim_size = shape[1] * shape[2] * shape[3]
net = tf.reshape(net, shape=[-1, dim_size])
w = tf.get_variable(name='w', shape=[dim_size, 500])
b = tf.get_variable(name='b', shape=[500])
net = tf.matmul(net, w) + b
net = tf.nn.relu(net)
with tf.variable_scope("FC2"):
w = tf.get_variable(name='w', shape=[500, 10])
b = tf.get_variable(name='b', shape=[10])
logits = tf.matmul(net, w) + b
with tf.variable_scope("Prediction"):
# 每行的最大值对应的下标就是当前样本的预测值
predictions = tf.argmax(logits, axis=1)
return logits, predictions
def create_loss(labels, logits):
"""
基于给定的实际值labels和预测值logits进行一个交叉熵损失函数的构建
:param labels: 是经过哑编码之后的Tensor对象,形状为[n_samples, n_class]
:param logits: 是神经网络的最原始的输出,形状为[n_samples, n_class], 每一行最大值那个位置对应的就是预测类别,没有经过softmax函数转换。
:return:
"""
with tf.name_scope("loss"):
# loss = tf.reduce_mean(-tf.log(tf.reduce_sum(labels * tf.nn.softmax(logits))))
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
tf.summary.scalar('loss', loss)
return loss
def create_train_op(loss, learning_rate=0.01, global_step=None):
"""
基于给定的损失函数构建一个优化器,优化器的目的就是让这个损失函数最小化
:param loss:
:param learning_rate:
:param global_step:
:return:
"""
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss, global_step=global_step)
return train_op
def create_accuracy(labels, predictions):
"""
基于给定的实际值和预测值,计算准确率
:param labels: 是经过哑编码之后的Tensor对象,形状为[n_samples, n_class]
:param predictions: 实际的预测类别下标,形状为[n_samples,]
:return:
"""
with tf.name_scope("accuracy"):
# 获取实际的类别下标,形状为[n_samples,]
y_labels = tf.argmax(labels, 1)
# 计算准确率
accuracy = tf.reduce_mean(tf.cast(tf.equal(y_labels, predictions), tf.float32))
tf.summary.scalar('accuracy', accuracy)
return accuracy
def train():
# 对于文件是否存在做一个检测
create_dir_with_not_exits(FLAGS.checkpoint_dir)
create_dir_with_not_exits(FLAGS.logdir)
with tf.Graph().as_default():
# 一、执行图的构建
# 0. 相关输入Tensor对象的构建
input_x = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='input_x')
input_y = tf.placeholder(dtype=tf.float32, shape=[None, 10], name='input_y')
global_step = tf.train.get_or_create_global_step()
# 1. 网络结构的构建
logits, predictions = create_model(input_x)
# 2. 构建损失函数
loss = create_loss(input_y, logits)
# 3. 构建优化器
train_op = create_train_op(loss,
learning_rate=FLAGS.learning_rate,
global_step=global_step)
# 4. 构建评估指标
accuracy = create_accuracy(input_y, predictions)
# 二、执行图的运行/训练(数据加载、训练、持久化、可视化、模型的恢复....)
with tf.Session() as sess:
# a. 创建一个持久化对象(默认会将所有的模型参数全部持久化,因为不是所有的都需要的,最好仅仅持久化的训练的模型参数)
var_list = tf.trainable_variables()
# 是因为global_step这个变量是不参与模型训练的,所以模型不会持久化,这里加入之后,可以明确也持久化这个变量。
var_list.append(global_step)
saver = tf.train.Saver(var_list=var_list)
# a. 变量的初始化操作(所有的非训练变量的初始化 + 持久化的变量恢复)
# 所有变量初始化(如果有持久化的,后面做了持久化后,会覆盖的)
sess.run(tf.global_variables_initializer())
# 做模型的恢复操作
ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
if ckpt and ckpt.model_checkpoint_path:
print("进行模型恢复操作...")
# 恢复模型
saver.restore(sess, ckpt.model_checkpoint_path)
# 恢复checkpoint的管理信息
saver.recover_last_checkpoints(ckpt.all_model_checkpoint_paths)
# 获取一个日志输出对象
train_logdir = os.path.join(FLAGS.logdir, 'train')
validation_logdir = os.path.join(FLAGS.logdir, 'validation')
train_writer = tf.summary.FileWriter(logdir=train_logdir, graph=sess.graph)
validation_writer = tf.summary.FileWriter(logdir=validation_logdir, graph=sess.graph)
# 获取所有的summary输出操作
summary = tf.summary.merge_all()
# b. 训练数据的产生/获取(基于numpy随机产生<可以先考虑一个固定的数据集>)
mnist = input_data.read_data_sets(
train_dir='../datas/mnist', # 给定本地磁盘的数据存储路径
one_hot=True, # 给定返回的数据中是否对Y做哑编码
validation_size=5000 # 给定验证数据集的大小
)
# c. 模型训练
batch_size = FLAGS.batch_size
step = sess.run(global_step)
vn_accuracy_ = 0
while True:
# 开始模型训练
x_train, y_train = mnist.train.next_batch(batch_size=batch_size)
_, loss_, accuracy_, summary_ = sess.run([train_op, loss, accuracy, summary], feed_dict={
input_x: x_train,
input_y: y_train
})
print("第{}次训练后模型的损失函数为:{}, 准确率:{}".format(step, loss_, accuracy_))
train_writer.add_summary(summary_, global_step=step)
# 持久化
if step % FLAGS.store_per_batch == 0:
file_name = 'model_%.3f_%.3f_.ckpt' % (loss_, accuracy_)
save_path = os.path.join(FLAGS.checkpoint_dir, file_name)
saver.save(sess, save_path=save_path, global_step=step)
if step % FLAGS.validation_per_batch == 0:
vn_loss_, vn_accuracy_, vn_summary_ = sess.run([loss, accuracy, summary],
feed_dict={
input_x: mnist.validation.images,
input_y: mnist.validation.labels
})
print("第{}次训练后模型在验证数据上的损失函数为:{}, 准确率:{}".format(step,
vn_loss_,
vn_accuracy_))
validation_writer.add_summary(vn_summary_, global_step=step)
# 退出训练(要求当前的训练数据集上的准确率至少为0.8,然后最近一次验证数据上的准确率为0.8)
if accuracy_ > 0.99 and vn_accuracy_ > 0.99:
# 退出之前再做一次持久化操作
file_name = 'model_%.3f_%.3f_.ckpt' % (loss_, accuracy_)
save_path = os.path.join(FLAGS.checkpoint_dir, file_name)
saver.save(sess, save_path=save_path, global_step=step)
break
step += 1
# 关闭输出流
train_writer.close()
validation_writer.close()
def prediction():
# TODO: 参考以前的代码自己把这个区域的内容填充一下。我下周晚上讲。
# 做一个预测(预测的评估,对mnist.test这个里面的数据进行评估效果的查看)
with tf.Graph().as_default():
pass
def main(_):
if FLAGS.is_train:
# 进入训练的代码执行中
print("开始进行模型训练运行.....")
train()
else:
# 进入测试、预测的代码执行中
print("开始进行模型验证、测试代码运行.....")
prediction()
print("Done!!!!")
if __name__ == '__main__':
# 默认情况下,直接调用当前py文件中的main函数
tf.app.run()
LeNet 5 (手写字母)

input 32x32 --conv --- maxpool----conv(和我们普通的卷积不同)----fullconnection 全连接----- RBF的思想(计算中心点的核函数的距离,距离越近的就是预测的类别)
C1层是一个卷积层
• 6个特征图,每个特征图中的每个神经元与输入中55的邻域相连,特征
图大小为2828
• 每个卷积神经元的参数数目:55=25个weight参数和一个bias参数 • 链接数目:(55+1)6(2828)=122304个链接
• 参数共享:每个特征图内共享参数,因此参数总数:共(55+1) *6=156个参数
S2层是一个下采样层
• 6个1414的特征图,每个图中的每个单元与C1特征图中的一个22邻域
相连接,不重叠。
• 和max pooling和average pooling不一样,在S2层中每个单元的4个 输入相加,乘以一个可训练参数w,再加上一个可训练偏置b,结果通过 sigmoid函数计算得到最终池化之后的值。
• 连接数:(22+1)14146=5880个。
• 参数共享:每个特征图内共享参数,因此有26=12个可训练参数。
C3层是一个卷积层
• 输入的feature map数量为6个,每个大小为1414;16个卷积核,得
到16张特征图,特征图大小为1010。
• 每个特征图中的每个神经元与S2中某几层的多个55的邻域相连;
• 例如:对于C3层第0张特征图,其每一个节点与S2层的第0~2张特征图, 总共3个5*5个节点相连接。
不是所有的futuremap 进行卷积,而是分开进行卷积,因为当时机器的性能不够,想方设法的提取更多的特征

S4层是一个下采样层(和S2一样)
• 由16个55大小的特征图构成,特征图中的每个单元与C3中相应特征图
的22邻域相连接。
• 连接数:(22+1)5516=2000个。
• 参数共享:特征图内共享参数,每个特征图中的每个神经元需要1个因 子和一个偏置,因此有2*16个可训练参数
• C5层是一个卷积层
• 120个神经元,可以看作120个特征图,每张特征图的大小为11
• 每个单元与S4层的全部16个单元的55邻域相连(S4和C5之间的全连接) • 连接数=可训练参数:(5516+1)120=48120个
F6层是一个全连接层
• 有84个单元,与C5层全连接。
• F6层计算输入向量和权重向量之间的点积,再加上一个偏置(wx+b), 最后将加权值做一个sigmoid转换。
• 连接数=可训练参数:(120+1)84=10164。
• 这里选择84作为神经元的数目从论文中可以认为是:ASCII字符标准的 打印字符,是用712大小的位图,这里希望每一维特征分别体现标准 712大小位图上每一个像素点的特性。
F7层是一个输出层
• 输出层是由欧式径向基函数(RBF)组成。每一个输出对应一个RBF函 数,每一个RBF函数都有84维的输入向量,RBF的函数公式如下。每一 个RBF函数都会有一个输出,最后输出层会输出一个10维的向量。


上代码
# -- encoding:utf-8 --
"""
Create on 19/5/25 10:06
"""
import os
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 定义外部传入的参数
tf.app.flags.DEFINE_bool(flag_name="is_train",
default_value=True,
docstring="给定是否是训练操作,True表示训练,False表示预测!!")
tf.app.flags.DEFINE_string(flag_name="checkpoint_dir",
default_value="./mnist/models/models_lenet5",
docstring="给定模型存储的文件夹,默认为./mnist/models/models_lenet5")
tf.app.flags.DEFINE_string(flag_name="logdir",
default_value="./mnist/graph/graph_lenet5",
docstring="给定模型日志存储的路径,默认为./mnist/graph/graph_lenet5")
tf.app.flags.DEFINE_integer(flag_name="batch_size",
default_value=16,
docstring="给定训练的时候每个批次的样本数目,默认为16.")
tf.app.flags.DEFINE_integer(flag_name="store_per_batch",
default_value=100,
docstring="给定每隔多少个批次进行一次模型持久化的操作,默认为100")
tf.app.flags.DEFINE_integer(flag_name="validation_per_batch",
default_value=100,
docstring="给定每隔多少个批次进行一次模型的验证操作,默认为100")
tf.app.flags.DEFINE_float(flag_name="learning_rate",
default_value=0.01,
docstring="给定模型的学习率,默认0.01")
FLAGS = tf.app.flags.FLAGS
def create_dir_with_not_exits(dir_path):
"""
如果文件的文件夹路径不存在,直接创建
:param dir_path:
:return:
"""
if not os.path.exists(dir_path):
os.makedirs(dir_path)
def create_model(input_x, show_image=False):
"""
构建模型
:param input_x: 占位符,格式为[None, 784]
:return:
"""
# 定义一个网络结构: input -> conv -> relu -> pooling -> conv -> relu -> pooling -> FC -> relu -> FC
with tf.variable_scope("net"):
with tf.variable_scope("Input"):
# 这里定义一些图像的处理方式,包括:格式转换、基础处理(大小、剪切...)
net = tf.reshape(input_x, shape=[-1, 28, 28, 1])
print(net.get_shape())
if show_image:
# 可视化图像
tf.summary.image(name='image', tensor=net, max_outputs=5)
with tf.variable_scope("Conv1"):
filter = tf.get_variable(name='w', shape=[5, 5, 1, 6])
bias = tf.get_variable(name='b', shape=[6])
net = tf.nn.conv2d(input=net, filter=filter, strides=[1, 1, 1, 1], padding='VALID')
net = tf.nn.bias_add(net, bias)
shape = net.get_shape()
print(shape)
if show_image:
# 对于卷积之后的值做一个可视化操作
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Relu1"):
net = tf.nn.relu(net)
print(net.get_shape())
if show_image:
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Pooling1"):
# ksize:池化的窗口形状;strides:窗口的滑动大小。
net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
print(net.get_shape())
if show_image:
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Conv2"):
# input_net形状为:[batch_size,14,14,6]
input_net = net
filter_in_channels = [
[0, 1, 2],
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 0],
[5, 0, 1],
[0, 1, 2, 3],
[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 0],
[4, 5, 0, 1],
[5, 0, 1, 2],
[0, 1, 3, 4],
[1, 2, 4, 5],
[2, 3, 5, 0],
[0, 1, 2, 3, 4, 5]
]
output_net = []
for idx, filter_in_channel in enumerate(filter_in_channels):
with tf.variable_scope("Conv2_{}".format(idx)):
tmp_channels = []
for channel in filter_in_channel:
# 获取对应channel的数据
print(channel,'=='*20)
tmp_net = input_net[:, :, :, channel]
# 合并数据
tmp_channels.append(tf.expand_dims(tmp_net, -1))
# 合并成一个输入操作
tmp_input_net = tf.concat(tmp_channels, axis=-1)
# 做卷积操作
filter = tf.get_variable(name='w', shape=[5, 5, len(tmp_channels), 1])
bias = tf.get_variable(name='b', shape=[1])
tmp_output_net = tf.nn.conv2d(input=tmp_input_net,
filter=filter,
strides=[1, 1, 1, 1], padding='VALID')
tmp_output_net = tf.nn.bias_add(tmp_output_net, bias)
output_net.append(tmp_output_net)
# 合并所有的输出通道
net = tf.concat(output_net, axis=-1)
print(net.get_shape())
with tf.variable_scope("Relu2"):
net = tf.nn.relu(net)
print(net.get_shape())
if show_image:
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("Pooling2"):
net = tf.nn.max_pool(value=net, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
print(net.get_shape())
if show_image:
# 对于卷积之后的值做一个可视化操作
shape = net.get_shape()
for k in range(shape[-1]):
image_tensor = tf.reshape(net[:, :, :, k], shape=[-1, shape[1], shape[2], 1])
tf.summary.image(name='image', tensor=image_tensor, max_outputs=5)
with tf.variable_scope("FC1"):
shape = net.get_shape()
dim_size = shape[1] * shape[2] * shape[3]
net = tf.reshape(net, shape=[-1, dim_size])
w = tf.get_variable(name='w', shape=[dim_size, 120])
b = tf.get_variable(name='b', shape=[120])
net = tf.matmul(net, w) + b
net = tf.nn.relu(net)
with tf.variable_scope("FC2"):
w = tf.get_variable(name='w', shape=[120, 84])
b = tf.get_variable(name='b', shape=[84])
net = tf.matmul(net, w) + b
net = tf.nn.relu(net)
with tf.variable_scope("FC3"):
w = tf.get_variable(name='w', shape=[84, 10])
b = tf.get_variable(name='b', shape=[10])
logits = tf.matmul(net, w) + b
with tf.variable_scope("Prediction"):
# 每行的最大值对应的下标就是当前样本的预测值
predictions = tf.argmax(logits, axis=1)
return logits, predictions
def create_loss(labels, logits):
"""
基于给定的实际值labels和预测值logits进行一个交叉熵损失函数的构建
:param labels: 是经过哑编码之后的Tensor对象,形状为[n_samples, n_class]
:param logits: 是神经网络的最原始的输出,形状为[n_samples, n_class], 每一行最大值那个位置对应的就是预测类别,没有经过softmax函数转换。
:return:
"""
with tf.name_scope("loss"):
# loss = tf.reduce_mean(-tf.log(tf.reduce_sum(labels * tf.nn.softmax(logits))))
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
tf.summary.scalar('loss', loss)
return loss
def create_train_op(loss, learning_rate=0.01, global_step=None):
"""
基于给定的损失函数构建一个优化器,优化器的目的就是让这个损失函数最小化
:param loss:
:param learning_rate:
:param global_step:
:return:
"""
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss, global_step=global_step)
return train_op
def create_accuracy(labels, predictions):
"""
基于给定的实际值和预测值,计算准确率
:param labels: 是经过哑编码之后的Tensor对象,形状为[n_samples, n_class]
:param predictions: 实际的预测类别下标,形状为[n_samples,]
:return:
"""
with tf.name_scope("accuracy"):
# 获取实际的类别下标,形状为[n_samples,]
y_labels = tf.argmax(labels, 1)
# 计算准确率
accuracy = tf.reduce_mean(tf.cast(tf.equal(y_labels, predictions), tf.float32))
tf.summary.scalar('accuracy', accuracy)
return accuracy
def train():
# 对于文件是否存在做一个检测
create_dir_with_not_exits(FLAGS.checkpoint_dir)
create_dir_with_not_exits(FLAGS.logdir)
with tf.Graph().as_default():
# 一、执行图的构建
# 0. 相关输入Tensor对象的构建
input_x = tf.placeholder(dtype=tf.float32, shape=[None, 784], name='input_x')
input_y = tf.placeholder(dtype=tf.float32, shape=[None, 10], name='input_y')
global_step = tf.train.get_or_create_global_step()
# 1. 网络结构的构建
logits, predictions = create_model(input_x)
# 2. 构建损失函数
loss = create_loss(input_y, logits)
# 3. 构建优化器
train_op = create_train_op(loss,
learning_rate=FLAGS.learning_rate,
global_step=global_step)
# 4. 构建评估指标
accuracy = create_accuracy(input_y, predictions)
# 二、执行图的运行/训练(数据加载、训练、持久化、可视化、模型的恢复....)
with tf.Session() as sess:
# a. 创建一个持久化对象(默认会将所有的模型参数全部持久化,因为不是所有的都需要的,最好仅仅持久化的训练的模型参数)
var_list = tf.trainable_variables()
# 是因为global_step这个变量是不参与模型训练的,所以模型不会持久化,这里加入之后,可以明确也持久化这个变量。
var_list.append(global_step)
saver = tf.train.Saver(var_list=var_list)
# a. 变量的初始化操作(所有的非训练变量的初始化 + 持久化的变量恢复)
# 所有变量初始化(如果有持久化的,后面做了持久化后,会覆盖的)
sess.run(tf.global_variables_initializer())
# 做模型的恢复操作
ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
if ckpt and ckpt.model_checkpoint_path:
print("进行模型恢复操作...")
# 恢复模型
saver.restore(sess, ckpt.model_checkpoint_path)
# 恢复checkpoint的管理信息
saver.recover_last_checkpoints(ckpt.all_model_checkpoint_paths)
# 获取一个日志输出对象
train_logdir = os.path.join(FLAGS.logdir, 'train')
validation_logdir = os.path.join(FLAGS.logdir, 'validation')
train_writer = tf.summary.FileWriter(logdir=train_logdir, graph=sess.graph)
validation_writer = tf.summary.FileWriter(logdir=validation_logdir, graph=sess.graph)
# 获取所有的summary输出操作
summary = tf.summary.merge_all()
# b. 训练数据的产生/获取(基于numpy随机产生<可以先考虑一个固定的数据集>)
mnist = input_data.read_data_sets(
train_dir='../datas/mnist', # 给定本地磁盘的数据存储路径
one_hot=True, # 给定返回的数据中是否对Y做哑编码
validation_size=5000 # 给定验证数据集的大小
)
# c. 模型训练
batch_size = FLAGS.batch_size
step = sess.run(global_step)
vn_accuracy_ = 0
while True:
# 开始模型训练
x_train, y_train = mnist.train.next_batch(batch_size=batch_size)
_, loss_, accuracy_, summary_ = sess.run([train_op, loss, accuracy, summary], feed_dict={
input_x: x_train,
input_y: y_train
})
print("第{}次训练后模型的损失函数为:{}, 准确率:{}".format(step, loss_, accuracy_))
train_writer.add_summary(summary_, global_step=step)
# 持久化
if step % FLAGS.store_per_batch == 0:
file_name = 'model_%.3f_%.3f_.ckpt' % (loss_, accuracy_)
save_path = os.path.join(FLAGS.checkpoint_dir, file_name)
saver.save(sess, save_path=save_path, global_step=step)
if step % FLAGS.validation_per_batch == 0:
vn_loss_, vn_accuracy_, vn_summary_ = sess.run([loss, accuracy, summary],
feed_dict={
input_x: mnist.validation.images,
input_y: mnist.validation.labels
})
print("第{}次训练后模型在验证数据上的损失函数为:{}, 准确率:{}".format(step,
vn_loss_,
vn_accuracy_))
validation_writer.add_summary(vn_summary_, global_step=step)
# 退出训练(要求当前的训练数据集上的准确率至少为0.8,然后最近一次验证数据上的准确率为0.8)
if accuracy_ > 0.99 and vn_accuracy_ > 0.99:
# 退出之前再做一次持久化操作
file_name = 'model_%.3f_%.3f_.ckpt' % (loss_, accuracy_)
save_path = os.path.join(FLAGS.checkpoint_dir, file_name)
saver.save(sess, save_path=save_path, global_step=step)
break
step += 1
# 关闭输出流
train_writer.close()
validation_writer.close()
def prediction():
# TODO: 参考以前的代码自己把这个区域的内容填充一下。我下周晚上讲。
# 做一个预测(预测的评估,对mnist.test这个里面的数据进行评估效果的查看)
with tf.Graph().as_default():
pass
def main(_):
if FLAGS.is_train:
# 进入训练的代码执行中
print("开始进行模型训练运行.....")
train()
else:
# 进入测试、预测的代码执行中
print("开始进行模型验证、测试代码运行.....")
prediction()
print("Done!!!!")
if __name__ == '__main__':
# 默认情况下,直接调用当前py文件中的main函数
tf.app.run()
网友评论