学过了CNN,就像使用CNN完成一次手写数字的识别过程。
这次的CNN网络结果使用LeNet-v5网络结构,不使用tensorflow,
推导并编写代码,以便加深印象。
CNN简介
卷积层+ReLu
池化层
全连接层
LeNet-v5简介
LeNet-v5共有7层,具体如下:
- 输入图片: 32321. 图片大小为32像素,1通道。
- 卷积层:2
- 池化层(降采样层):2
- 全连接层:2
- 输出:1。手写数字识别中为10种数字的概率。
第一层 卷积层
- input image size: 28281
- 卷积核: 5*5,6个
- 卷积模式: same
- 卷积步长: 1
- 卷积Padding: 0
- output image size: 28286. 图片大小为28*28,共有6张Feature Map.
- 参数个数: ((55)+1)6 = 156. 其中+1是因为需要加入一个偏置。
- 连接数: 156(2828) = 122304.
第二层 平均池化层
- input image size: 28286
- 卷积核: 2*2
- 卷积模式: valid
- 卷积步长: 2
- 卷积Padding: 0
- output image size: 14146
第三层 卷积层
- input image size: 14146. 图片大小为28*28,共有6张Feature
- 卷积核: 5*5, 16个
- 卷积模式: valid
- 卷积步长: 1
- 卷积Padding: 0
- output image size: 101016
- 参数个数: ((55)+1)16 = 416
第四层 最大池化层
- input image size: 101016
- 卷积核: 2*2
- 卷积模式: valid
- 卷积步长: 2
- 卷积Padding: 0
- output image size: 5516
注: 需要将这一层的输出图片拉直成一维的数据,以适应下一层的输入。
第五层 全连接层
- input image size: 5516
- output: 120个单元
每个单元与第4层中全部400个单元之间进行全连接,
如同传统机器学习方法,FC5层计算输入向量与权重向量之间的点积,再加上一个偏置。
- 参数个数: 120(55*16+1) = 48120
全连接层的功能是实现分类或者回归(前面的卷积层和池化层的功能是提取图片特征)
第六层 全连接层
- input: 120单元
- output: 84单元
每个单元与第5层中全部120个单元之间进行全连接
- 参数个数: 84*(120+1) = 10164
第七层 Output输出层
- input: 84单元
- output: 1种类别
输出层由欧式径向基函数(Euclidean Radial Basis Function, RBF)单元
组成,
每类一个单元,每个有84个输入。
CNN推导
tensorflow lenet实现
输入
1 | import tensorflow as tf |
Lenet 网络实现
这部分实验了好久,主要的问题是每次训练得到的accuracy过低, 只有0.1左右,
一直以为是accuracy的计算方式问题或者是net结构问题, 调整了好久.
最终参考github上面star数量最多的两位前辈的代码,终于跑出了像样的accuracy.
1 | # https://github.com/ganyc717/LeNet |
1 | # https://github.com/xiao-data/lenet |
Lenet 计算loss
使用cross_entropy作为loss函数, 并且加入l2_regularization, 使用Adam Optimizer.
1 | cross_entropy = tf.reduce_mean( |
Lenet 计算accuracy
比较预测得到的输出和原始数据输入labels, 将[True, True, False,…]转换成float.
再计算总和求平均.
注意: 必须使用和计算loss时使用的output, 否则预测率很低
1 | # `{计算准确性需要使用同一次计算的输出, 否则会出现loss变低. 但是accuracy仍然不高的情况}` |
Lenet 训练
加载MNIST数据集, 分批次投喂给Lenet, 打印accuracy和loss.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
57import tensorflow as tf
from tensorflow.examples.tutorials.mnist \
import input_data
from lenet import Lenet
def main(argv):
tf.reset_default_graph()
# `{读取数据}`
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
# `{训练}`
lenet = Lenet()
sess = tf.Session()
is_trianed = False
saver = tf.train.Saver()
model_file = tf.train.latest_checkpoint("MNIST_model/")
if model_file != None:
saver.restore(sess, model_file)
is_trianed = True
print("restore variables from model file!")
else:
sess.run(tf.global_variables_initializer())
if not is_trianed:
for i in range(10000):
batch = mnist.train.next_batch(50)
if i % 100 == 0:
train_accuracy, train_loss = sess.run(
[lenet.train_accuracy, lenet.loss],
feed_dict={
lenet.raw_images: mnist.validation.images[:1000] , lenet.raw_labels: mnist.validation.labels[:1000], lenet.keep_prob:1
})
print("After %d iteration, the loss is %g, the accuracy is %g" % (i, train_loss, train_accuracy))
pass
_, output = sess.run(
[lenet.train_op,lenet.train_output],
feed_dict={lenet.raw_images: batch[0], lenet.raw_labels:batch[1], lenet.keep_prob:1
})
# print(output)
pass
saver.save(sess, "MNIST_model/mnist.ckpt")
pass
print("Train model success! \
Start test accuracy on test set!")
# `{测试}`
train_accuracy = sess.run(lenet.train_accuracy, feed_dict={
lenet.raw_images: mnist.test.images, lenet.raw_labels: mnist.test.labels, lenet.keep_prob: 1
})
print("the mean accuracy of test set is %g" % (train_accuracy))
print("Process End!")
pass
if __name__ == '__main__':
tf.app.run()
pass
运行结果
1 | ~/python.exe E:/document/python/Lenet/Train.py |