单个神经网络的问题
对于单神经元,想要解决MNIST问题,无论如何调节神经网络超参数,模型的准确率仅仅在91%左右。单个神经元的处理能力是有限的,所以尝试构建多层多神经元的网络,看能否提高网络的准确率。同时希望尝试对tensorboard做一些进阶,训练过程可视化有助于调参。
定义全连接层函数
由于构建多层网络,为了能够让组网更加清晰,定义一个多元线性回归的全连接层函数,该函数希望能够通用,全连接只前一层的所有节点都与下一层的每个节点相连。
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
import numpy as np
#读取mnist数据
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
#定义全连接层函数
def fcn_layer(inputs, #输入数据
input_dim, #输入神经元数量
output_dim, #输出神经元数量
activation=None #激活函数
):
W=tf.Variable(tf.truncated_normal([input_dim,output_dim], stddev = 0.1)) #以截断正太分布的随机数初始化W
b = tf.Variable(tf.zeros([output_dim])) #以0初始化b
XWb = tf.matmul(inputs,W) +b #建立表达式:input*W+b
if activation is None: #默认不使用激活函数
output = XWb
else:
output = activation(XWb)
return output
#将节点使用tensorboard展示出来
tf.reset_default_graph() #清空之前的计算图
使用全连接层函数定义隐藏层和输出层
有了全连接层函数,使用该函数来定义神经网络
#构建输入层,占位符x,y就是用来接收tensorflow图像
x = tf.placeholder(tf.float32, [None,784],name = "X")
y = tf.placeholder(tf.float32, [None,10], name = "Y")
#为了将图像能够在tensorboard中显示出来,就必须将这些数据加入到tensorboard的summary中去,summary提供一个image方法来显示它
#参数-1表示带入的数据总量不明
#参数28,28表明带入的数据是图像的长宽:28*28
#参数1表示带入图像的通道数为1,即单色的图像
im_shaped_input = tf.reshape(x,[-1,28,28,1])
#参数10表示一次显示10张图
tf.summary.image('input',im_shaped_input,10)
#使用全连接层函数来构建隐藏层,第一隐藏层256个单元,第二隐藏层64个节点
H1_NN = 256
H2_NN = 64
#隐藏层1
h1 = fcn_layer(inputs = x,
input_dim = 784,
output_dim = H1_NN,
activation =tf.nn.relu)
#隐藏层2
h2 = fcn_layer(inputs = h1,
input_dim = H1_NN,
output_dim = H2_NN,
activation = tf.nn.relu)
#使用全连接层函数构建输出层
forward = fcn_layer(inputs =h2,
input_dim = H2_NN,
output_dim = 10,
activation = None)
#前向输出值在以直方图显示
tf.summary.histogram("forward",forward)
#需要pred节点去计算准确率
pred = tf.nn.softmax(forward)
定义损失函数和超参数
#定义损失函数 交叉熵
loss_function = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=forward, labels =y))
#将loss值以标量的形式显示出来
tf.summary.scalar("loss",loss_function)
#设置训练参数
train_epochs =40 #训练轮数
batch_size =50 #单次训练批量大小
total_batch = int(mnist.train.num_examples/batch_size) #一轮训练有多少批次
display_step = 1 #显示粒度
learning_rate = 0.01 #学习率
#选择优化器,选用Adam优化器做尝试
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss_function)
#定义准确率
correct_predication = tf.equal(tf.argmax(pred,1),tf.argmax(y,1))
#准确率,将布尔值转化为浮点数,并计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_predication,tf.float32))
#将准确率以标量的形式显示出来
tf.summary.scalar("accuracy:",accuracy)
#记录训练模型时间
from time import time
startTime=time()
#tensorBoard合并所有summary
merged_summary_op = tf.summary.merge_all()
writer = tf.summary.FileWriter('log/',sess.graph)
定义保存模型
#保存模型的粒度
save_step = 5 #表示每5轮进行一次保存
#创建保存模型文件的目录
import os
ckpt_dir ="./ckpt_dir/"
if not os.path.exists(ckpt_dir):
os.makedirs(ckpt_dir)
#开始训练模型之前保存模型
saver = tf.train.Saver()
定义会话,开始训练
#初始化会话
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
#开始训练网络
for epoch in range(train_epochs):
for batch in range(total_batch):
xs,ys = mnist.train.next_batch(batch_size) #读取批次数据
sess.run(optimizer,feed_dict={x:xs,y:ys}) #执行批次训练
#生成summary
summary_str = sess.run(merged_summary_op,feed_dict={x:xs,y:ys})
#将summary写入文件
writer.add_summary(summary_str,epoch)
#total_batch个批次训练完成后,使用验证数据计算误差与准确率;验证集没有分批
loss, acc = sess.run([loss_function,accuracy],
feed_dict={x:mnist.validation.images,y:mnist.validation.labels})
#打印训练过程中的详细信息
if(epoch+1)%display_step == 0:
print("Train Epoch:","%02d"%(epoch+1),"Loss=","{:.9f}".format(loss),
"Accuracy=","{:.4f}".format(acc))
#训练过程中保存模型
if(epoch+1)% save_step == 0:
saver.save(sess, os.path.join(ckpt_dir,
'mnist_h256_h64_model_{:06d}.ckpt'.format(epoch+1)))
print('mnist_h256_h64_model_{:06d}.ckpt saved'.format(epoch+1))
saver.save(sess,os.path.join(ckpt_dir,'mnist_h256_h64_model.ckpt'))
print("Model saved!")
#显示运行总时间
duration = time()-startTime
print("Train Finished tasks:","{:.2f}".format(duration))
writer.close()
完成训练后可以看到:
1、网络的精度从91%提到高了97%左右,通过超参调节可以达到98%以上
2、网络生成的模型保存在对应目录下
3、网络的节点图
精度和损失的变化图
输入数据的可视化
网络节点图
前向计算直方图
本例在前一个单节点神经网络的前提下进行了下列优化
1、神经网络的结构从单隐藏层单节点变为双隐藏层,多节点神经网络
2、添加了模型保存功能
3、添加了tensorboard可视化的一些内容