本文主要是笔者在学习CS231n课程之后结合一些博客文章对相关知识点进行了一个总结,仅仅相当于一个知识框图,如果文中出现任何错误欢迎大家指正。
首先推荐一下CS231n的课程及其中文笔记贺完结!CS231n官方笔记授权翻译总集篇发布,本文大部分内容是参考此笔记进行总结,详细的内容还是请大家参考原文。
不管是简单的线性分类器模型,还是复杂的深度学习网络模型,模型最先的出来的都是一个score矩阵,通过score矩阵带入损失函数才求得当前的损失,损失用来衡量我们对结果的不满意程度,根据损失值再进行反向传播。根据问题的不同有不同的损失函数:
SVM损失函数:其最后的效果是使得模型在正确分类上的得分比不正确的分类上的得分高处一个边界值 Δ \Delta Δ,其损失函数又成为折页损失(Ridge损失),公式如下
L i = ∑ j ̸ = y i m a x ( 0 , f j − f y i + 1 ) \displaystyle L_i=\sum_{j\not=y_i}max(0,f_j-f_{y_i}+1) Li=j̸=yi∑max(0,fj−fyi+1)
Softmax损失函数:其输入值是一个 score向量,输出也是一个向量,其中每个元素在0~1之间,且所有元素和为1。其损失为交叉熵损失,公式如下:
L i = − l o g ( e f y i ∑ j e f j ) \displaystyle Li=-log(\frac{e^{f_{y_i}}}{\sum_je^{f_j}}) Li=−log(∑jefjefyi)
以上两者区别如下:
所谓属性问题就是每个样本不仅仅只有一个标签,而是具有多个属性,解决方法是
所谓回归问题就是直接预测出值的问题,例如长度、数量,而不仅仅是一个定性标签的问题。
当面对一个回归任务,首先考虑是不是必须这样。一般而言,尽量把你的输出变成二分类,然后对它们进行分类,从而变成一个分类问题。
L2正则化:实现:对于网络中的每个权重 w w w,向目标函数中增加一个 1 2 λ w 2 \frac{1}{2}\lambda w^2 21λw2,其中 λ \lambda λ是正则化强度。作用:L2正则化可以直观理解为它对于大数值的权重向量进行严厉惩罚,倾向于更加分散的权重向量。这样就有了一个优良的特性:使网络更倾向于使用所有输入特征,而不是严重依赖输入特征中某些小部分特征。
L1正则化:实现:对于每个 w w w我们都向目标函数增加一个 λ ∣ w ∣ \lambda|w| λ∣w∣。作用:L1正则化会让权重向量在最优化的过程中变得稀疏(即非常接近0)。也就是说,使用L1正则化的神经元最后使用的是它们最重要的输入数据的稀疏子集。
给每个神经元中权重向量的量级设定上限,并使用投影梯度下降来确保这一约束。在实践中,与之对应的是参数更新方式不变,然后要求神经元中的权重向量 w → \overrightarrow{w} w必须满足 ∣ ∣ w → ∣ ∣ 2 < c ||\overrightarrow{w}||_2<c ∣∣w∣∣2<c
在训练的时候,随机失活的实现方法是让神经元以超参数p的概率被激活或者被设置为0,在predict函数中不进行随机失活,但是对于两个隐层的输出都要乘以p,调整其数值范围。因为我们想要神经元的输出与训练时的预期输出是一致的。
这里突然自己想补充一点,在深度学习中,一般是采用一阶的梯度下降法直接进行梯度下降,而在视觉SLAM里的非线性优化中通常采用高斯牛顿或列文博格的方法,都不采用二阶的牛顿法的原因是Hessen矩阵计算量过大。
x += - learning_rate * dx
v = mu * v - learning_rate * dx # 与速度融合
x += v # 与位置融合
v_prev = v # 存储备份
v = mu * v - learning_rate * dx # 速度更新保持不变
x += -mu * v_prev + (1 + mu) * v # 位置更新变了形式
动量更新和Nestrerov动量更新的区别:既然我们知道动量将会把我们带到绿色箭头指向的点,我们就不要在原点(红色点)那里计算梯度了。使用Nesterov动量,我们就在这个“向前看”的地方计算梯度。
如果学习率很高,系统的动能就过大,参数向量就会无规律地跳动,不能够稳定到损失函数更深更窄的部分去,因此需要进行学习率退火:
然后还有一部分方式是逐参数适应学习率的方法,就学习率会和梯度变化的大小有关:
cache += dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)
cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)
m = beta1*m + (1-beta1)*dx
v = beta2*v + (1-beta2)*(dx**2)
x += - learning_rate * m / (np.sqrt(v) + eps)
偏置通常初始化为0
即比较解析梯度和数值梯度的误差,数值梯度速度蛮,但是结果稳定;解析梯度速度快,结果精确但是不稳定,我们通常用解析梯度作为梯度下降的输入,而数值梯度对其进行梯度检查,有一下几点注意
损失函数,即它在前向传播时对每个独立的批数据进行计
x轴通常都是表示周期(epochs)单位,该单位衡量了在训练中每个样本数据都被观察过次数的期望(一个周期意味着每个样本数据都被观察过了一次)。相较于迭代次数(iterations),一般更倾向跟踪周期,这是因为迭代次数与数据的批尺寸(batchsize)有关,而批尺寸的设置又可以是任意的。损失值的震荡程度和批尺寸(batch size)有关,当批尺寸为1,震荡会相对较大。
训练集和验证集的准确率,在训练集准确率和验证集准确率中间的空隙指明了模型过拟合的程度。
权重更新比例,即权重中更新值的数量和全部值的数量之间的比例,一个经验性的结论是这个比例应该在1e-3左右。如果更低,说明学习率可能太小,如果更高,说明学习率可能太高。
即每个神经元与输入数据的一个局部区域连接,该连接的空间大小叫做神经元的感受野(receptive field),一共有三个超参数:深度(depth),步长(stride)和零填充(zero-padding)。输出数据体在空间上的尺寸可以通过输入数据体尺寸( W W W),卷积层中神经元的感受野尺寸( F F F),步长( S S S)和零填充的数量( P P P)的函数来计算 S i z e = ( W − F + 2 P ) / S + 1 Size = (W-F+2P)/S+1 Size=(W−F+2P)/S+1同一个深度上的卷积核是权重共享的,在反向传播的时候,都要计算每个神经元对它的权重的梯度,但是需要把同一个深度上的所有神经元对权重的梯度累加,这样就得到了对共享权重的梯度。而输入图片是中心结构时,需要放松参数共享的限制,将层称为局部连接层(Locally-Connected Layer)
作用是逐渐降低数据体的空间尺寸,其输入数据体尺寸( W W W),超参数为尺寸( F F F),步长( S S S),则 S i z e = ( W − F ) / S + 1 Size = (W-F)/S+1 Size=(W−F)/S+1反向传播可以简单理解为将梯度只沿最大的数回传。因此,在向前传播经过汇聚层的时候,通常会把池中最大元素的索引记录下来
解决Internal Covariate Shift问题(由于输入分布的不断变化,导致上层网络需要不断调整去适应,导致网络学习速率低,容易陷入梯度饱和区域,减缓网络收敛速度),可以通过PCA和白化解决,但是计算成本太高公式如下: Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] Z^{[l]}=W^{[l]}A^{[l-1]}+b^{[l]} Z[l]=W[l]A[l−1]+b[l] μ = 1 m ∑ i = 1 m Z [ l ] ( i ) \mu=\frac{1}{m}\sum_{i=1}^mZ^{[l](i)} μ=m1i=1∑mZ[l](i) σ 2 = 1 m ∑ i = 1 m ( Z [ l ] ( i ) − μ ) 2 \sigma^2=\frac{1}{m}\sum_{i=1}^m(Z^{[l](i)}-\mu)^2 σ2=m1i=1∑m(Z[l](i)−μ)2 Z ~ [ l ] = γ ⋅ Z [ l ] − μ σ 2 + ϵ + β \tilde{Z}^{[l]}=\gamma\cdot\frac{Z^{[l]}-\mu}{\sqrt{\sigma^2+\epsilon}}+\beta Z~[l]=γ⋅σ2+ϵZ[l]−μ+β A [ l ] = g [ l ] ( Z ~ [ l ] ) A^{[l]}=g^{[l]}(\tilde{Z}^{[l]}) A[l]=g[l](Z~[l])参数 γ , β \gamma,\beta γ,β的引入是为了恢复数据本身的表达能力,对规范化后的数据进行线性变换,需要学习。其效果是(1)BN使得网络中每层输入数据的分布相对稳定,加速模型学习速度;(2)BN使得模型对网络中的参数不那么敏感,简化调参过程,使得网络学习更加稳定;(3)BN允许网络使用饱和性激活函数(例如sigmoid,tanh等),缓解梯度消失问题;(4)BN具有一定的正则化效果
起到推理器和分类器的效果,可以将全连接层转化为卷积层
一对一的结构通常没什么用,一对多可以用来输入一个图片,输出一句描述图片的话,多对一可以输入一句话,判断是正面还是负面情绪,**多对多(延时)**可以用来机器翻译,多对多输入一个视频,判断每帧分类
如上图所示,其前向传播公式为: h t = f W ( h t − 1 , x t ) h_t=f_W(h_{t-1},x_t) ht=fW(ht−1,xt)
这里值得注意的是,每一步用的都是同一个函数以及同样的参数,上式展开得: h t = t a n h ( W h h h t − 1 + W x h x t + b ) h_t=tanh(W_{hh}h_{t-1}+W_{xh}x_t+b) ht=tanh(Whhht−1+Wxhxt+b) y t = S o f t m a x ( W o h h t + c ) y_t = Softmax(W_{oh}h_t+c) yt=Softmax(Wohht+c)相较于普通的神经网络其实就是多加上了 h t − 1 h_{t-1} ht−1
其损失函数为 L t ( y t , y t ^ ) = − y t l o g ( y t ^ ) L_t(y_t,\hat{y_t})=-y_tlog(\hat{y_t}) Lt(yt,yt^)=−ytlog(yt^) L ( y t , y t ^ ) = − ∑ t y t l o g ( y t ^ ) L(y_t,\hat{y_t}) = -\sum_{t}^{}y_tlog(\hat{y_t}) L(yt,yt^)=−t∑ytlog(yt^)其反向求导公式需要求损失函数 L t ( y t , y t ^ ) L_t(y_t,\hat{y_t}) Lt(yt,yt^)对 W h h , W x h , W o h W_{hh},W_{xh},W_{oh} Whh,Wxh,Woh的倒数,然后按照梯度下降法进行下降,推导过程可以参考循环神经网络RNN 梯度推导(BPTT)
RNN 前后依赖的特性导致两个输入距离比较远的时候作用会非常弱,同时会有梯度消失或梯度爆炸的问题,一个解决方案就是设计 Gate,保存重要记忆,这就是LSTM所谓 Gate 的结构就是一个使用 Sigmoid 神经网络和一个 Elementwise Multiplication 的操作,这两个操作合在一起就是一个门的结构,Sigmoid 作为激活函数的全连接神经网络层会输出一个 0-1 之间的数值,描述当前输入有多少信息量可以通过这个结构,类似于门,门打开时(Sigmoid 输出为1时),全部信息都可以通过;当门关上时(Sigmoid 输出为0),任何信息都无法通过。
其步骤如下(参考递归神经网络 RNN 笔记)
(1)新输入 x t x_t xt 和前状态 h t − 1 h_{t−1} ht−1 通过 Sigmoid 变换决定 c t − 1 c_{t−1} ct−1 的哪些信息可以舍弃, f t f_t ft 与 C t − 1 C_{t−1} Ct−1 做 Elementwise Multiplication 运算,对部分信息进行去除
(2)新输入 x t x_t xt 前状态 h t − 1 h_{t−1} ht−1 通过 Sigmoid 变换告诉 c t c_t ct 哪些新信息想要保存,通过 t a n h tanh tanh 变换建一个新的侯选值向量。 i t i_t it: 新信息添加时的系数(对比 f t f_t ft), g t g_t gt 单独新数据形成的控制参数,用于对 c t c_t ct 进行更新。
(3)根据旧的控制参数 c t − 1 , f t , i t , g t c_{t−1},f_t,i_t,g_t ct−1,ft,it,gt 组合生成最终生成该时刻最终控制参数
(4)新输入 x t x_t xt 和前状态 h t − 1 h_{t−1} ht−1 通过 Sigmoid 变换决定 Cell State 的哪些信息需要输出,与 Cell State 通过 t a n h tanh tanh 变换后的值相乘,产生此刻的新的 LSTM 输出
整个过程: C t C_t Ct 信息舍弃 => C t C_t Ct 局部生成 => C t C_t Ct 更新 => C t C_t Ct 运算
进化史:AlexNet(8) -> VGG(19) -> GoogleNet(22) -> ResNet(152) -> ResNext
AlexNet一共8层,它首次提出(1)ReLU非线性激活;(2)Max Pooling池化;(3)Dropout
VGG一共19层,它的贡献主要是(1)将一个大卷积核分解成连续多个小卷积核(7×7核可以分成3个3×3核),从而减少参数、降低计算、增加深度,下图是他的结构图,非常简洁明了
GoogLeNet一共有四个版本,其特点是Inception Architecture,提供多尺度特征,输出通道多尺度化,如下
Inception V1主要贡献是:(1)Split-Merge(指上图结构)增加网络对多尺度的适应性,增加网络宽度;(2)Bottleneck Layer,即使用1×1的卷积进行降维,大幅度降低计算量(3)取消全连接;(4)辅助分类器,用来解决梯度消失问题
Inception V2主要贡献是:(1)使用Batch Normalization解决Internal Covariate Shift问题,取消部分dropout
Inception V3主要贡献是:(1)使用非对称卷积;(2)采用特殊的池化高效的讲尺寸;(3)取消浅层辅助分类器
ResNet全是3×3的卷积核,通过如下残差结构解决梯度消失问题,可以多达152层,取消了池化、全连接层、Dropout,然后通过卷积步长取代池化
进化史:(第一阶段)R-CNN -> SPP-Net -> Fast R-CNN -> Faster R-CNN(第二阶段)YOLO -> SSD -> R-FCN
传统方法“Region Proposals + 手工特征 + 分类器”,R-CNN方法为“Selectiv Search + CNN特征 + SVM”,如下图
其步骤如下:
(1)通过Selective Search算法提取2000个Region Proposals(和类别无关但是包含物体的区域),Seletive Search算法相较于滑窗穷举法计算量要小,大概思路就是通过特征先提取小尺度区域,然后一次次合并得到大的尺寸
(2)对特征进行CNN的特征提取
(3)对CNN特征进行SVM的二分类
R-CNN慢是因为Selectiv Search之后进行卷积特征提取,重复计算量太大。SPP-Net所做的改进主要是(1)直接输入整图,所有区域共享卷积计算(2)引入空间金字塔池化,为不同尺寸的区域,在Conv5上输出提取特征映射到尺寸固定的全连接层上
R-CNN的pipeline是:Image -> Selective Search -> Warp -> Convlution Layer -> Fully Connected layer -> output;
SPP-Net的pipeline是:Image -> Convlution Layer -> Spatial Pyramid Pooling -> Fully Connected layer -> output;
在SPP-Net的基础上又引入了两个新技术
(1)感兴趣区域池化层,有效避免了物体的形变扭曲,保证了特征信息的真实性,同时不需要对每个proposal都提取特征,采用映射方式从整张图片的Feature Map上获取ROI Feature区域;
(ROI Pooling时,将输入的 h × w h × w h×w大小的Feature Map分割成 H × W H × W H×W大小的子窗口(每个子窗口的大小约为 h / H , w / W h/H,w/W h/H,w/W,其中 H 、 W H、W H、W为超参数,如设定为7 x 7),对每个子窗口进行Max-Pooling操作,得到固定输出大小的Feature Map。而后进行后续的全连接层操作)
(2)多任务损失函数。
Fast R-CNN可以端到端的单阶段训练,所有层的参数都可以Fine Tune。
Faster R-CNN其实就是在Fast RCNN的基础上讲Selectiv Search算法替换成Region ProPosal Network(RPN),进一步共享卷积计算
如上图左所示,首先根据输入图获得Feature Map,然后传入到RPN网络汇总,RPN网络所做的事情,用固定窗口(3×3)对Feature Map进行滑动扫描,每个窗口对应一个256-d的Intermediater Layer,其输出是 2 K 2K 2K个Score和 4 K 4K 4K个Coordinate,其中 K K K就是每个窗口对应Anchor Box的数量, 2 K 2K 2K是因为RPN只判定某个区域里面是否存在感兴趣物体(0,1),它的输出是一个Score大于0.5的Bounding Box(由Coordinate获得),然后,在Feature Map上对Bounding Box里的内容进行Classification,同时由于Bounding Box的坐标不准确,因此会进行Bounding Box Regression,这也就是上图右所示内容
YOLO的作者在生活中应该是个逗逼,但是他的作品是真的强,YOLO有一个隐藏技能就是它的网络是用C实现的(darknet),可以直接嵌入到C++框架中,我之后会写一篇博客讲如何调用YOLO网络
其实现步骤如下:
(1)将图片resize到448×448大小的尺寸,然后讲图片划分为 S × S S×S S×S个Grid(S=7,因此64×64的小图片就是一个Grid)
(2)每个Grid负责生成 B B B个Bounding Box,每个Bounding Box对应4个Coordinate和1个Confidence(表示表示物体对应的Bounding Box和Ground Truth Box的Intersection of Union(IOU)大小)
(3)每个grid还要生成 C C C个Conditional Class Probabilities(表示该Grid内部包含物体时,这个物体属于各个类别上的概率)
(4)因此一张图片输出为 S × S × ( B × 5 + C ) S×S×(B×5+C) S×S×(B×5+C),然后就是找Ground Truth进行训练。
因为其是通过Grid进行划分图片,假如一个Grid对应多个小物体,则只能输出一个小物体,因此YOLO对小物体检测效果不好,YOLOv3通过对网络结构改进,添加了多尺度预测,解决了上述问题,参考目标检测网络之 YOLOv3
参考SSD原理与实现,其主要原理如下图所示:
其基本步骤如下:
(1)类似于Faster R-CNN先从Image通过CNN生成Feature Map,不同的是SSD需要生成不同尺寸的Feature Map
(2)类似于YOLO,采用3×3的窗口在每个FeatureMap上进行扫描,对应生成 B B B个Bounding Box(借鉴了Faster R-CNN中的Anchor Box的原理),每个Bounding Box对应4个Coordinate和 C C C个Class Probability
(3)可以看到对于 M × N M×N M×N的feature map,输出节点数为 M × N × K × ( C + 4 ) M×N×K×(C+4) M×N×K×(C+4),然后就是找Ground Truth进行训练
下图很好的概括了Faster R-CNN、YOLO、SSD的不同原理
R-FCN是在Faster R-CNN的框架上进行了改造,其效果比Faster R-CNN要好,其流程如下:
其两点创造性工作是
(1)把基础的分类网由VGG换成了ResNet
(2)R-FCN使用了基于全图-全卷积-可共享的Postion-Sensitive Score Maps 来处理RPN的映射和ROI的提取,避免Faster R-CNN对每一个Proposal执行ROI Pooling时在FC层进行权重计算消耗的时间
进化史:FCN -> SegNet -> DeepLab
卷积化:是指所有全连接层转化为卷积层,使用任意尺寸的输入,输出低分辨率的图片
反卷积化:是指讲低分辨率的图片进行上采样,输出同分辨率的图片
FCN结构如下:
其步骤其实就是卷积之后反卷积,这里有两点需要注意
(1)反卷积操作:操作的直观理解如下:
上左图就是卷积操作,上右图就是反卷积操作,在代码中卷积和反卷积操作其实就是矩阵相乘
(2)跳跃结构:在结构图中可以看出来,FCN中加入跳跃结构,是因为直接将全卷积后的结果上采样后得到的结果通常是很粗糙的,通过跳跃结构来优化输出
其结构如下:
如图是一个对称网络,由中间绿色Pooling层与红色Upsampling层作为分割,左边是卷积提取高维特征,并通过Pooling使图片变小,右边是反卷积(在这里反卷积与卷积没有区别)与Upsampling,通过反卷积使得图像分类后特征得以重现,最后通过Softmax,输出不同分类的最大值。
这里值得注意的是Upsampling的操作,在Pooling的时候记录最大值的位置,Upsampling将其恢复到最大值的最大值的位置,Upsampling后面的反卷积其实就是卷积操作,下图就展示了SegNet和FCN中Upsampling操作的不同。
其核心工作就是进行空洞卷积+CRF作为后处理
(1)在DCNN中重复最大池化和下采样带来的分辨率下降问题,分辨率的下降会丢失细节。DeepLab是采用的atrous(带孔)算法扩展感受野,获取更多的上下文信息
(2)分类器获取以对象中心的决策是需要空间变换的不变性,这天然的限制了DCNN的定位精度,DeepLab采用完全连接的条件随机场(DenseCRF)提高模型捕获细节的能力
其流程如下:
这里也是先推荐一下博客BAT机器学习面试1000题系列,之后有时间在搜集相关的问题
写了三篇分别关于视觉SLAM、机器学习和深度学习的总结之后,还是有很多问题知其然不知其所以然,还需要之后在工作研究中慢慢学习总结才行,另外概率论、矩阵和最优化的知识在每个领域里都是有用到的,很多知识是互通的,比如视觉SLAM中的BA优化和深度学习里面的梯度下降其实是一个问题,只是根据各自特点采用了不同的数学解法,能在自己脑子里形成一个知识框架感觉还是很好的,最后就是这几篇博客可能更多地是用给自己总结,读者读起来应该很费力,之后慢慢改善吧,继续加油咯!