转自:http://www.sohu.com/a/138403426_470008
卷积神经网络基础
神经网络
先借用 CNTK 的一个例子,来看看如何使用神经网络来进行分类。如果想根据一个人的年龄和年收入,对他的政治倾向进行分类(保守派,居中和自由派),怎么做呢?答案是通过已知值,建立并训练一个预测模型。该模型是某种函数,由两个输入产生一个结果,该结果能够解释他属于哪个政治派别。
训练和测试数据。输入值 X1 和 X2 分别代表年龄和收入,三个颜色的点代表政治倾向类型。实心点代表训练数据,空心点代表预测结果。本图源自 MSDN 的 Machine Learning - Exploring the Microsoft CNTK Machine Learning Tool 一文。
基本的神经网络,本图源自 MSDN 的 Machine Learning - Exploring the Microsoft CNTK Machine Learning Tool 一文。
这就可以用一个简单的神经网络来解决:两个输入节点 (input nodes,分别代表年龄和收入) 和三个输出节点 (output nodes 分别代表三个政治倾向的概率)。输入(8.0, 3.0) 时, 输出 (0.3090, 0.0055, 0.6854)。该网络还有 5 个隐藏节点 (hidden nodes)。每个节点用从 0 开始的编号来代表,比如 input[0] 是最靠左上角的节点,output2 是最右下角的。
中间的连线叫做权重(weights),比如,从 input[0] 到 hidden[0] 的权重为 2.41。计算隐藏节点的输出值时,先将每个输入的权重乘以所连的节点的值,将所有乘积叠加,并加上偏置量,再输入隐含节点的激活函数,即可得到输出。
常见的隐藏层激活函数包括 tanh(双曲正切函数)、Sigmoid 和 ReLU。
常见的激活函数:Sigmoid,双曲正切和 ReLU,图片源于 A Practical Introduction to Deep Learning with Caffe and Python 一文。
比如,图中隐含层第三个节点 h[2]:
以此类推,可以算出所有隐藏层的输出。最终输出和隐藏节点的算法类似,只是去掉了激活函数,比如 output[0]:
我们希望得到不同结果的概率,因此将 output 输入到 softmax 函数,进行转换。
它会把一个由 N 个值组成的向量,“压”成另一个 N 个值的向量。每个结果都在(0,1)之间,且总和为 1。同时,该函数能放大最大的值,让大值影响更大,并削弱较小的值的作用。因此,Softmax 激活函数常用于神经网络的最后一层,用来得到概率。
以此类推: output[1]=0.0055, output[2]=0.6854。output[2] 代表的概率最高,0.6854,因此对(8.0,3.0)的分类是“绿色”,即“自由派”。这些工作是由最后一层:全互联层(Fully Connected Layer) 来完成。
用于图像识别的神经网络
图像由像素组成,彩色图像包括 RGB(红绿蓝)分量,每个分量的轻重由灰度值表示。 因此,神经网络的输入是 N 维数组,长宽深,分别由 RGB 三个颜色分量组成。
图片源于 http://xrds.acm.org/blog/2016/06/convolutional-neural-networks-cnns-illustrated-explanation/
我们希望通过神经网络后,得到一组数字,来描述每种结果的可能性。对肺癌图像而言,我们希望得到“阴性”和“阳性”这两种情况的各自概率。
图像通过卷积神经网络的卷积层、激活层、池化层、批量归一化层和全互联层(Fully Connected Layer)将产生上述结果。
感谢 *A beginner's guide to understanding convolutional Neural Networks* 一文
实际上,不需要通过卷积,也可以实现图像识别——只需要用样本图像的二维数组 + 标签,训练神经网络,也可以产生一样的效果。数据量越大,效果越好。
为什么要在“神经网络”前加“卷积”?
答案很简单。如果要识别一个在图片里位置居中的手写的“8”,用神经网络 + 一张 NVIDIA GTX 1080 就可以搞定,无需卷积。然而,同样的“8”,如果位置不居中,在画面的左上角、右下角或缩小 50% 等等,神经网络都会认为是完全不同的“8”。如果训练数据没有类似的位置和大小,就无法准确识别。
因此,我们在神经网络之前,加了一个重要环节:特征提取。这就是卷积的重要功能之一:它将一个小过滤器(“神经元”或“卷积核”),比如图案“8”,一步步地平移扫描整个图像。无论“8”的位置是在左上角,还是右上角,它都能找出来。卷积的结果就是“特征”, 一个数字组成的数组。
然后,再将特征数组,送到神经网络里,让神经网络对这个数组进行判断,而不是对图像本身判断,结果就好得多。
卷积神经网络
卷积是两个函数和的计算:将翻转平移,和相乘后,做积分。得到。
两个方形脉冲 f 和 g 的卷积。g 先对 τ = 0 反转,接着平移"t",成为 g(t-τ)。重叠部分的面积 (黑色实线),即为"t"处的卷积。横坐标为 τ及 f*g 的自变量"t"。
方形脉冲和指数衰退脉冲的卷积。重叠部分面积 (黑色实线)即为处的卷积。
对于离散的矩阵 A 和 B,卷积也是一样的:先将矩阵 B 翻转,再平移, 每个元素和矩阵 A 相应的位置的元素相乘后的总和,即得出该位置的卷积。
5x5 的绿色矩阵 A 和 3x3 的矩阵 B 卷积,得出粉红色矩阵 C。矩阵 B 每滑动一步,和矩阵 A 的 [点积][14] 就是该位置的卷积值。
如前所述,如果矩阵 A 是输入的图像。矩阵 B 是过滤器。通过卷积运算,能将各种图案特征分析出来,比如弧线、边缘、色块等等,得到一个较小的矩阵,叫做激活地图(activation map)。 举一个过滤器为例:
比如,要分析出一段长弧线,(本图来自 A beginner's guide to understanding convolutional Neural Networks 一文)
用第一个矩阵是原图像,第二个矩阵为过滤器(或卷积核),两者卷积结果——激活地图上在弧线位置的值较大:6600,而在其他没有这样大弧线的位置,卷积值较小。(本图来自 A beginner's guide to understanding convolutional Neural Networks 一文)
实际用于图像分析的卷积是三维的,请见下图。比如,彩色图像包括 RGB 三种色彩,因此,输入除了长、宽两个维度之外,还有厚度(“3”)。因此要检测某种图案特征,卷积核或过滤器实际上是三维的,如图中的粉红色方块。
这仅仅是一种图像特征的过滤器,而更多的特征还需要更多的过滤器。最终的激活地图是将多个过滤器的卷积结果沿厚度方向“叠”起来,因此用了多少个过滤器,其结果(激活地图)的“厚度”就是多少。
由 RGB 三个颜色通道组成的三层图像(第一个浅蓝方块体),与粉红色的 3 维过滤器(厚度同样为 3)卷积后,得到一个面。用 96 个不同的过滤器卷积,得到 96 层,即厚度为 96。这 96 个过滤器分别检测不同特征。
那么这些过滤器里的值怎么确定,是按经验值或前人的试验来设定的吗? 不是,是机器自己“琢磨”出来的,换句话说,是神经网络训练出来的,过程如下,图片源于 Machine Learning is Fun!:
上图中第二步得到激活地图。通过激活层,比如用 ReLU 作为激活函数,将激活地图上所有负数将变为零,正数将不变。
再通过池化层,将特征地图的空间尺寸逐渐缩小,以便减少网络里的参数和计算量,并控制过拟合。池化层对输入矩阵沿厚度方向的每个切片进行操作,求最大值或平均值来调整其空间大小。
最常见一种池化层是用 2x2 的 Max-Pooling 过滤器。
池化层在空间上缩减样本,在厚度方向保持不变。 左图:通过尺寸为 2、步长为 2 的过滤器,将尺寸 224x224x64 缩减为 112x112x64,而厚度方向尺寸不变。右图:最常用的缩减运算是“最大值”,即求出 2x2 格子(同样颜色)里的最大值,然后右移 2 格(步长为 2)。
第五步:将第四步输出的“特征”输入另一个神经网络,进行分类。该层叫做“全互联层”。
实际的神经网络会由多个卷积层和池化层组成。每个卷积层实际会用 N 个不同过滤器,得到 N 个结果,叠起来形成厚度 N。比如第一层卷积会用 96 个检测不同特征的过滤器,因此厚度为 96. 此例将 224x224x3(RGB 三色)的图像经过两次卷积 + 池化,再经过 3 次卷积,一次池化,和两个全互联层(即 dense layer),得到最终的 1000 种分类。
一个卷积神经网络里,可以由多个卷积层和池化层组成。每层如何决定权重,完全由训练产生,没有人工干预。不过,有人逐层分析已经训练好的神经网络,发现前面的卷积层寻找的是简单的特征,比如边缘或曲线。而后面的卷积层寻找的是人脸、皱纹等更高级的特征。
最后,将后面得到的高级特征,输入另一个全互联神经网络层和 SoftMax 函数,即可获得一组输出值:比如每种分类标签的概率。后面的肺癌 CT 识别的案例里,正是借用了 ImageNet 用来进行图像分类的 ResNet-157 模型,将全互联层的输入,转接到 LightGBM。利用已训练好的 ResNet-157 计算 CT 图像的特征值, 并用这些特征值和标签训练 LightGBM 的神经网络,并实现对肺癌 CT 的识别。
训练神经网络
前面提到,所有过滤器的值都是通过训练获得,哪些是肺癌的特征?是机器自己“琢磨”出来的,那么,到底是怎么算出来的呢? 答案是,通过用一组已知的图片和各自对应的标签(Label) 来训练神经网络。 训练过程将逐渐调整各个过滤器的每个值(或权重),也称之为反向传播(Back propogation)。反向传播包括四个计算步骤:前向传导(forward pass)、损失函数 (loss function)、后向传导 (backward pass) 和权重更新(weight update)。
先将所有过滤器和权重设为任意数。前向传导是将样本图像输入神经网络,按上面提到的办法计算得到输出。因为在训练阶段知道正确的样本图像分类结果,所以可以算出计算结果和正确结果之间的差距, 记为“L”,比如用均方差 MSE 作为 L,这就是一种损失函数。可以想象,第一次用任意数初始化,得到的 L 会很大,要逐渐减小 L,需要先找到不同权重"W"对 L 的影响,即求 dL/dW。结果越大,代表影响越大,调整也应该越大;结果为零,则代表该权重对 L 没影响,无需调整。后向传导就是求 dL/dW。之后,再将第一轮的权重更新成新的权重:
其中,η是学习速度(learning rate),w 是新的权重,wi 是前一轮的权重。η由用户自己选择,值越高,则每次变化越大,有可能更快地得到最优结果,但如果过大,也可能得不到最佳结果。整个反向传播的过程,包括上述四个部分,称作一个“循环(epoch)"。为了利用并行计算来缩短时间,并能更顺利地收敛,先将每 n 个训练样本编成一个“小批次”(mini-batch),对每个小批次反复 epoch 循环中的 4 个步骤,并更新权重,直到最后的 m 次循环的得分不再提升时结束。下面肺癌的例子中,对 lightGBM 回归树训练的“early_stop_ping_round=300”,即 m=300。
注意,每次更新权重时,dL/dW = {同一个小批里 n 个训练样本的 dL/dW 的平均值}。有时候用完样本数据后,得分可能还是不收敛,就要将样本数据重新排序(shuffle),取另一套测试数据,继续训练。
防止过拟合
如何避免过拟合是机器学习里非常重要的考虑因素。如果权重和偏置量(Bias) 过于“贴近”训练数据,很可能造成模型对新数据不够适应,实际运用时产生很糟糕的效果。更确切地说,如果训练所用的数据少,又追求尽可能拟合绝大多数数据,那么很可能拟合了训练数据里的“噪音”或异常值,弄得模型敏感而复杂,因此,最糟糕的训练是仅用一套数据训练所有节点。后面提到的 Early_stop_ping_round,L1 和 L2,交叉验证,及剔除(Dropout)都是避免过拟合的措施。
剔除(Dropout)
剔除能够在训练阶段快速检验是否过拟合。如果模型没有问题,那么将神经网络里的部分节点去掉,也应该产生正确的结果。
神经网络的剔除 左图:带有两个隐藏层的神经网络; 右图:经过剔除的一个子网络。叉代表被剔除的隐藏和输入节点; 图片源于 Dropout: A Simple Way to Prevent Neural Network from Overfitting。
采用剔除时,每个子网络的每个输入节点和隐藏节点是否出现,由概率 p 随机决定连接。被剔除的节点权重也剔除掉,如上图的右图 (b) 所示。一般来说,将保留大部分输入节点和部分隐藏节点(比如 50%)。
举一篇关于剔除的经典论文 Dropout: A Simple Way to Prevent Neural Network from Overfitting 里所采用的的剔除为例:未使用剔除时,训练过程的每个小批次(mini-batch) 里的 n 个图像样本所训练的都是同样的一个网络,如上图 (a)。而采用剔除时,每个训练样本都对应一个不同的经随机剔除的子网络,如上图(b)。因此,每个小批次中的 n 个图像样本,将分别对应 n 个子网络,而每次 epoch 循环更新权重 w 时,用的是 n 个的平均值。
验证时,不再剔除,而是用完整的网络,每个权重等于训练结果中的权重与相应概率的乘积,即(p* 训练权重 w),如下图。
从训练到最终的网络 左图:在训练阶段,每个输入和隐藏节点存在的概率为 p,和下层网络的连接权重为 w; 右图:在验证阶段,每个节点都保留,权重是 p 和 w 的乘积,模型的输出是训练阶段所有输出的期望值; 图片源于 Dropout: A Simple Way to Prevent Neural Network from Overfitting。
交叉验证
如何保证模型在新的数据下,仍有较好表现?一般会将所有样本数据的一部分预留起来,用剩下的训练模型。等训练结束后,再用预留的数据验证,看真实效果如何。这是避免过拟合的重要措施。
但,这样做,使得用于训练模型的数据少了,且选择哪部分数据用于训练,哪部分用于验证,也可能影响效果。交叉验证是个解决方案。比如以 K 折交叉(K-fold cross validation) 验证为例:将样本数据分成 K 份,先选一份(A)作为验证数据,预留起来。用剩下的 K-1 份训练网络,再用预留的那份(A)做验证。
然后,再另选一份作为验证数据(B),同样重复上述步骤,用剩下的 K-1 份训练,并用 B 做验证。以此类推,K 次之后,所有的数据都做过验证数据。最终的验证得分是 K 次验证得分的平均。
用 scikit-learn 的 train_test_split 函数可以很容易地按某个百分比,将数据拆分成训练和验证的两部分。用 cross_val_score(clf,x_data,y_label,cv=num_K_fold) 可以很容易地用设置好的分类器 clf,进行折数为 num_K_fold 的 K 折交叉验证。
肺癌 CT 影像识别
微软的 Miguel Fierro, Ye Xing, Tao Wu 等人在 2017 年 1 月 Kaggle 上的“数据科学肺癌检测竞赛”里,在60 分钟内,利用已训练好的卷积神经网络 ResNet-157 提取 CT 图像的特征,并训练提升树(boosted tree),以识别肺癌 CT 影像是癌症阴性或阳性。他们获得了不错的成绩——1 月 19 日之前排名位前 10%,2 月 7 日之前,居前 20%。
所用到的工具包括:
-
特征提取:已训练好的卷积神经网络——一个用 CNTK 开发的 152 层 ResNet 模型,用 ImageNet 的图像数据集进行的训练;
-
图像分类:LightGBM 灰度提升框架;
-
带 GPU 加速的 Azure 虚机;
具体代码请见 Jupyter notebook 里的笔记。用 CNTK 和 ResNet-157 计算特征用了 53 分钟(如果用更简单的 18 层 ResNet 模型,需 29 分钟),训练 LightGBM 用了 6 分钟。代码请见 Kaggle。
训练速度对获奖来说非常重要。CNTK 和 LightGBM,加上 Azure 的高性能 GPU 虚机,为他们按需提供高性能计算环境,效果很好。下面,我们具体看看他们怎么做的。
用 ResNet 模型、CNTK 和 LightGBM 实施图像识别
深度学习的一种较新的办法是用已训练好的卷积神经网络作为基础,利用已经训练好的模型、权重来加快速度。这也是该团队所采用的方法。他们用 ImageNet 已训练好的卷积神经网络 ResNet-152 作为基础,来提取图像特征,然后将特征输入 LightGBM 灰度提升树框架(包括了 GBDT,GBRT,GBM,MART 等),来进行训练和分类。
该模型的前面几层会提取基本的特征,比如色块、弧线等。后面的层会识别更高层次的特征,比如结节等,更后面的层再进一步识别更复杂的特征,比如和恶性结节等肺癌特征更加贴近的特征。
让我们先看看 ImageNet 如何用卷积神经网络进行图像分类,见上图。输入是 224x224 的彩色图像,每个图像包括 RGB 三个色彩分量,记为 224x224x3。每个卷积层进行卷积计算,用多个厚度为 3 的过滤器,提取各种图像特征,因此,每层的输出的厚度随着过滤器的数量增加而变厚。
最后,由池化 +SoftMax 函数组成的分类器将输出一组由 1000 种概率组成的向量(最后的一组黑色小圈),对应于 ImageNet 的 1000 种不同图像分类。该概率向量中,哪个分类的概率最高,就是识别结果。比如上图中用猫照片输入 ResNet,经过每层卷积计算后,图片大小变小,厚度增加,直到最后的判断结果,即图中第二个小黑点的概率值最高,即识别结果:“虎斑猫”。
用已训练好的 ImageNet 的 ResNet-152 模型输出特征,输入到 LightGBM 中进行分类。
为了借用 ImageNet 的特征提取,来实现肺癌图像分类,先将由池化 +SoftMax 函数组成的分类器去掉,而将图中的"penultimate layer"的节点的输出作为 LightGBM 分类器的输入。 同时,每个患者的 CT 套图是黑白的,所以要先像 ImageNet 的 RBG 样本那样,裁切到 224x224 大小,三张一组。分成 K 批输入前面提到的已训练的神经网络,计算到“pentimate layer”为止。该过程用 CNTK 执行。将输出结果输入灰度提升树,用 LightGBM 分类。
LightGBM 是微软 DMTK 框架的一部分,将灰度提升树用于分布式集群上,以达到更快的速度,而且随着节点数增加,可以成比例地提高计算性能。据好事者测,比 XGBoost 快 10 倍,内存使用稍微少些。作为微软 AI 的两大利器,DMTK(Distributed Machine Learning Toolkit)主要优势是分布式,而非深度学习。CNTK 的优势在于深度学习,所以这两种常常一起用。
ResNet
为什么要用 ImageNet 的 ResNet-152 模型? ResNet 是微软亚洲研究院 Kaiming He 等人提出的。传统神经网络层数较多时,优化比较困难,因此拟合不够。而且如果仅仅增加层数,得到的训练误差和实验误差可能更高。而 ResNet 收敛更快,更容易训练,层数也可以更多,误差更低。比如,在 2015 年 ResNet 一战成名的 ILSVRC 比赛中,它囊括 ImageNet 和 COCO 的图像分类、物体检测等五项比赛冠军。2014 年冠军用的是 GoogleNet 的 22 层网络,而 2015 年的冠军 ResNet 有 152 层,将图像分类的误差从 6.7% 缩减到 3.57%,而物体检测 mAP 指标从 2014 年 16 层 VGG 的 66%,提升到 101 层 ResNet 的 86%。下图是 2016 年 10 月 25 日为止,由 Eugenio Culurciello 发表的,对 AlexNet, VGG 和 ResNet 的比较。
步骤