TensorFlow实战之CNN

CNN 原理

Tensorflow实现CNN

LeNet-5模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import tensorflow as tf
INPUT_NODE=784#输入层节点个数
OUTPUT_NODE=10#输出层节点个数
IMAGE_SIZE=28#原始图像大小
NUM_CHANNELS=1#原始图像的深度
NUM_LABELS=10#输出深度
CONV1_DEEP=32#第一层卷积深度
CONV1_SIZE=5#过滤器的长宽
CONV2_DEEP=64#第二层卷积深度
CONV2_SIZE=5#过滤器的长宽
FC_SIZE=512#全连接层节点数
#输入参数
def inference(input_tensor,train,regularizer):
"""
第一层:卷积层
将28*28*1的原始图片像通过卷积核5*5卷积为28*28*32的矩阵,其中过滤器处理的矩阵深度为1,过滤器的深度为32
"""
#为了便于变量管理,tf中通过变量名称获取变量的机制主要是通过tf.get_varibale和tf.varibale_scope函数来实现
with tf.variable_scope('layer1-conv1'):
"""
第一个参数是name
第二个参数shape依次是卷积核高度,卷积核宽度,图像通道数(输入深度),卷积核个数(输出深度)
第三个参数是初始化权重参数的方式:采用截取的正态分布,标准差为0.1
"""
conv1_weights=tf.get_variable(
"weight",[CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
"""
第二个参数是shape,偏差的维度是卷积后的深度(卷积核个数)
第三个参数是初始化偏差的方式,采用常量0.0来初始化
"""
conv1_biases=tf.get_variable(
"bias",[CONV1_DEEP],
initializer=tf.constant_initializer(0.0))
"""
第一个参数:输入数据,shape为[batch,height,width,channels]
第二个参数:卷积核
第三个参数:步长,分别对应上面shape的每一个维度,即batch上步长为1,height上步长为1,width上步长为1,channels上步长为1
第四个参数:用全0补齐,这样的结果是,卷积前后矩阵的长宽不变
"""
conv1=tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding='SAME')
"""
使用RELU函数作为激活函数
tf.nn.bias_add 将一维的偏差项加到conv1中
"""
relu1=tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases))
"""
第二层:池化层
池化层的目的是防止过拟合
将28*28*32的矩阵池化为14*14*32的矩阵
该池化层的参数说明如下:
第一个参数是输入矩阵
第二个参数是池化矩阵大小:对应着[batch,height,width,channels],即对一个batch的2*2*1池化
第三个参数是步长,与上面对应,每次移动一个batch的2个高,2个宽,深度为1的步长
第三个参数是使用全0填充
"""
with tf.name_scope("layer2-pool1"):
pool1=tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
"""
第三层:卷积层
将14*14*32的矩阵卷积为14*14*64
"""
with tf.variable_scope('layer3-conv2'):
conv2_weights=tf.get_variable(
"weight",[CONV2_SIZE,CONV2_SIZE,CONV1_DEEP,CONV2_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
conv2_biases=tf.get_variable(
"bias",[CONV2_DEEP],
initializer=tf.constant_initializer(0.0))
conv2=tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding="SAME")
relu2=tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))
"""
第四层:池化层
将14*14*64的矩阵池化为7*7*64
"""
with tf.name_scope("layer4-pool2"):
pool2=tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
pool_shape=pool2.get_shape().as_list()#获取shape并转为list
nodes=pool_shape[1]*pool_shape[2]*pool_shape[3]#将矩阵(计算矩阵(7*7*64)的节点个数,用于全连接的输入节点,第一维为batch
reshaped=tf.reshape(pool2,[pool_shape[0],nodes])#将pool2从[batch,7,7,64]变为[batch,7*7*64]
"""
第五层:全连接层
输入节点为7*7*64
输出节点为512
"""
with tf.variable_scope("layer5-fc1"):
fc1_weights=tf.get_variable(
"weight",[nodes,FC_SIZE],
initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer!=None:tf.add_to_collection("losses",regularizer(fc1_weights))
fc1_biases=tf.get_variable("bias",[FC_SIZE],initializer=tf.constant_initializer(0.1))
fc1=tf.nn.relu(tf.matmul(reshaped,fc1_weights)+fc1_biases)
if train:fc1=tf.nn.dropout(fc1,0.5)
"""
第六层:全连接层
输入节点为512
输出节点为10
"""
with tf.variable_scope('layer6-fc2'):
fc2_weights=tf.get_variable(
"weight",[FC_SIZE,NUM_LABELS],
initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer!=None:tf.add_to_collection("losses",regularizer(fc2_weights))
fc2_biases=tf.get_variable(
"bias",[NUM_LABELS],
initializer=tf.constant_initializer(0.1))
logit=tf.matmul(fc1,fc2_weights)+fc2_biases
return logit

训练程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import tensorflow as tf
import chapter6.letNet_inference as letNet_inference
import numpy as np
BATCH_SIZE=100#批量处理的大小
LEARNING_RATE_BASE=0.01#学习率
LEARNING_RATE_DECAY=0.99#
REGULARIZATION_RATE=0.0001#正则化系数
TRAINING_STEPS=6000#训练次数
MOVING_AVERAGE_DECAY=0.99#衰减率
def train(mnist):
"""
:param mnist:
:return:
"""
"""
输入张量
第一个参数为值的类型
第二个参数为张量矩阵,shape表示:批量个数,原始图片像素长,原始图片像素宽,原始图片像素深度
第三个参数:变量名
"""
x=tf.placeholder(
tf.float32,
[BATCH_SIZE,letNet_inference.IMAGE_SIZE,letNet_inference.IMAGE_SIZE,letNet_inference.NUM_CHANNELS],
name='x-input')
"""
输出张量
第一个参数为值类型
第二个参数为张量矩阵,
"""
y_=tf.placeholder(
tf.float32,
[None,letNet_inference.OUTPUT_NODE],
name='y-input')
regularizer=tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)#L2正则
y=letNet_inference.inference(x,False,regularizer)
global_step=tf.Variable(0,trainable=False)
variable_averages=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
variable_averages_op=variable_averages.apply(tf.trainable_variables())
"""
logits:其shape是[batch_size,num_classes],一般为神经网络的最后一层
labels:shape与logits相同,神经网络期望的输出
tf.argmax:表示对矩阵(y_)按行或列(0表示按列,1表示按行)计算最大值
这个函数的作用就是计算最后一层softmax层的cross entropy,然后将输出的结果和labels做交叉熵
返回的是一个向量,这里还需要将向量中的值全部求和取平均
关于这个函数说明参见:https://www.cnblogs.com/welhzh/p/6595032.html
"""
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
cross_entropy_mean=tf.reduce_mean(cross_entropy)#求取平均值
loss=cross_entropy_mean+tf.add_n(tf.get_collection('losses'))#交叉熵和正则项作为损失函数
"""
指数衰减法
参数依次如下:
基础学习率,
当前迭代轮数,
迭代次数,(这里取得是训练完所有数据需要迭代的次数)【表示的是迭代该次数后,对基础学习率进行修正】
学习率衰减速度
"""
learning_rate=tf.train.exponential_decay(
LEARNING_RATE_BASE,
global_step,
mnist.train.num_examples/BATCH_SIZE,
LEARNING_RATE_DECAY,
staircase=True)
"""
优化算法,以learning_rate的速率来最小化损失函数,
"""
train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
"""
"""
with tf.control_dependencies([train_step,variable_averages_op]):
train_op=tf.no_op(name='train')
saver=tf.train.Saver()
with tf.Session() as sess:
tf.global_variables_initializer().run()
for i in range(TRAINING_STEPS):
xs,ys=mnist.train.next_batch(BATCH_SIZE)
#将训练数据格式调整为一个二维矩阵
reshaped_xs = np.reshape(xs, (
BATCH_SIZE,
letNet_inference.IMAGE_SIZE,
letNet_inference.IMAGE_SIZE,
letNet_inference.NUM_CHANNELS))
_, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: reshaped_xs, y_: ys})
if i % 1000 == 0:
print("After %d training step(s), loss on training batch is %g." % (step, loss_value))

如果觉得有帮助,给我打赏吧!