用c 实现卷积神经网络络实现mnist分类为什么会死机

mnist的卷积神经网络例子和上一篇博文中的神经网络例子大部分是相同的。但是CNN层数要多一些,网络模型需要自己来构建。
程序比较复杂,我就分成几个部分来叙述。
首先,下载并加载数据:
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
#下载并加载mnist数据
x = tf.placeholder(tf.float32, [None, 784])
#输入的数据占位符
y_actual = tf.placeholder(tf.float32, shape=[None, 10])
#输入的标签占位符
定义四个函数,分别用于初始化权值W,初始化偏置项b, 构建卷积层和构建池化层。&
#定义一个函数,用于初始化所有的权值 W
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
#定义一个函数,用于初始化所有的偏置项 b
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
#定义一个函数,用于构建卷积层
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
#定义一个函数,用于构建池化层
def max_pool(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
接下来构建网络。整个网络由两个卷积层(包含激活层和池化层),一个全连接层,一个dropout层和一个softmax层组成。&
x_image = tf.reshape(x, [-1,28,28,1])
#转换输入数据shape,以便于用于网络中
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
#第一个卷积层
h_pool1 = max_pool(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(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])
#reshape成向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#第一个全连接层
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#dropout层
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_predict=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
#softmax层
网络构建好后,就可以开始训练了。
cross_entropy = -tf.reduce_sum(y_actual*tf.log(y_predict))
train_step = tf.train.GradientDescentOptimizer(1e-3).minimize(cross_entropy)
#梯度下降法
correct_prediction = tf.equal(tf.argmax(y_predict,1), tf.argmax(y_actual,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
#精确度计算
sess=tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
#训练100次,验证一次
train_acc = accuracy.eval(feed_dict={x:batch[0], y_actual: batch[1], keep_prob: 1.0})
print 'step %d, training accuracy %g'%(i,train_acc)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
test_acc=accuracy.eval(feed_dict={x: mnist.test.images, y_actual: mnist.test.labels, keep_prob: 1.0})
print "test accuracy %g"%test_acc
Tensorflow依赖于一个高效的C++后端来进行计算。与后端的这个连接叫做session。一般而言,使用TensorFlow程序的流程是先创建一个图,然后在session中启动它。
这里,我们使用更加方便的InteractiveSession类。通过它,你可以更加灵活地构建你的代码。它能让你在运行图的时候,插入一些计算图,这些计算图是由某些操作(operations)构成的。这对于工作在交互式环境中的人们来说非常便利,比如使用IPython。
训练20000次后,再进行测试,测试精度可以达到99%。
完整代码:
# -*- coding: utf-8 -*-
Created on Thu Sep
8 15:29:48 2016
@author: root
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
#下载并加载mnist数据
x = tf.placeholder(tf.float32, [None, 784])
#输入的数据占位符
y_actual = tf.placeholder(tf.float32, shape=[None, 10])
#输入的标签占位符
#定义一个函数,用于初始化所有的权值 W
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
#定义一个函数,用于初始化所有的偏置项 b
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
#定义一个函数,用于构建卷积层
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
#定义一个函数,用于构建池化层
def max_pool(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
x_image = tf.reshape(x, [-1,28,28,1])
#转换输入数据shape,以便于用于网络中
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
#第一个卷积层
h_pool1 = max_pool(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(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])
#reshape成向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#第一个全连接层
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#dropout层
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_predict=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
#softmax层
cross_entropy = -tf.reduce_sum(y_actual*tf.log(y_predict))
train_step = tf.train.GradientDescentOptimizer(1e-3).minimize(cross_entropy)
#梯度下降法
correct_prediction = tf.equal(tf.argmax(y_predict,1), tf.argmax(y_actual,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
#精确度计算
sess=tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
#训练100次,验证一次
train_acc = accuracy.eval(feed_dict={x:batch[0], y_actual: batch[1], keep_prob: 1.0})
print('step',i,'training accuracy',train_acc)
train_step.run(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
test_acc=accuracy.eval(feed_dict={x: mnist.test.images, y_actual: mnist.test.labels, keep_prob: 1.0})
print("test accuracy",test_acc)
阅读(...) 评论()卷积神经网络大总结
时间: 09:59:39
&&&& 阅读:2208
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&
大家都清楚神经网络在上个世纪七八十年代是着实火过一回的,尤其是后向传播BP算法出来之后,但90年代后被SVM之类抢了风头,再后来大家更熟悉的是SVM、AdaBoost、随机森林、GBDT、LR、FTRL这些概念。究其原因,主要是神经网络很难解决训练的问题,比如梯度消失。当时的神经网络研究进入一个低潮期,不过Hinton老人家坚持下来了。
功夫不负有心人,2006年Hinton和学生发表了利用RBM编码的深层神经网络的Science Paper:Reducing the Dimensionality of Data with Neural Networks,不过回头来看,这篇paper在当今的实用性并不强,它的更大作用是把神经网络又推回到大家视线中,利用单层的RBM自编码预训练使得深层的神经网络训练变得可能,但那时候Deep learning依然争议很多,最终真正爆发是2012年的ImageNet的夺冠,这是后话。
如图中所示,这篇paper的主要思想是使用受限RBM先分层训练,受限的意思是不包含层内的相互连接边(比如vi*vj或hi*hj)。每一层RBM训练时的目标是使得能量最小:
能量最小其实就是P(v, h)联合概率最大,而其他v’相关的p(v’, h)较小,后面这个是归一化因子相关。这块如果理解有问题的,需要补一下RBM相关知识,目前网上资料不少了。
大致的过程为,从输入层开始,不断进行降维,比如左图中的2000维降到1000维, 降维时保证能量最小,也就是输出h和输入v比较一致,而和其他输入v’不一致,换句话说,输出尽量保证输入的信息量。降维从目标上比较类似于PCA,但Hinton在文章说这种方法比PCA效果会好很多,尤其是经过多层压缩的时候(比如784个像素压缩到6个实数),从原理应该也是这样的,RBM每一层都尽量保留了输入的信息。
预训练结束后,就会展开得到中间的解码器,这是一个叠加的过程,也就是下一层RBM的输出作为上一层RBM的输入。
最后再利用真实数据进行参数细调,目标是输入图片经过编码解码后尽量保持原图信息,用的Loss函数是负Log Likelihood:
这篇在今天看来实用性不太大,难度也不大,但在当时这篇文章看起来还是晦涩的,很多原理没有细讲。为何能中Science?个人认为,毕竟Hinton是神经网络的泰斗,换个人名不见经传的人估计中不了,另外这篇文章也确实使得以前不可能的深层神经网络变得可能了,在今天依然有很多可以借鉴的地方,细心的同学会发现上百或上千层的ResNet的思想在一定程度上和这篇论文是神似的。ResNet也是意识到深层(152层)不好直接训练,那就在单层上想办法,将原来直接优化H(x)改为优化残差F(x) = H(x)-x,其中H(X)是某一层原始的的期望映射输出,x是输入,相当于输入x有个直通车到达该层输出,从而使得单层的训练更加容易。
参考博客:/52machinelearning/p/5821587.html
参考资料:
[1] Paper:
[2] 代码:
CNN的发展史
& & & &上一篇回顾讲的是2006年Hinton他们的Science Paper,当时提到,2006年虽然Deep Learning的概念被提出来了,但是学术界的大家还是表示不服。当时有流传的段子是Hinton的学生在台上讲paper时,台下的机器学习大牛们不屑一顾,质问你们的东西有理论推导吗?有数学基础吗?搞得过SVM之类吗?回头来看,就算是真的,大牛们也确实不算无理取闹,是骡子是马拉出来遛遛,不要光提个概念。
& & & &时间终于到了2012年,Hinton的学生Alex Krizhevsky在寝室用GPU死磕了一个Deep Learning模型,一举摘下了视觉领域竞赛ILSVRC 2012的桂冠,在百万量级的ImageNet数据集合上,效果大幅度超过传统的方法,从传统的70%多提升到80%多。个人觉得,当时最符合Hinton他们心境的歌非《我不做大哥好多年》莫属。
& & & &这个Deep Learning模型就是后来大名鼎鼎的AlexNet模型。这从天而降的AlexNet为何能耐如此之大?有三个很重要的原因:
大量数据,Deep Learning领域应该感谢李飞飞团队搞出来如此大的标注数据集合ImageNet;GPU,这种高度并行的计算神器确实助了洪荒之力,没有神器在手,Alex估计不敢搞太复杂的模型;算法的改进,包括网络变深、数据增强、ReLU、Dropout等,这个后面后详细介绍。
& & & &从此,Deep Learning一发不可收拾,ILSVRC每年都不断被Deep Learning刷榜,如图1所示,随着模型变得越来越深,Top-5的错误率也越来越低,目前降到了3.5%附近,而在同样的ImageNet数据集合上,人眼的辨识错误率大概在5.1%,也就是目前的Deep Learning模型的识别能力已经超过了人眼。而图1中的这些模型,也是Deep Learning视觉发展的里程碑式代表。
图1. ILSVRC历年的Top-5错误率
& & & &在仔细分析图1中各模型结构之前我们先需要了解一下深度学习三驾马车之一————LeCun的LeNet网络结构。为何要提LeCun和LeNet,因为现在视觉上这些神器都是基于卷积神经网络(CNN)的,而LeCun是CNN的祖师爷,LeNet是LeCun打造的CNN经典之作。
& & & &LeNet以其作者名字LeCun命名,这种命名方式类似的还有AlexNet,后来又出现了以机构命名的网络结构GoogLeNet、VGG,以核心算法命名的ResNet。LeNet有时也被称作LeNet5或者LeNet-5,其中的5代表五层模型。不过别急,LeNet之前其实还有一个更古老的CNN模型。
最古老的CNN模型
& & & &1985年,Rumelhart和Hinton等人提出了后向传播(Back Propagation,BP)算法[1](也有说1986年的,指的是他们另一篇paper:Learning representations by back-propagating errors),使得神经网络的训练变得简单可行,这篇文章在Google Scholar上的引用次数达到了19000多次,目前还是比Cortes和Vapnic的Support-Vector Networks稍落后一点,不过以Deep Learning最近的发展劲头来看,超越指日可待。
& & & &几年后,LeCun利用BP算法来训练多层神经网络用于识别手写邮政编码[2],这个工作就是CNN的开山之作,如图2所示,多处用到了5*5的卷积核,但在这篇文章中LeCun只是说把5*5的相邻区域作为感受野,并未提及卷积或卷积神经网络。关于CNN最原始的雏形感兴趣的读者也可以关注一下文献[10]。
图2. 最古老的CNN网络结构图
& & & &1998年的LeNet5[4]标注着CNN的真正面世,但是这个模型在后来的一段时间并未能火起来,主要原因是费机器(当时苦逼的没有GPU啊),而且其他的算法(SVM,老实说是你干的吧?)也能达到类似的效果甚至超过。
图3. LeNet网络结构
& & & &初学者也可以参考一下Caffe中的配置文件:
/BVLC/caffe/blob/master/examples/mnist/lenet.prototxt
AlexNet、VGG、GoogLeNet、ResNet对比
& & & &LeNet主要是用于识别10个手写数字的,当然,只要稍加改造也能用在ImageNet数据集上,但效果较差。而本文要介绍的后续模型都是ILSVRC竞赛历年的佼佼者,这里具体比较AlexNet、VGG、GoogLeNet、ResNet四个模型。如表1所示。
Data Augmentation
Inception(NIN)
卷积核大小
全连接层数
全连接层大小
Local Response Normalization
Batch Normalization
表1 AlexNet、VGG、GoogLeNet、ResNet对比
& & & &接下里直接上图即可,AlexNet结构图如下:
图4. AlexNet网络结构
& & & &换个视角:
图5. AlexNet网络结构精简版
& & & &AlexNet相比传统的CNN(比如LeNet)有哪些重要改动呢:
(1) Data Augmentation
& & & &数据增强,这个参考李飞飞老师的cs231课程是最好了。常用的数据增强方法有:
随机裁剪、平移变换
颜色、光照变换
(2) Dropout
& & & &Dropout方法和数据增强一样,都是防止过拟合的。Dropout应该算是AlexNet中一个很大的创新,以至于Hinton在后来很长一段时间里的Talk都拿Dropout说事,后来还出来了一些变种,比如DropConnect等。
(3) ReLU激活函数
& & & &用ReLU代替了传统的Tanh或者Logistic。好处有:
ReLU本质上是分段线性模型,前向计算非常简单,无需指数之类操作;ReLU的偏导也很简单,反向传播梯度,无需指数或者除法之类操作;ReLU不容易发生梯度发散问题,Tanh和Logistic激活函数在两端的时候导数容易趋近于零,多级连乘后梯度更加约等于0;ReLU关闭了右边,从而会使得很多的隐层输出为0,即网络变得稀疏,起到了类似L1的正则化作用,可以在一定程度上缓解过拟合。
& & & &当然,ReLU也是有缺点的,比如左边全部关了很容易导致某些隐藏节点永无翻身之日,所以后来又出现pReLU、random ReLU等改进,而且ReLU会很容易改变数据的分布,因此ReLU后加Batch Normalization也是常用的改进的方法。
(4) Local Response Normalization
& & & &Local Response Normalization要硬翻译的话是局部响应归一化,简称LRN,实际就是利用临近的数据做归一化。这个策略贡献了1.2%的Top-5错误率。
(5) Overlapping Pooling
& & & &Overlapping的意思是有重叠,即Pooling的步长比Pooling Kernel的对应边要小。这个策略贡献了0.3%的Top-5错误率。
(6) 多GPU并行
& & & &这个不多说,比一臂之力还大的洪荒之力。
& & & &VGG结构图
图6. VGG系列网络结构
& & & &换个视角看看VGG-19:
图7. VGG-19网络结构精简版
& & & &VGG很好地继承了AlexNet的衣钵,一个字:深,两个字:更深。
&iframe id=&iframe_0.7388& src=&data:text/charset=utf8,%3Cimg%20id=%22img%22%20src=%22https://www.52ml.net/wp-content/uploads/2016/08/googlenet.png?_=%20style=%22border:max-width:967px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById(‘img‘);%20window.parent.postMessage(%7BiframeId:‘iframe_0.7388‘,width:img.width,height:img.height%7D,%20‘‘);%7D%3C/script%3E&
frameborder=&0& scrolling=&no& style=&border-style: border-width: width: 967 height: 285&&&/iframe&
图8. GoogLeNet网络结构
& & & &GoogLeNet依然是:没有最深,只有更深。
& & & &主要的创新在于他的Inception,这是一种网中网(Network In Network)的结构,即原来的结点也是一个网络。Inception一直在不断发展,目前已经V2、V3、V4了,感兴趣的同学可以查阅相关资料。Inception的结构如图9所示,其中1*1卷积主要用来降维,用了Inception之后整个网络结构的宽度和深度都可扩大,能够带来2-3倍的性能提升。
图9. Inception结构
网络结构如图10所示。
图10. ResNet网络结构
& & & &ResNet依然是:没有最深,只有更深(152层)。听说目前层数已突破一千。
& & & &主要的创新在残差网络,如图11所示,其实这个网络的提出本质上还是要解决层次比较深的时候无法训练的问题。这种借鉴了Highway Network思想的网络相当于旁边专门开个通道使得输入可以直达输出,而优化的目标由原来的拟合输出H(x)变成输出和输入的差H(x)-x,其中H(X)是某一层原始的的期望映射输出,x是输入。
图11. ResNet网络结构
Deep Learning一路走来,大家也慢慢意识到模型本身结构是Deep Learning研究的重中之重,而本文回顾的LeNet、AlexNet、GoogLeNet、VGG、ResNet又是经典中的经典。
随着2012年AlexNet的一举成名,CNN成了计算机视觉应用中的不二选择。目前,CNN又有了很多其他花样,比如R-CNN系列。
参考博客:/52machinelearning/p/5821591.html
[参考文献]
[1] DE Rumelhart, GE Hinton, RJ Williams, Learning internal representations by error propagation. 1985 – DTIC Document.
[2] Y. LeCun , B. Boser , J. S. Denker , D. Henderson , R. E. Howard , W. Hubbard and L. D. Jackel, “Backpropagation applied to handwritten zip code recognition”, Neural Computation, vol.
1, no. 4, pp. 541-551, 1989.
[3] Kaiming He, Deep Residual Learning, http://image-net.org/challenges/talks/ilsvrc2015_deep_residual_learning_kaiminghe.pdf
[4] Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner. Gradient-based learning applied to document recognition. Proceedings of the IEEE, 86(11):, 1998.
[5] A. Krizhevsky, I. Sutskever, and G. Hinton. Imagenet classification with deep convolutional neural networks. In Advances in Neural Information Processing Systems 25, pages ,
[6] Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott E. Reed, Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich: Going deeper with convolutions. CVPR
[7] Karen Simonyan, Andrew Zisserman: Very Deep Convolutional Networks for Large-Scale Image Recognition. CoRR abs/ (2014)
[8] Kaiming He, Xiangyu Zhang, Shaoqing Ren, and Jian Sun. Deep Residual Learning for Image Recognition. IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2016
[9] 一些对应的caffe实现或预训练好的模型: /BVLC/caffe /BVLC/caffe/wiki/Model-Zoo
[10] K. Fukushima. Neocognitron: A self-organizing neural network model for a mechanism of pattern recognition unaffected by shift in position. Biological Cybernetics, 36(4): 93-202, 1980.
关于卷积神经网络CNN,网络和文献中有非常多的资料,我在工作/研究中也用了好一段时间各种常见的model了,就想着简单整理一下,以备查阅之需。如果读者是初接触CNN,建议可以先看一看“Deep Learning(深度学习)学习笔记整理系列”中关于CNN的介绍[1],是介绍我们常说的Lenet为例,相信会对初学者有帮助。
Lenet,1986年Alexnet,2012年GoogleNet,2014年VGG,2014年Deep Residual Learning,2015年
就从Lenet说起,可以看下,可以试着理解每一层的大小,和各种参数。由两个卷积层,两个池化层,以及两个全连接层组成。
卷积都是5*5的模板,stride=1,池化都是MAX。下图是一个类似的结构,可以帮助理解层次结构(和caffe不完全一致,不过基本上差不多)
2012年,Imagenet比赛冠军的model——Alexnet [2](以第一作者alex命名)。。说实话,这个model的意义比后面那些model都大很多,首先它证明了CNN在复杂模型下的有效性,然后GPU实现使得训练在可接受的时间范围内得到结果,确实让CNN和GPU都大火了一把,顺便推动了有监督DL的发展。
模型结构见下图,别看只有寥寥八层(不算input层),但是它有60M以上的参数总量,事实上在参数量上比后面的网络都大。
这个图有点点特殊的地方是卷积部分都是画成上下两块,意思是说吧这一层计算出来的feature map分开,但是前一层用到的数据要看连接的虚线,如图中input层之后的第一层第二层之间的虚线是分开的,是说二层上面的128map是由一层上面的48map计算的,下面同理;而第三层前面的虚线是完全交叉的,就是说每一个192map都是由前面的128+128=256map同时计算得到的。
Alexnet有一个特殊的计算层,LRN层,做的事是对当前层的输出结果做平滑处理。下面是我画的示意图:
前后几层(对应位置的点)对中间这一层做一下平滑约束,计算方法是:
具体打开Alexnet的每一阶段(含一次卷积主要计算)来看[2][3]:
(1)con - relu - pooling - LRN
具体计算都在图里面写了,要注意的是input层是227*227,而不是paper里面的224*224,这里可以算一下,主要是227可以整除后面的conv1计算,224不整除。如果一定要用224可以通过自动补边实现,不过在input就补边感觉没有意义,补得也是0。
(2)conv - relu - pool - LRN
和上面基本一样,唯独需要注意的是group=2,这个属性强行把前面结果的feature map分开,卷积部分分成两部分做。
(3)conv - relu
(4)conv-relu
(5)conv - relu - pool
(6)fc - relu - dropout
这里有一层特殊的dropout层,在alexnet中是说在训练的以1/2概率使得隐藏层的某些neuron的输出为0,这样就丢到了一半节点的输出,BP的时候也不更新这些节点。&
fc - relu - dropout&
(8)fc - softmax&
以上图借用[3],感谢。
googlenet[4][5],14年比赛冠军的model,这个model证明了一件事:用更多的卷积,更深的层次可以得到更好的结构。(当然,它并没有证明浅的层次不能达到这样的效果)
这个model基本上构成部件和alexnet差不多,不过中间有好几个inception的结构:
是说一分四,然后做一些不同大小的卷积,之后再堆叠feature map。
计算量如下图,可以看到参数总量并不大,但是计算次数是非常大的。&
VGG有很多个版本,也算是比较稳定和经典的model。它的特点也是连续conv多,计算量巨大(比前面几个都大很多)。具体的model结构可以参考[6],这里给一个简图。基本上组成构建就是前面alexnet用到的。&
下面是几个model的具体结构,可以查阅,很容易看懂。
Deep Residual Learning
这个model是2015年底最新给出的,也是15年的imagenet比赛冠军。可以说是进一步将conv进行到底,其特殊之处在于设计了“bottleneck”形式的block(有跨越几层的直连)。最深的model采用的152层!!下面是一个34层的例子,更深的model见表格。&
其实这个model构成上更加简单,连LRN这样的layer都没有了。
block的构成见下图:
OK,到这里把常见的最新的几个model都介绍完了,可以看到,目前cnn model的设计思路基本上朝着深度的网络以及更多的卷积计算方向发展。虽然有点暴力,但是效果上确实是提升了。当然,我认为以后会出现更优秀的model,方向应该不是更深,而是简化。是时候动一动卷积计算的形式了。
参考博客:http://blog.csdn.net/xbinworld/article/details/
[2] ImageNet Classification with Deep Convolutional Neural Networks&
[5] Going deeper with convolutions&
[6] VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION
本系列博客是对刘昕博士的的一个扩充性资料。
主要讨论CNN的发展,并且引用刘昕博士的思路,对CNN的发展作一个更加详细的介绍,将按下图的CNN发展史进行描述:
上图所示是刘昕博士总结的CNN结构演化的历史,起点是神经认知机模型,此时已经出现了卷积结构,经典的LeNet诞生于1998年。然而之后CNN的锋芒开始被SVM等手工设计的特征盖过。随着ReLU和dropout的提出,以及GPU和带来的历史机遇,CNN在2012年迎来了历史突破–AlexNet.
CNN的演化路径可以总结为以下几个方向:
进化之路一:网络结构加深进化之路二:加强卷积功能进化之路三:从分类到检测进化之路四:新增功能模块
本系列博客将对CNN发展的四条路径中最具代表性的CNN模型结构进行讲解。
一切的开始(&)
下图是广为流传LeNet的网络结构,麻雀虽小,但五脏俱全,卷积层、pooling层、全连接层,这些都是现代CNN网络的基本组件。
输入尺寸:32*32卷积层:3个降采样层:2个全连接层:1个输出:10个类别(数字0-9的概率)
因为LeNet可以说是CNN的开端,所以这里简单介绍一下各个组件的用途与意义。
Input (32*32)
输入图像Size为32*32。这要比mnist中最大的字母(28*28)还大。这样做的目的是希望潜在的明显特征,如笔画断续、角点能够出现在最高层特征监测子感受野的中心。
C1, C3, C5 (卷积层)
卷积核在二维平面上平移,并且卷积核的每个元素与被卷积图像对应位置相乘,再求和。通过卷积核的不断移动,我们就有了一个新的图像,这个图像完全由卷积核在各个位置时的乘积求和的结果组成。
二维卷积在图像中的效果就是:&
对图像的每个像素的邻域(邻域大小就是核的大小)加权求和得到该像素点的输出值。具体做法如下:
卷积运算一个重要的特点就是: 通过卷积运算,可以使原信号特征增强,并且降低噪音。
不同的卷积核能够提取到图像中的不同特征,这里有&,下面是不同卷积核得到的不同的feature map,
以C1层进行说明:C1层是一个卷积层,有6个卷积核(提取6种局部特征),核大小为5*5,能够输出6个特征图Feature Map,大小为28*28。C1有156个可训练参数(每个滤波器5*5=25个unit参数和一个bias参数,一共6个滤波器,共(5*5+1)6=156个参数),共156&(28*28)=122,304个连接。
S2, S4 (pooling层)
S2, S4是下采样层,是为了降低网络训练参数及模型的过拟合程度。池化/采样的方式通常有以下两种:
Max-Pooling: 选择Pooling窗口中的最大值作为采样值;Mean-Pooling: 将Pooling窗口中的所有值相加取平均,以平均值作为采样值;
S2层是6个14*14的feature map,map中的每一个单元于上一层的 2*2 领域相连接,所以,S2层是C1层的1/4。
F6 (全连接层)
F6是全连接层,类似MLP中的一个layer,共有84个神经元(为什么选这个数字?跟输出层有关),这84个神经元与C5层进行全连接,所以需要训练的参数是:(120+1)*84=10164.&
如同经典神经网络,F6层计算输入向量和权重向量之间的点积,再加上一个偏置。然后将其传递给sigmoid函数产生单元i的一个状态。
Output (输出层)
输出层由欧式径向基函数(Euclidean Radial Basis Function)单元组成,每类一个单元,每个有84个输入。&
换句话说,每个输出RBF单元计算输入向量和参数向量之间的欧式距离。输入离参数向量越远,RBF输出的越大。用概率术语来说,RBF输出可以被理解为F6层配置空间的高斯分布的负log-likelihood。给定一个输式,损失函数应能使得F6的配置与RBF参数向量(即模式的期望分类)足够接近。
王者回归()
AlexNet 可以说是具有历史意义的一个网络结构,可以说在AlexNet之前,深度学习已经沉寂了很久。历史的转折在2012年到来,AlexNet 在当年的ImageNet图像分类竞赛中,top-5错误率比上一年的冠军下降了十个百分点,而且远远超过当年的第二名。
AlexNet 之所以能够成功,深度学习之所以能够重回历史舞台,原因在于:
非线性激活函数:ReLU防止过拟合的方法:Dropout,Data augmentation大数据训练:百万级ImageNet图像数据其他:GPU实现,LRN归一化层的使用
下面简单介绍一下AlexNet的一些细节:
Data augmentation
有一种观点认为神经网络是靠数据喂出来的,若增加训练数据,则能够提升算法的准确率,因为这样可以避免过拟合,而避免了过拟合你就可以增大你的网络结构了。当训练数据有限的时候,可以通过一些变换来从已有的训练数据集中生成一些新的数据,来扩大训练数据的size。
其中,最简单、通用的图像数据变形的方式:
从原始图像(256,256)中,随机的crop出一些图像(224,224)。【平移变换,crop】水平翻转图像。【反射变换,flip】给图像增加一些随机的光照。【光照、彩色变换,color jittering】
AlexNet 训练的时候,在data augmentation上处理的很好:
随机crop。训练时候,对于256*256的图片进行随机crop到224*224,然后允许水平翻转,那么相当与将样本倍增到((256-224)^2)*2=2048。测试时候,对左上、右上、左下、右下、中间做了5次crop,然后翻转,共10个crop,之后对结果求平均。作者说,不做随机crop,大网络基本都过拟合(under substantial overfitting)。对RGB空间做PCA,然后对主成分做一个(0, 0.1)的高斯扰动。结果让错误率又下降了1%。
ReLU 激活函数
Sigmoid 是常用的非线性的激活函数,它能够把输入的连续实值“压缩”到0和1之间。特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1.&
但是它有一些致命的&缺点:
Sigmoids saturate and kill gradients.&sigmoid 有一个非常致命的缺点,当输入非常大或者非常小的时候,会有饱和现象,这些神经元的梯度是接近于0的。如果你的初始值很大的话,梯度在反向传播的时候因为需要乘上一个sigmoid 的导数,所以会使得梯度越来越小,这会导致网络变的很难学习。Sigmoid 的 output 不是0均值.&这是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值的信号作为输入。&
产生的一个结果就是:如果数据进入神经元的时候是正的(e.g.&x&0&elementwise
in&f=wTx+b),那么&w&计算出的梯度也会始终都是正的。&
当然了,如果你是按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的 kill gradients 问题相比还是要好很多的。
ReLU 的数学表达式如下:&
f(x)=max(0,x)
很显然,从图左可以看出,输入信号&0时,输出都是0,&0&的情况下,输出等于输入。w&是二维的情况下,使用ReLU之后的效果如下:
Alex用ReLU代替了Sigmoid,发现使用 ReLU 得到的SGD的收敛速度会比 sigmoid/tanh 快很多。
主要是因为它是linear,而且 non-saturating(因为ReLU的导数始终是1),相比于 sigmoid/tanh,ReLU 只需要一个阈值就可以得到激活值,而不用去算一大堆复杂的运算。
关于激活函数更多内容,请移步我的另一篇文章:http://blog.csdn.net/cyh_24/article/details/
结合预先训练好的许多不同模型,来进行预测是一种非常成功的减少测试误差的方式(Ensemble)。但因为每个模型的训练都需要花了好几天时间,因此这种做法对于大型神经网络来说太过昂贵。
然而,AlexNet 提出了一个非常有效的模型组合版本,它在训练中只需要花费两倍于单模型的时间。这种技术叫做Dropout,它做的就是以0.5的概率,将每个隐层神经元的输出设置为零。以这种方式“dropped out”的神经元既不参与前向传播,也不参与反向传播。
所以每次输入一个样本,就相当于该神经网络就尝试了一个新的结构,但是所有这些结构之间共享权重。因为神经元不能依赖于其他特定神经元而存在,所以这种技术降低了神经元复杂的互适应关系。
正因如此,网络需要被迫学习更为鲁棒的特征,这些特征在结合其他神经元的一些不同随机子集时有用。在测试时,我们将所有神经元的输出都仅仅只乘以0.5,对于获取指数级dropout网络产生的预测分布的几何平均值,这是一个合理的近似方法。
单个GTX 580 GPU只有3GB内存,这限制了在其上训练的网络的最大规模。因此他们将网络分布在两个GPU上。&
目前的GPU特别适合跨GPU并行化,因为它们能够直接从另一个GPU的内存中读出和写入,不需要通过主机内存。
他们采用的并行方案是:在每个GPU中放置一半核(或神经元),还有一个额外的技巧:GPU间的通讯只在某些层进行。
例如,第3层的核需要从第2层中所有核映射输入。然而,第4层的核只需要从第3层中位于同一GPU的那些核映射输入。
Local Responce Normalization
一句话概括:本质上,这个层也是为了防止激活函数的饱和的。
个人理解原理是通过正则化让激活函数的输入靠近“碗”的中间(避免饱和),从而获得比较大的导数值。
所以从功能上说,跟ReLU是重复的。
不过作者说,从试验结果看,LRN操作可以提高网络的泛化能力,将错误率降低了大约1个百分点。
AlexNet 优势在于:网络增大(5个卷积层+3个全连接层+1个softmax层),同时解决过拟合(dropout,data augmentation,LRN),并且利用多GPU加速计算
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&国之画&&&& &&&&chrome插件&&
版权所有 京ICP备号-2
迷上了代码!

我要回帖

更多关于 卷积神经网络 的文章

 

随机推荐