||转载请标明出处:http://blog.csdn.net/weixin_37669436/article/details/72971982
楔子
讲真,卷积神经网络(Convolutional Neural Network,CNN)不是仅仅一篇两篇文章能讲清楚的,何况囧于博主水平有限,也不能将其融会贯通,娓娓道来,只能知其半解,分享博主粗鄙的经验。这篇文章的重点不在于卷积神经的数学推导和剖析,关于卷积神经的原理网上大可找到非常详细,科学可依赖的介绍,你也可以查找《Machine Learning》(周志华)这本西瓜书,下面我会罗列一些关于这方面的论文。本章主要是从TensorFlow的角度去实现卷积神经,可以算的上式TensorFlow对CNN的实战入门。
- 参见 Geoffrey Hinton(即深度学习之父)的论文:Rectified Linear Units Improve Restricted Boltzmann Machines
- 参考 Geoffrey Hinton 的论文:Dropout: A Simple Way to Prevent Neural Networks from Overfitting
- 参阅 Min Lin 的论文:Network In Network
- Yoshua Bengio (另外一个深度学习先驱 )论文:How transferable are features in deep neural networks?
- Ali Sharif Razavian 论文:CNN Features off-the-shelf: an Astounding Baseline for Recognition
- Jeff Donahue 论文:DeCAF: A Deep Convolutional Activation Feature for Generic Visual Recognition
- 知乎上有非常直观的解释:了解详情
一.前提
本文的前提是你已经了解或熟悉了卷积神经的原理,如果你是初次了解,网上有很多介绍卷积神经的文章和专栏,他们很多都讲解的非常清楚,我在这里就不在重复啰嗦,班门弄斧了。
- 百科的介绍:点击进入
- 一篇非常详细的专栏:点击进入
- 深度学习元老Yann Lecun(下附图)详解卷积神经网络:点击进入
简书上一篇文章:点击进入
反正知识遍地都是,不管是你百度还是Google,关键在于你是否想去学。如果你将上面其中之一看懂的话,那么你就基本掌握了卷积神经的一些基础,接下来构建代码也会灰常清晰。
首先,在写代码之前,我要贴出这哥们的照片来镇楼。这个神可谓是卷积神经的先驱,没有他,我们不会学习到如此精巧的知识,也不会探索到卷积神经的奥妙。
Yann LeCun 出生在法国,曾在多伦多大学跟随深度学习鼻祖Geoffrey Hinton进行博士后研究。早在20世纪80年代末,Yann LeCun就作为贝尔实验室的研究员提出了卷积网络技术,并展示如何使用它来大幅度提高手写识别能力。上世纪末本世纪初,当神经网络失宠时Yann LeCun是少数几名一直坚持的科学家之一。他于2003年成为纽约大学教授,并从此引领了深度学习的发展,目前任职于Facebook FAIR实验室。
二.小刀牛试:实现简单的CNN
我们现在构建一个简单的卷积神经,我们使用的数据集依然为经典中的战斗机的MNIST,预期可以达到99.2%左右的准确率。下面是这个简单卷积神经的结构图。
1.结构
结构如上图,找了半天才发现电脑没有一个可以画图的ide,第一次用wps画这么龌龊的结构图(汗~~)。
注意上图,卷积层(Convolution layer)它的深度(高度)是增加的,这也是符合常理的。卷积层视图将神经网络中的每一小块进行更加深入地分析从而得到抽象程度更高的特征,所以一般,通过卷积层处理的节点会变得很深。
池化层(Pooling)不会改变三维矩阵的深度,但是它会缩小矩阵的大小,如图所示,卷积层明显比池化层大(截面积)。
Dropout层,我在上篇博客上讲过,它是进行特征筛选的,上面的0.5表示保留的参数百分比(keep_prob),你可以在我上一篇博客上好好看看Drouput层的用法。(了解详情)
2.载入MNIST数据
这个我就不多说,毕竟这个号称飞机中的战斗鸡的经典数据集几乎是无人不晓,无人不用。
"""
卷积神经网络:两个卷积层+一个全连接层
目的:手写数字识别
数据集:MNIST数据
预计准确率:99.2%
结构:input-->Conv1+ReLu-->MaxPool1-->Conv2+ReLu-->MaxPool2-->FC1+ReLu-->DropOut-->FC2+SoftMax-->Output
"""
from tensroflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist=input_data.read_data_sets('MNIST_data/',one_hot=True)
sess=tf.InteractiveSession()
3.权重(weight),偏执(bias)定义函数
我们这里使用截断的高斯分布(了解详情wiki)来初始化权重,而且我们的偏执(bias)也增加一个小的正值(0.1)用来避免死亡节点。
"""定义权重和偏置"""
def weight_variable(shape):
return tf.Variable(tf.truncated_normal(shape=shape,stddev=0.1))#截断的高斯分布
def bias_variable(shape):
return tf.Variabel(tf.constant(0.1,shape=shape))
4.定义卷积,池化函数
我们这里讲卷积的步长全部设置为1,padding为’SAME’,最大池化层的尺寸为2x2,步长也为2x2,也就是说它会对图片进行2x2的缩小,例如我们图片是28x28大小尺寸,经过这个池化层后就变成了14x14的大小。
"""定义卷积"""
def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
"""定义池化"""
def max_pool_2x2(x):
return tf.nn.max_pool_2x2(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
5.定义参数和算法公式
注意这里训练次数为20000次,我们首先将784的一维向量转为28x28的结构。x_images=tf.reshape(x,[-1,28,28,1])
中各个参数的意思为:-1代表样本数量不固定,28x28为输入样本尺寸,1代表颜色通道数量,一般灰度图颜色通道数量为1,而彩色RGB的即为3.
"""定义参数和算法公式"""
input_n=784
training_nums=20000
batch_size=50
learning_rate=1e-4
x=tf.placeholder(tf.float32,[None,784])
y_=tf.placeholder(tf.float32,[None,10])
keep_prob=tf.placeholder(tf.float32)
x_images=tf.reshape(x,[-1,28,28,1])
6.前向传播算法
接下来就是我们的结构层了,结构如上图,我们在每层中用了ReLu激活函数(activation function),来进行非线性处理。最后使用softmax层输出结果。
"""第一个卷积层"""
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
h_conv1=tf.nn.relu(conv2d(x_images,W_conv1)+b_conv1)
h_pool1=max_pool_2x2(h_conv1)
"""第二个卷积层"""
W_conv2=weight_variable([5,5,32,64])
b_conv2=bias_variable([64])
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
h_pool2=max_pool_2x2(h_conv2)
"""全连接层"""
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2,W_fc1)+b_fc1)
"""DropOut层"""
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
"""全连接层"""
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
7.定义损失,训练及测试
最后一步,我们使用交叉熵作为损失,Adam作为优化器进行优化,最后求出准确率的平均值。训练过程,每一百步进行测试并打印。并且训练的dropout参数(keep_prob)为0.5,因为我们要提高参数多样性,提升泛化性。
"""定义损失和优化器"""
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1]))
train_step=tf.AdamOptimizer(learning_rate).minimize(cross_entropy)
predictions=tf.eqaul(tf.argmax(y_,1),tf.argmax(y,1))
accuarcy=tf.reduce_mean(tf.cast(predictions,tf.float32))
"""训练过程"""
tf.global_variables_initializer().run()
for i in range(training_nums):
x_batch,y_batch=tf.train.next_batch(batch_size)
if i%100==0:
print('step: %d, accuarcy: %g'%(i,accuarcy.eval(feed_dict={x:x_batch,y_:y_batch,keep_prob:1.0})))
train_step.run(feed_dict={x:x_batch,y_:y_batch,keep_prob:0.5})
"""测试过程"""
print('accuarcy: %g'%accuarcy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
"""
后记:这个CNN模型可以得到准确率约为99.2%,基本满足对手写数字识别准确率的要求了
"""
三.总结
上面我们针对MNIST数据集,运用了TensorFlow编写了一个简单的卷积神经网络,这个卷积神经的结构很简单,即为两个卷积池化层+一个全连接层(Fully Connection),最后运用Softmax分类器进行输出,我们没有建造复杂的神经结构,其实对于MNIST这种数据集,这样简单的卷积神经早已够用,但要是针对更为庞大复杂的CIFAR-10,这个明显都显得相形见绌。
相关代码:可在我的Github上进行下载(点击进入)
参考文献:
- 《机器学习》周志华
- 《TensorFlow实战》才云科技 郑泽宇
- 其他论文,如上面链接