在TensorFlow目录下新建文件,命名为LeNet-5.py,利用TensorFlow解决类似于LeNet-5在MNIST数据集上进行数字识别的问题,在PyCharm中编写以下代码。
-×- coding: utf-8 -×-
载入MINIST数据需要的库
from tensorflow.examples.tutorials.mnist import input_data
保存模型需要的库
from tensorflow.python.framework.graph_util import convert_variables_to_constants
from tensorflow.python.framework import graph_util
导入其他库
import tensorflow as tf
import time
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
获取MINIST数据
mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)
占位符
x是特征值,也就是像素
使用一个28×28=784列的数据来表示一个图像的构成
每一个点都是这个图像的一个特征
因为每一个点都会对图像的外观和表达的含义有影响,只是影响的大小不同而已
x = tf.placeholder("float", shape=[None, 784], name="Mul") # 输入28×28=784
y_是真实数据[0,0,0,0,1,0,0,0,0],为4
y = tf.placeholder("float", shape=[None, 10], name="y") # 输出
变量 784×10的矩阵
W表示每一个特征值(像素点)影响结果的权重
这个值很重要,因为深度学习的过程就是发现特征
经过一系列训练,得出每一个特征值对结果影响的权重
训练就是为了得到这个最佳权重值
W = tf.Variable(tf.zeros([784, 10]), name='x')
b = tf.Variable(tf.zeros([10]), 'y_')
权重
def weight_variable(shape):
# 生成的值服从具有指定平均值和标准偏差的正态分布
# 如果生成的值大于平均值的两个标准偏差的值,则丢弃重新选择
initial = tf.truncated_normal(shape, stddev=0.1) # 标准差为0.1
return tf.Variable(initial)
偏差
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
卷积
def conv2d(x, W):
# 参数x指需要做卷积的输入图像,要求它是一个Tensor
# 具有[batch, in_height, in_width, in_channels]这样的shape
# 具体含义是[训练时一个batch的图像数量, 图像高度, 图像宽度, 图像通道数]
# 注意这是一个4维的Tensor,batch和in_channels在卷积层中通常设为1
# 参数W相当于CNN中的卷积核,要求它是一个Tensor
# 具有[filter_height, filter_width, in_channels, out_channels]这样的shape
# 具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数]
# 注意,第三维in_channels就是参数x的第四维
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='VALID')
# 参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度为4
# 参数padding:string类型的量,只能是“VALID”,不补零
最大池化
def max_pool_2x2(x):
# x:input
# ksize:filter,滤波器大小为2×2
# strides:步长,2×2,表示filter窗口每次水平移动两格,每次垂直移动两格
# padding:填充方式,补零
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
第一层卷积
权重+偏置+激活+池化
patch为5×5;in_size为1,即图像的厚度,如果是彩色的,则为3;32个卷积核(滤波器)
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
对数据进行重新排列,形成图像
x_image = tf.reshape(x, [-1, 28, 28, 1])
print("x",x)
print("x_image",x_image)
ReLU操作,输出大小为28×28×32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
Pooling操作,输出大小为14×14×32
h_pool1 = max_pool_2x2(h_conv1)
第二层卷积
权重+偏置+激活+池化
patch为5×5;in_size为32,即图像的厚度;out_size是64,即输出的大小
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
ReLU操作,输出大小为14×14×64
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
Pooling操作,输出大小为7×7×64
h_pool2 = max_pool_2x2(h_conv2)
全连接一
W_fc1 = weight_variable([7 × 7 × 64, 1024])
b_fc1 = bias_variable([1024])
全连接二
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
输入数据变换
变换为m×n,列n为7×7×64
h_pool2_flat = tf.reshape(h_pool2, [-1, 7 × 7 × 64])
进行全连接操作
tf.nn.relu()函数可将大于0的数保持不变,将小于0的数置为0
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
Dropout可防止过拟合,它一般用在全连接层,训练用,测试不用
Dropout就是在不同的训练过程中随机扔掉一部分神经元
Dropout可以让某个神经元的激活值以一定的概率p停止工作
参数keep_prob:设置神经元被选中的概率,在初始化时keep_prob是一个占位符
TensorFlow在运行时设置keep_prob具体的值,如keep_prob: 0.5
keep_prob = tf.placeholder("float", name='rob')
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
用于训练的softmax()函数将所有数据归一化到0~1之间,大的数据特征更明显
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2, name='res')
训练完成后,进行测试用的softmax()函数
y_conv2 = tf.nn.softmax(tf.matmul(h_fc1, W_fc2) + b_fc2, name="final_result")
交叉熵的计算,返回包含了损失值/误差的Tensor
熵是衡量事物混乱程度的一个值
cross_entropy = -tf.reducesum(y × tf.log(y_conv))
优化器,负责最小化交叉熵
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
tf.argmax():取出该数组最大值的下角标
correct_prediction = tf.equal(tf.argmax(yconv, 1), tf.argmax(y, 1))
计算准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
创建会话
with tf.Session() as sess:
time_begin = time.time()
# 初始化所有变量
sess.run(tf.global_variables_initializer())
# print(sess.run(W_conv1))
# 保存输入/输出,可以在之后用
tf.add_to_collection('res', y_conv)
tf.add_to_collection('output', y_conv2)
tf.add_to_collection('x', x)
# 训练开始
for i in range(10000):
# 取出MNIST数据集中的50个数据
batch = mnist.train.next_batch(50)
# run()可以看作输入相关值到函数中的占位符,然后计算出结果
# 这里将batch[0]给x,将batch[1]给y_
# 执行训练过程并传入真实数据
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
if i % 100 == 0:
train_accuracy = accuracy.eval(feed_dict={x: batch[0],\
y_: batch[1],
keep_prob: 1.0})
print("step %d, training accuracy %g" % (i, train_accuracy))
time_elapsed = time.time() - time_begin
print("训练所用时间:%d秒" % time_elapsed)
# 用saver 保存模型
saver = tf.train.Saver()
saver.save(sess, "model_data/model")