说明:本文是七月算法5月深度学习班第五次课听课笔记。黄色标注的部分为自己不太确定的部分。
训练
mini-batch SGD
神经网络使用mini-batch SGD训练得到最优权重。训练过程如下:(以下参考了andrew ng的机器学习课程)
例如训练样本量m=3200,mini-batch 每次取32张
for i = 1,33,65,...从i 开始取32个图片样本前向计算得到中间变量a z 和 损失函数值后向计算得到梯度用这部分梯度更新权重
问:为什么使用batch而不使用一张图片呢?答:一张图片样本量不够,容易发生振荡。如果是一张图片,就是随机梯度下降了。
两种去均值方法
第一种:减去图片每个像素的均值。在图片的每个像素位求均值。例如样本图片是[32,32,3],将会得到[32,32,3]数组的平均值。每个样本的不同像素减去对应位置的均值。AlexNet使用该方法。
第二种:减去每个通道(channel)的均值。例如样本图片是[32,32,3],会得到3个平均值,分别表示R、G、B的均值。每个样本不同通道的值减去对应的均值。VGGNet使用该方法。
再次强调:CNN训练不需要做标准化、PCA和白化
权重初始化
SGD参数学习第一步就是权重初始化。权重初始化有多种方法。
al表示每层神经单元值。W1表示从第一层到第二层的权重
方法1 w=0。不可以。所有权重初始化为0,这会发生对称现象。例如a2=g(a1*W1)。所有W1=0,a2所有神经单元的值就都相同了。而神经网络的不同神经元是用来学习不同的知识点。这样就引起了对称性。不能好好工作了。
方法2 w=0.01*np.random.rand(D,H). 初始化权重为一些小的随机数。在python实现中,实现了权重正负数各一半。效果:该方法在包含1-2个隐藏层的网络中是有效的。网络层数加深,带来整个网络激活传递的不对称性(会引起数据在很小或者特别大的范围内变动,也就是说方差趋于0,或者无穷)。
实现:使用10层网络(500)神经元,观察 每一层 神经单元的 平均值 和方差。可以看到从第三层开始均值与方差几乎不发生变化,接近0。
方法3 w=np.random.rand(fan_in,fan_out). 说明:fan_in = 这一层输入元素的个数,fan_out=这一层输出元素的个数。效果:会出现梯度为0的情况,类似sigmoid函数出现的情况。
方法4 w=np.random.rand(fan_in,fan_out)/np.sqr(fan_in) 效果:效果还不错可以使用。但是在使用ReLU激活函数的时候,同样带来整个网络激活传递的不对称性。方法5 w=np.random.rand(fan_in,fan_out)/np.sqr(fan_in/2)这是一篇在2015年的论文中提到的方法。可以解决ReLU时发生的问题。
Batch Normalization
对于权重可能引起网络激活的不对称性问题,谷歌提出了一种解决方法Batch Normalization。思想是期望激励过后的神经元的值仍然能够保持高斯分布。
问:为什么是高斯分布呢?
答:高斯分布简单,方差可控。而且还满足了同一层神经元要有一定的差异性。
问题:BN放在什么问题?
Batch Normalization通常接在全连接之后,激励层之前。全连接层是产生波动最大可能性的地方,也是学习能力最强的地方。
问题:BN的具体操作
求均值;求方差;xi=(xi-均值)/np.sqr(方差+e);最后一步做伸缩和平移且输出:yi=gama * xi+beta 。gama和beta是训练过程中可以获得的。之所以有最后一步,是因为BN过程中对原始数据做了修改,表达的信息会有部分丢失。通过伸缩平移尽量将信息还原。
BN的优点是:学习率设置高一点也可以;对初始化数据依赖少了。
开始训练
首先先用小数据集训练(10个分类,每个分类下10个样本)测试训练模型是否OK。接着可以改变正则化,从无到有。需要监控的参数 1const function的值是不是振荡下降;2 训练集上的准确率是否能到100%。几个现象:准确率低(0.6),cost function值不变=>有问题,学习率太大了?训练集准确率>>交叉验证集准确率 =>过拟合,试试调大正则化项?训练集准确率 约等于 交叉验证集准确率 如果都很高,那模型不错,可以使用。如果都很低(0.6),数据问题?模型问题?样本倾斜了?
Dropout ---神经网络正则化
L2 正则化 l = ... + lamda*(权重和) 用于神经网络,参数个数多,计算量大。所以不是最好的选择。
Dropout 语言描述:1 别一次打开所有学习单元;别让神经元记住那么多东西;每次关掉一部分感知器,得到新的模型,最后融合。
设置一个概率p=允许通过的概率。在dropout层,会有n*(1-p)个节点关闭,神经单元的值为0。注意:不是权重为0。由于训练的时候有一个概率,在预测的时候同样需要概率。所以工业上一般是在训练过程中,将输入数据x=x*p。预测的时候就不需要再乘以p了。
Caffe使用
主要模块
Blob 存储数据和梯度值
Layer 传递层与层的输入输出
Net 网络,利用前向后向计算梯度
Solver 用梯度更新权重
使用过程
网上有很多资料讲使用过程,这里不详细记录。
1 Resize图片,转存为LMDB/LevelDB格式。注意分类下表从0开始。
2 定义网络结构
3 定义solver,训练参数
4 训练
模型库选择 model zoo
1 如果层次不变,改变输入输出
输入是 data层 data_param 和transform_param 参数段。输出是layer { name: "fc8" ,name 需要修改。
2 如果添加/删除层次,注意顺序。一般把前面层学习率调低,从修改层开始调高学习率。一般fine-tuning的前期loss下降非常快,中间有个瓶颈期,要有耐心。
3 在solver调整学习率(1/10,1/100)。利用snapshot 存储中间结果。如果发生宕机,可以接着继续训练。