深度学习相关经验和笔记
超参数调试
- 可以多做交叉实验
- 超参数的设置需要尝试和经验
- 测试时随机选择一批超参数
- 从粗到细的范围进行选择
- 有的参数(学习率)应该用对数坐标随机取值
- 至少每几个月评估一次超参数设置
- 当资源不够时,可以一直调试一个模型(panda,babysitting one model)
- 当资源足够,可以并行测试多个超参数模型(caviar)
- 超参数的最优值可能会随时间变化
- 一般可以优先考虑学习率、batch_size
- 还可以考虑冲量因子(momentum beta)、学习率衰减、网络结构(节点数、层数)等
- 深度学习是一个迭代的过程 想法->实验->结果->新的想法,需要快速建立第一个简单的系统,然后迭代
激活函数
- 非线性激活函数是必须的(要不然神经网络只是在做线性映射,不能捕捉XY之间的非线性关系)(除非是做线性回归)
- sigmoid做激活函数时很慢(梯度小),一般用在二分类的最后输出节点
- tanh比sigmoid几乎总是效果更好 且其均值是0 有数据中心化的效果
- 在输入很大或者很小的时候 tanh和sigmoid的斜率都很小 梯度下降会比较慢
- Relu/leakyRelu 修正线性单元,一般可以作为默认选择
- 优缺点:
- 解决了梯度消失、爆炸的问题
- 计算方便,计算速度快
- 加速了网络的训练
- 由于负数部分恒为0,会导致一些神经元无法激活(可通过设置小学习率部分解决)
- 输出不是以0为中心的
- sigmoid的导数a(1-a) tanh:1-a^2 relu/leaky relu:easy
- softmax激活函数:适用于多分类的输出层,当类别数目为2时,与sigmoid等价,cost函数可以由binary entropy推广而来
损失函数
- 关于模型参数的用来表达(对于特定的数据)模型效果有多好的函数
- Loss Function 对单个样本的度量
- Cost Function 全体样本的损失函数的均值 对全体的度量
- rmse容易产生局部最小值
- 一般用交叉熵(binary class)
- 可以根据问题特点自定义损失函数
特征选择与降维
- 获得一组特征的主要相关变量
- 优点:
- 剔除冗余特征,减小存储和计算的压力
- 降维到2、3维,便于可视化
- 过多的特征容易导致过拟合
- 降维:PCA、t-SNE
- 特征选择:卡方检测、信息量
- 覆盖度
- 取值方差
- 熵:
- H(X) = 对X的多个取值求和(-plog2p)
- 越混乱越不可预测熵值越大
- 条件熵
- H(X|Y) = 对Y的多个取值求和(p(y)H(X|Y=y))
- 信息增益:
- 信息增益就是熵和特征条件熵的差,描述的是不确定性减少的程度
- entropy(前) - entropy(后)
- g(D, A) = H(D) - H(D|A)
- 缺点:信息增益偏向取值较多的特征,因为当特征的取值较多时,根据此特征划分更容易得到纯度更高的子集,因此划分之后的熵更低,信息增益更高。
- 信息增益比
- gr(D, A) = g(D, A) / Ha(D)
- Ha(D)的作用是作为惩罚项,特征取值多时Ha(D)更小,所以信息增益比会更大,会偏向取值较少的特征
- Ha(D),是对于样本集合D,将当前特征A作为随机变量(分群的依据是特征A的各个特征值,而不是D的label值),求得的经验熵。
- 并不直接选择信息增益率最大的特征,而是现在候选特征中找出信息增益高于平均水平的特征,然后在这些特征中再选择信息增益率最高的特征。
- 基尼指数(基尼不纯度)
- 表示在样本集合中随机选中的样本被分错的概率,集合越纯被分错的概率越小
- 基尼指数 = 样本被选中的概率 * 样本被分错的概率
- Gini(p) = 求和(p(1 - p)) = 1 - 求和(pk^2)
- 二分类时 Gini(p) = 2p(1-p)
- 基于特征A划分样本集合D的基尼指数
- Gini(D, A) = 对A的多个取值求和(piGino(Di))
数据规范化
- 数据规范化是十分重要的预处理步骤,用于重新调整特征的取值范围,能够保证反向传播学习的速度和效果
- 如果没有进行规范化,波动范围更大的特征将在损失函数中获得更大的权重,对于波动较小的特征学习速度会偏慢
- 最大最小归一
- 对数归一
- 分桶归一
- 正态分布数据:零均值化 归一化方差
优化算法
- mini-batch梯度下降:batch_size一般取64~512
- Batch GD(小数据集适用<2000):单次迭代时间太长,可能内存放不下 速度太慢(大样本数据集情况下)
- SGD(batch_size=1,在线训练):失去向量化带来的批次计算的加速效果,可能受样本质量影响比较大,优化过程容易震荡
- momentum:计算参数梯度的移动平均数,依此做梯度下降,增加了超参数beta,可以取0.9
- 指数移动加权平均 ave_n = beta * ave_n-1 + (1 - beta) * value_n,大致相当于前1/(1 - beta)个值的平均值
- 偏差修正:ave_0 = 0, ave_n = ave_n / (1 - beta ^ n) ,一般不会用
- Adagrad: 除以梯度的累计平方和,对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些,总体上可以加快学习速度,减少摆动;缺点在于梯度累计平方和单调递增,梯度更新会越来越慢。
- RMSprop:计算参数梯度的平方移动均值,梯度下降时除以这个均值的平方根,可以减少摆动,加快较小梯度变化的参数更新
- Adam:结合RMSprop和momentum,超参数beta1=0.9, beta2=0.999,可以优先选择adam作为默认优化方法
- 学习率衰减: 减小mini_batch末段不收敛引起的摆动, alpha = 1 / (1 + decay_rate * epoch_num) * alpha0,或者alpha = decay_rate ^ epoch_num * alpha0
几种网络/层的结构
cnn(conv net)
-
用卷积操作来提取(一般是图像中的)特征
-
padding
- 卷积的缺点:1. 图像缩小 2. 边角的信息在卷积过程中利用得少
- 在图像周围填充0 解决上面的问题
- same padding:padding size = (f - 1) / 2 使得图片大小不变(图片尺寸 n filter尺寸 f)
- valid padding:不进行padding
-
深度cnn 图像越来越小 channel越来越多
-
池化(pooling)
- 提取特征,缩小数据量,最大池化比较常用 平均池化用得较少,常用2*2的池化层, 有助于平移不变性
- 缩小图片,在不丢失过多信息的同时减小了计算量
- 有助于高一些的层提取更大粒度的空间特征
-
卷积的优点
- 卷积层参数少的特点:参数共享(在图像中特征提取可以通用)、稀疏连接(图像的某一小部分的性质与其他部分关系不大,不用全连接)
- 卷积层具有很好的平移不变性(即图像平移也会输出高度相似的特征,与滑动窗口卷积和池化有关)
- 一般使用3*3的卷积核,较小的卷积核意味着更少的参数和计算,能够引入更多的过滤器,提升特征提取能力
-
网络中的网络(1*1的卷积层):对于图中的每一个位置,等同于对所有通道做了全连接层,图片大小不变,输入size是通道数,输出是过滤器数量,可以用来压缩通道数
-
inception网络:将各种size的卷积层和池化层堆叠起来,不需要人为指定卷积层大小,网络自动学习
-
对于图像问题,多采用开源的结构和参数权重,进行finetuning,修改上层网络结构,视情况冻结底层特征层
-
图像数据扩增:镜像翻转、随机裁剪、平移、旋转、色彩转换
-
例子:LeNet-5、AlexNet、VGG-16
-
目标检测
- 目标定位:假定图片里最多只有一个待检测物体,输出格式:
- pc:0/1 是否存在物体
- c one-hot 物体类别
- bx by bw bh 0~1 物体boundingbox的位置和大小
-
特征点识别
- 识别物体特征点 例如人脸的眼角、鼻头、嘴角等 人体的手、腰部等
- 输出为n个bx、by,n为不同的特征点的个数
-
滑动窗口目标检测
- 选用不同大小的窗口,在整个图片上滑动,检测是否含有物体
- 滑动窗口时有许多卷积计算可以重用,所以可以将整张图片当做输入,而不是先进行裁剪,再输入到cnn当中(需要将fc层转换为conv层)
-
YOLO算法:you only look once
- 将原始输入分成很多个小网格,对每个网格使用目标定位检测物体(假定最多只有一个物体)
- 将物体分配到bounding box中点所在的网格(bx,by在0~1之间,bw,bh可能大于1)
- 单次卷积实现(计算共享)
- 交并比(intersection over union,IOU):bouding box交集和并集的比
- 非极大值抑制:找出检测中pc最大的矩形,抑制与这个矩形IOU高的矩形,避免同一个物体被多次检测出
- anchor box:每个物体都被分配到中点所在的网格下与其交并比最高的anchor box,能够识别不同物体在同一个网格的情况,anchor box可以手动指定,也可以使用kmeans聚类
-
残差网络
-
残差网络ResNet:增加捷径,有助于训练很深的神经网络
-
有助于缓解梯度消失或者梯度爆炸
RNN
-
几种模型
- XY长度相等的多对多 实体词识别
- XY长度不相等的多对多 翻译
- 多对一 情感倾向
- 一对多 音乐序列生成
-
GRU(Gated Recurrent Unit,门控循环单元)
- 增加记忆细胞c
- 门控单元: 更新门决定记忆细胞是否更新、更新多少(移动加权平均)
- 记忆细胞作为循环的输入输出
-
LSTM
- 门控单元更复杂更强力
- 更新门、遗忘门、输出门
-
双向RNN(BRNN)
- 适用于有完整序列内容,且需要为序列每个位置做预测
- 使用LSTM的BRNN往往是首选
-
Deep RNN
- 下层RNN的序列输出提供给上层RNN
attention
- 序列编码
- RNN 递归式进行,无法并行进行,没有长期记忆
- CNN 窗口式遍历,容易捕捉局部信息,通过层叠增大感受野
- Attention 直接获取全局信息
- 定义
- Attention(Q, K, V) = softmax(QK^t / sqrt(dk))V
- 维度:Q∈Rn×dk,K∈Rm×dk,V∈Rm×dv 最后结果:n×dv
- 将n×dk的序列Q编码成了一个新的n×dv的序列,对于单个query,通过与key内积并softmax的方式得到q与各个key的相似度,然后依据相似度对value进行加权求和,得到query所对应的输出
- 其中sqrt(dk)因子起到调节作用,使内积不会太大,保证softmax后不会非0即1
- Multi-Head Attention
- headi=Attention(QWqi,KWki,VWvi)
- MultiHead(Q,K,V)=Concat(head1,...,headh)
- 把QKV通过参数矩阵进行变换之后再做attention,重复h次之后拼接到一起,多头之间参数不共享
- 类似CNN中的channel(filter数目)
- 一般K=V,当Q=K=V时,就是自注意力机制(Self Attention)
- 单纯的Attention并不能捕捉序列的顺序信息,Google通过位置向量来引入位置信息(sin,cos编码)
- transformer
- Encoder: 由N=6个相同的layers组成, 每一层包含两个sub-layers. 第一个sub-layer 就是多头注意力层(multi-head attention layer)然后是一个简单的全连接层。 其中每个sub-layer都加了residual connection(残差连接)和normalisation(归一化)
- Decoder: 由N=6个相同的Layer组成,但这里的layer和encoder不一样, 这里的layer包含了三个sub-layers, 其中有一个self-attention layer, encoder-decoder attention layer 最后是一个全连接层。前两个sub-layer 都是基于multi-head attention layer。这里有个特别点就是masking, masking 的作用就是防止在训练的时候 使用未来的输出的单词。比如训练时,第一个单词是不能参考第二个单词的生成结果的。Masking就会把这个信息变成0,用来保证预测位置 i 的信息只能基于比 i 小的输出。
BERT、GPT、ERNIE
- 预训练产生词向量
deepFM
CRF(条件随机场)
CRNN
NLP
- 词嵌入:将词嵌入到多维特征空间的单点上
- 与encoding类似
- 比one-hot维度更少
- 学习到词的多维特征,能表达词之间的关系
- 降维方法:t-SNE算法,将多维特征映射到二维空间,方便查看嵌入效果
- 词嵌入可以用大量无标注的文本内容学习,然后迁移到需要标注内容的任务上(也可以下载预训练的词嵌入模型)
- 可以用余弦相似度求向量之间的相似程度
- 词向量学习
- skip gram:对一个词 取其前后N个词中的词作为目标词训练
- CBOW:用周围的词预测中间的词
- seq2seq
- 翻译:rnn对输入编码之后rnn解码输出
- beam search:集束搜索,从很大的树状搜索空间中搜索最优结果,可以看做是每一步选择多个的贪心算法,它比BFS、DFS更快,但不能保证找到最优解
- 文本生成精确度:BLEU score(机器翻译、图片描述,不适用于机器语音转录)
视频检测
- slowfast
- 3d ResNet
一些经验和思考
结构化与非结构化
- 结构化数据(能够很好地用数据库存储的数据,有很好的结构化定义)
- 非结构化数据,文字 图像 语音等等
- 结构化训练数据是一种很重要的能力,这个过程一般是数据预处理、特征提取和选择,能够大幅提升机器学习的效果
- 对于非结构化输出,可以尝试进行结构化
- 比起传统的机器学习方法,深度学习能够更好地处理非结构化数据
- DNN的知识来自于两个方面,一个是带标记的数据集,另一个就是手工工程,当数据量较少时,手工工程就更加重要,包括数据结构化、特征工程、精心设计的网络结构等
关于计算图
- 图的终点是损失函数,需要最小化损失函数
- 前向计算值 反向计算导数(关于网络参数的偏导)
- 推导得出网络参数的更新公式
- 对于监督学习 输入X是固定的 网络参数参数w、b是变化的 通过反向传播求导来计算梯度
- 随机初始化所有参数 将W初始化为很小的随机数 b可以设为0
梯度爆炸、梯度消失
- 较低层(靠近输入的层)参数的偏导依赖于高层激活函数的导数的级联乘积
- 当训练一个较深的网络,梯度计算层层传导可能出现梯度爆炸或者梯度消失,使得loss不再变化或者loss不断变大
- 从深层网络角度来讲,不同的层学习的速度差异很大,表现为网络中靠近输出的层学习的情况很好,靠近输入的层学习的很慢
- 可以使用梯度裁剪或者残差网络(增加shortcut)尝试解决
- 正则项对于梯度爆炸可能有用(因为会抑制w的增长)
- 使用relu作为激活函数可以有效控制梯度消失问题(导数不会趋近于0)
- batchnorm对于梯度消失和爆炸也有抑制作用(规范化每层的输出,消除放大缩小的影响)
数据划分
- 数据一般分为训练集train、开发集dev(交叉验证集)和训练集test来防止过拟合
- 训练集和开发集都输入模型,但开发集不参与训练,只是提供实时的模型评价,测试集用于离线测试,会进行更多评价标准的测试
- 经验做法是6:2:2或者8:1:1,随着数据量越来越大,dev和test占比可以更小
- 三个数据集尽量要来自同一分布
过拟合与欠拟合
-
偏差指的是算法在大型 训练集上的错误率;方差指的是算法在测试集上的表现低于训练集的程度。当使用均方误差(MSE )作为误差度量指标时,你可以写下偏差和方差对应的两个公式,并且证明总误差=偏差+方差。但在 处理机器学习问题时,此处给出的偏差和方差的非正式定义已经足够。
-
欠拟合(高偏差、训练集表现不好)
- 模型未能很好地捕捉训练集数据中的信息
- 做更多的特征工程,使得训练集中的信息更容易被学习到
- 可能网络结构无法承载和表达训练集的信息,采用新的更大的网络和调整优化方法
- 进行更长时间的训练
- 调整超参数
- 不断降低偏差,直到能较好地你拟合训练集,再观察方差
-
过拟合(高方差、dev集表现不好)
- 从训练集中学到的信息不能很好地应用于dev集甚至现实世界
- 获取更多训练数据,可以尝试数据扩增(尤其对于图片)
- 噪音注入:手动给训练集增加噪声样本
- 采用正则化和dropout
- 训练集和dev集可能分布本身不一致
- 也有可能高容量的网络捕捉到了训练集中的噪声,尝试采用表达能力稍弱的网络结构(一般不要这样做)
- 调整超参数
- 对学习到的参数进行限制,例如uninorm, maxnorm, minmax
- 特征多,样本少,需要做特征选择
- 相关的特征多,可能引起多重共线性问题 (http://www.doc88.com/p-4823474704187.html) (https://support.minitab.com/zh-cn/minitab/18/help-and-how-to/modeling-statistics/regression/supporting-topics/model-assumptions/multicollinearity-in-regression/)
正则化
- 正则项 在损失函数中给参数w增加一定的权重,使得模型倾向于更简单化,避免学习出过于复杂的模型从而造成过拟合,优先选用L2正则项
- dropout 训练时在某些层随机使得一些节点失活,预测时使用全部信息,dropout能够使节点更加独立,不过多依赖其他节点进行预测,只使用部分信息也能有较好的效果,提升了模型的健壮性和泛化能力。
- 在过拟合之前提前终止(early stopping)也是好的正则化方法
batchnorm
- 痛点:每一层的输出的分布可能会变化,不利于后面层的学习(参考数据规范化部分)
- 对一个batch的每层的每个feature都做normalization
- 存在前面层学习到的信息丢失的可能,可以使用缩放和平移变量γ和β ,计算归一化后的值(并不一定做标准归一化)
- 缩放和平移变量γ和β是对总体期望和方差的估计,每一个批次使用移动加权平均计算,这样以后既能较好地凸显一个batch内的相对关系(更有区分度),也不丢失相对总体的信息
- 减小batch内不同数据分布的差异,使得梯度更加均匀
- 对于像sigmoid或者tanh这样的激活函数来说,归一化的输入也更友好
- 优点:batchnorm本身有助于正则化(对参数分布有规范化的作用);收敛较快,可以使用更大的学习率;有更好的泛化能力,可以不用或者少用其他的正则方式;batch size应该设大一些,也有助于加速训练
- 测试和线上预估时可以使用样本总体的均值和方差,一般采用移动平均得到,预估和训练时打分不一致是正常的
神经网络调优流程
- 首先要拟合训练集
- 然后拟合dev和test数据集(减小方差)
- 最后在真实世界表现提升
- 偏差/方差分析:用人类水平(贝叶斯最优)做标杆来决定采用减小偏差还是减小方差的策略,bayes error -> training error -> dev error
- 做误差分析:人工标记出错的类, 集中处理较常出现的误差类型
度量方法
- 查准率(precision,P)标记为真的,多少是真样本?
- 查全率(recall, R)对于所有为真的样本,有多少被标记了?
- F1 score:查准率和查全率的调和平均数 1/(1/P + 1/R),单一数值评价指标
- roc、auc: 图像纵横坐标分别是真阳率(True Positive Rate, TPR)和假阳率(False Positive Rate, FPR),在模型对于正负预测阈值的选择上,我们希望TPR尽量高,而FPR尽量低,roc的auc大于0.5,体现了在一批预测结果中正样本排在负样本前的概率
- 多个指标的情况下,选择一个作为优化指标,选择其他的作为满足指标
迁移学习和多任务学习
- 迁移学习:当任务A和任务B拥有相同的输入格式,且A的数据量远远大于B时,训练B数据的网络时可以将训练A数据得到的网络做fine tuning,其中的低层次特征可能会对提升B的效果有帮助
- 多任务学习:训练单个网络处理多任务,一个样本对应多个标签,损失函数为多个任务损失函数的和,当不同任务可以共享底层特征、数据量相近时适用
- 可以训练更大更深的网络来应对多任务
最优化问题
- 凸函数:一个函数是凸函数是它存在最优解的充要条件
- 约束问题
- 无约束优化 直接对f(X)求导,得到最优解
- 等式约束优化 拉格朗日乘数法
- 不等式约束优化 最优解必须满足KKT条件
- 如果损失函数不平滑(L1正则),则在不可导处使用次梯度(subgradient)代替梯度进行梯度下降
- 稀疏性很重要,是一个主要的追求目标,除了特征选择的作用以外,稀疏性可以使得预测计算的复杂度降低
- 在online模式下,由于W不是沿着全局梯度更新,而是一个近似随机的更新过程,即使使用L1正则也很难产生稀疏解
- 在线最优化算法
- 截断梯度法(TG)
- FOBOS
- RDA
- FTRL
负采样
- 主要是为了解决样本选择偏差问题,适用于比较大的物料库的情况 (经验上 >10w,可以开始尝试),如果物料库比较小,直接学精排样本可能会更好
- 常规负采样,因为正样本里高热item是统治性的,所以要对热门item做过采样,具体按照曝光热度、点击热度还是其他需要尝试,理论上使用点击热度应该更好,因为更贴合正样本分布,样本也更难
- 难负例构造,纯用负采样的话任务太简单,模型学不出太多有价值的东西,需要人为给样本增加难度,方法很多,一般可以尝试下面一些方式
- 同一个request 采精排排在不上不下位置的 (100 ~ 500)
- 用曝光未点击
- 同一个batch 采其他用户的正样本item中打分比较高的
- 用item相关性较高的 (比如同类目、同店铺)