小批随机梯度下降
① 取一批样本数据
② 通过网络进行前向传播,得到损失函数
③ 方向传播计算梯度
④ 使用梯度更新参数
概览本章内容:
① 初始化设置
激活函数、数据预处理、权重初始哈、正则化、梯度检查
② 动态训练
监控学习率、参数更新、超参数优化
③ 评估
整体模型评估
① 激活函数(使用relu)
② 数据预处理(对数据的每个特征都进行零中心化,然后将其数值范围都归一化到[-1, 1]范围之内)
③ 权重初始化(使用标准差为 2/n−−−√ 2 / n 的高斯分布来初始化权重,其中 n n 是输入的神经元数)
④ 批处理(用)
⑤ 监控学习过程
⑥ 超参数优化(随机样本参数,)
(1)Sigmoid:σ(x)=11+e−x σ ( x ) = 1 1 + e − x
(2)tanh: tanh(x) t a n h ( x ) 其中, tanh(x)=2σ(2x)−1 t a n h ( x ) = 2 σ ( 2 x ) − 1
(3)relu: max(0,x) m a x ( 0 , x )
(4)Leaky relu: max(0.1x,x) m a x ( 0.1 x , x ) 为解决relu死亡问题的尝试
(5)maxout: max(wT1x+b1,wT2x+b2) m a x ( w 1 T x + b 1 , w 2 T x + b 2 )
(6)elu: {xα(ex−1)x⩾0x<0 { x x ⩾ 0 α ( e x − 1 ) x < 0
实践:
(1)首选RELU,关注学习率的变化;
(2)尝试Leaky relu/maxout/elu;
(3)尝试tanh,但是不要有太多期望;
(4)不要使用sigmoid函数
均值减法:是预处理常用的形式。对数据中每个独立特征减去平均值,从几何上可以理解为,每个维度上都将数据云的中心迁置原点。
归一化:将所有的数据都归一化,使其数值范围都近似相等。实现归一化的两种常用方法:①先对数据做零中心化,然后每个维度都除以其标准差;②对每个维度做归一化,使得每个维度的最大和最小值是1和-1。(这个操作只有在确信不同的输入特征有不同的数值范围时才有意义)
PCA:先对数据做零中心化处理,然后计算协方差矩阵,它展示了数据中的相关性结构。
协方差矩阵的对角线上是方差,协方差矩阵是对称和半正定的。
通常使用PCA降维过的数据训练线性分类器和神经网络会达到非常好的性能结果,同时还节省时间和存储器空间。
白化:白化操作的输入时特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化。该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将会是一个均值为零,且协方差相等的矩阵。
记住:任何预处理策略(比如数据均值)都只能在训练集上进行计算,算法训练完毕后,在应用到验证集或者测试集上。
当权重用0初始化会发生什么?
全0初始化时一个错误的开始。如果网络中的每个神经元都计算出同样的输出,然后他们就会在反向传播中计算出同样的梯度,从而进行同样的参数更新。换句话说,如果权重被初始化为同样的值,神经元之间就失去了不对称性的源头。
解决:小的随机数初始化,0均值和0.01的标准差的高斯分布
权重初始值要非常接近0又不能等于0,
这种方式对小的网络是可行的,但是对于深层网络会发生问题。
稀疏初始化:所有权重矩阵初始化为0,但每个神经元都同下一层固定数目的神经元随机连接。
偏置初始化:通常将偏置初始化为0,这是因为随机小数值权重矩阵已经打破了对称性。
初始化值太小,激活函数为0,梯度为0,不更新
初始化值太大,对于tanh,激活函数饱和,梯度为0,不学习
初始化刚刚好,所有层的激活函数很好地运行,学习过程非常好
1、为每个维度独立计算均值和方差;
2、标准化;
批处理通常放在全连接或者卷积层之后,在非线性函数之前。
1、使梯度升高,流向整个网络;
2、允许有更高的学习率;
3、在初始化时,减少依赖性;
4、充当正则化的形式,可能轻微的减少了dropout的需要
注;
在测试阶段,批处理层的函数功能完全不同;
均值和标准差不是基于批计算的,相反,在训练过程中使用单个固定的经验平均值;
标准化之前,分类损失对权重矩阵的改变非常敏感,很难优化。
标准化之后,权重矩阵的微小的改变对损失值不会产生很大的影响,实现优化非常容易
一 数据预处理
二 选择网络结构
训练:以小的正则化项系数开始,并找到使损失函数下降的学习率,损失值不下降的话,是因为学习率太低。NAN代表学习率过高。
梯度检查
梯度检查就是把解析梯度很数值计算梯度进行比较。在实践中,使用中心化公式。
在使用有限差值近似计算数值梯度的时候,我们常见的公式是:
交叉验证策略
训练集和验证集精确度差距较大,代表过拟合,增加正则化项
训练集和验证集精确度差不多,增加模型容量
① 优化(Momentum,RMSProp,Adam等)
② 正则化(使用L2正则化和dropout的倒置版本)
③ 转移学习(项目中使用)
我们的梯度来自于小批处理,所以可以有一些噪声。
SGD+Momentum
AdaGrad: 根据每个维度的历史平方和添加元素的梯度缩放
AdaGrad的一个缺点就是,在深度学习中单调的学习率被证明通常过于激进且过早停止学习
RMSProp
Adam(使用最多)
实践中,Adam在大多数案例中是一个不错的恶魔人选择,
模型集成:① 训练多个独立地模型;②测试阶段,平均化他们的结果,
可以提高额外2%的性能。
不要独立地训练模型,在训练过程中,我们使用单个模型的简单样式。
正则化可以提高单个模型的性能。
正则化:在损失函数中,额外增加一项
Dropout正则化方法,在每个前向过程中,随机把一些神经元的权重置为0,通常把这个超参数设置为0.5
正则化,增加数据
在训练集中的所有像素应用PCA,
沿着原来的颜色方向,设置一个颜色偏移,
对训练图像的所有像素增加颜色偏移,
每层正则化:对于不同层进行不同的正则化很少见(除了输出层以外)
如果你想要训练或者使用CNN,你将会使用许多数据。
少数据,相似数据集 -> 在最高层使用线性分类器
少数据,不同数据集 -> 这种情况不好处理,尝试在不同阶段使用线性分类器
多数据,相似数据集 -> 调整一些层
多数据,不同数据集 -> 调整层中的大部分数据
模型集成的几种方法:
(1)同一个模型,不同的初始化。使用交叉验证来得到最好的参数,然后用最好的参数来训练不同初始化条件的模型。这种方法的风险在于多样性只来自于不同的初始化条件。
(2)在交叉验证集中发现最好的模型。使用交叉验证来得到最好的超参数,然后取其中最好的几个模型来进行集成。这样就提高了集成的多样性,但是风险在于可能包含不够理想的模型。在实际操作中,这样操作起来比较简单,在交叉验证后就不需要额外的训练。
(3)一个模型设置多个记录点。如果训练非常耗时,那就在不同的训练时间对网络留下记录点,然后用他们来进行模型集成。这样做多样性不足,但是在实践中效果还是不错的,这种方法的优势就是代价比较小。
(4)在训练的时候跑参数的平均值。在训练过程中,如果损失值相较于前一次权重出现指数下降时,就在内存中对网络的权重进行一个备份。这样就对前几次循环中的网络状态进行了平均。
模型集成的一个劣势就是在测试数据的时候会花费更多的时间
(1)利用小批量数据对实现进行梯度检查,还要注意各种错误;
(2)进行合理性检查,确认初始损失值是合理的,在小数据集上能得到100%的准确率
(3)在训练时,跟踪损失函数值,训练集合验证集准确率,如果愿意,还可以跟踪更新的参数量相对于总参数量的比例(一般在1e-3左右),然后如果是对于卷积神经网络,可以将第一层的权重可视化
(4)推荐的两个更新方法是SGD+Nesterov动量方法,或者Adam方法
(5)随着训练进行学习率衰减
(6)使用随机搜索来搜索最优的超参数
(7)进行模型集成来获得额外的性能提高
① CPU vs GPU
② 深度学习框架
CPU:更少的核,但每个核要快的多,能力更强,善于序列化执行任务;
GPU:更多的核,但每个核比较慢,善于并行任务;
GPU编程
CUDA(仅仅NVIDIA)
(1)编写类C代码,直接在GPU上运行;
(2)高级API,cuBLAS,cuFFT,cuDNN等;
OPENCL
(1)和CUDA类似,在CPU和GPU上都能运行;
(2)运行速度相对较慢;
CPU的性能往往没有得到好的优化。
cuDNN比没有优化的CUDA快。
若你不够小心,在读取数据并转移到GPU的时候,训练过程会遇到瓶颈。
解决办法,① 把所有的数据读到内存,② 使用固态硬盘不使用机械硬盘,③ 使用多个CPU进程预先取到数据。
要点
(1)容易构建大的计算图;
(2)在计算图中容易计算梯度;
(3)在包裹了cuDNN,CUBLAS的GPU中高效运行;
计算图
使用numpy实现的程序,只能够自己计算梯度,不能够在GPU上加速。但是Tensorflow和PyTorch可以在GPU上运行
建议
(1)对大多数项目来说,Tensorflow是一个安全的选择,虽然它有不完美的地方,但是它的社区非常庞大,得到了广泛的使用,可以和高级的封装一起使用(Keras,Sonnet);
(2)PyTorch用作研究是非常好的,但是他比较新;
(3)在多个机器上使用Tensorflow计算一个图;
(4)发布产品时,考虑Caffe,Caffe2或者Tensorflow;
(5)在移动端使用,考虑Caffe2或者Tensorflow