基础知识01

  • 张量
  • 参数初始化策略
  • 参数范数与正则化
  • 梯度下降法
  • 梯度爆炸与梯度消失
  • 自适应学习率算法
  • 评估指标
  • 归一化
  • Dropout
  • 激活函数
  • 损失函数
  • 反向传播算法(公式推导)
  • 过拟合与欠拟合

张量

张量(tensor)是一个多维数组,张量的阶数(order)也称为维度(dimensions)。

一阶张量是一个矢量,二阶张量是一个矩阵,三阶或更高阶的张量叫做高阶张量

三阶张量

张量的范数

张量 \(\mathscr{X} \in \mathbb{R}^{I_1 \times I_2 \times \cdots \times I_N}\) 的范数(norm)是其所有元素平方和的平方根,即

\[ \Vert \mathscr{X} \Vert = \sqrt{\sum_{i_1=1}^{I_1}{\sum_{i_2=1}^{I_2}{\cdots \sum_{i_N=1}^{I_N}{x_{i_1i_2 \cdots i_N}^2}}}} \]

张量的内积

两个相同大小的张量 \(\mathscr{X} , \mathscr{Y} \in \mathbb{R}^{I_1 \times I_2 \times \cdots \times I_N}\) 的内积(inner product)为

\[ \langle \mathscr{X} , \mathscr{Y} \rangle = \sum_{i_1=1}^{I_1}{\sum_{i_2=1}^{I_2} {\cdots \sum_{i_N=1}^{I_N}{x_{i_1i_2 \cdots i_N} y_{i_1i_2 \cdots i_N}}}} \]

且有 \(\langle \mathscr{X} , \mathscr{X} \rangle = \Vert \mathscr{X} \Vert^2\)

一些代码实现

# 生成一个随机的(n,m)的矩阵,其中的每个元素都从均值为0、标准差为1的标准高斯分布(正态
x=torch.randn(3, 4)

# 使用 arange 创建一个行向量 x。这个行向量包含以0开始的前n个整数,它们默认创建为整数
x = torch.arange(12)

# 查看x的形状
x.shape

# 改变x的形状 元素的个数总和不能改变
'''
view和reshape都是用来重塑tensor的shape的。
view只适合对满足连续性条件(contiguous)的tensor进行操作,
而reshape同时还可以对不满足连续性条件的tensor进行操作,具有更好的鲁棒性。
view能干的reshape都能干,如果view不能干就可以用reshape来处理
参考连接:https://blog.csdn.net/Flag_ing/article/details/109129752
'''
x.reshape(3,4)

# 查看设备是否能使用cuda
torch.cuda.is_available()

# 把张量移动到GPU上
# DEVICE='cuda:0'
DEVICE='cpu'
x.to(DEVICE)
# 或者
# x.cuda()

# 查看张量所在的设备
x.device
# 基本的加减乘除
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y
# 两个向量在同一维度上的拼接
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
# 两个向量在新维度上的堆叠
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.stack((X, Y), dim=0)

索引切片和广播机制 就像在任何其他Python数组中一样,张量中的元素可以通过索引和切片访问。 张量的广播机制和numpy的广播机制一样 切片和python内置的数组一样 两个张量形状不一样时进行运算,有两种情况能够进行广播

  1. A.ndim > B.ndim, 并且A.shape最后几个元素包含B.shape, A.shape=(2,3,4,5), B.shape=(3,4,5) A.shape=(2,3,4,5), B.shape=(4,5) A.shape=(2,3,4,5), B.shape=(5)

  2. A.ndim == B.ndim, 并且A.shape和B.shape对应位置的元素要么相同要么其中一个是1, A.shape=(1,9,4), B.shape=(15,1,4) A.shape=(1,9,4), B.shape=(15,1,1)

参数初始化策略

参数初始化指的是网络模型在进行训练之前,对各个节点的权重和偏置进行初始化赋值的过程。

深度学习中,神经网络的参数初始化策略对模型的收敛速度及性能有至关重要的影响。在神经网络中,随着层数的增多,在梯度下降的过程中极易出现梯度消失或梯度爆炸的问题,一个好的参数初始化对于处理这两个问题有着很大帮助。

初始化为常数、过大或过小

这些初始化策略都是不可取的,常数初始化会使得每层所有神经元相等,效果等效于一个神经元,极大限制了神经网络的学习能力。而参数过大过小会导致模型出现梯度爆炸或梯度消失的问题。

具体推导过程可见:https://zhuanlan.zhihu.com/p/138064188

什么样的初始化是好的?

  • 因为对参数 \(w\) 的大小和正负缺乏先验知识,\(w\) 应为随机数,且期望 \(E(w) = 0\)
  • 为了防止梯度爆炸和梯度消失,权重不宜过大或过小,要对权重的方差 \(Var(w)\) 有所控制。
  • 由于 \(dW_{l} = \frac{1}{m}dZ_{l}\cdot A_{l-1}^T\)\(dW_{l}\) 还与 \(A_{l-1}^T\) 有关,所以我们希望不同激活层输出的方差相同,即 \(Var(a_l) = Var(a_{l-1})\) ,也就意味着不同激活层输入的方差相同,即 \(Var(z_l) = Var(z_{l-1})\)
  • 权重的数值范围应考虑到前向与后向两个过程,不能过大或过小。

Xavier初始化策略

论文地址:Understanding the difficulty of training deep feedforward neural networks

核心思想:正向传播时,激活值的方差保持不变;反向传播时,关于状态值的梯度的方差保持不变

Xavier初始化将每层权重设置在有界的随即均匀分布中选择的值

\[ \pm \frac{\sqrt{6}}{\sqrt{n_i+n_{i+1}}} \]

其正态分布形式为

\[ (u, \sigma^2) = (0, \frac{2}{n_{i-1}+n_{i}}) \]

Xavier初始化策略对使用关于零对称且在[-1, 1]内有输出的激活函数(如softsign和tanh)效果较好,而如果使用ReLU激活函数则会产生梯度消失。

def Xavier(m, h):
return torch.Tensor(m, h).uniform_(-1, 1) * math.sqrt(6. / (m + h))

x = torch.randn(512)
for i in range(100):
a = Xavier(512, 512)
x = torch.tanh(a @ x)
print(x.mean(), x.std())

x = torch.randn(512)
for i in range(100):
a = Xavier(512, 512)
x = torch.relu(a @ x)
print(x.mean(), x.std())
tensor(0.0072) tensor(0.0723)
tensor(5.5722e-16) tensor(8.1033e-16)

Kaiming初始化策略

论文地址:Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification

核心思想:正向传播时,状态值的方差保持不变;反向传播时,关于激活值的梯度的方差保持不变

Kaiming初始化(也称he初始化)是针对Relu激活函数的初始化方法,作者证明了如果采用一下输入权重初始化策略,深层网络会更早收敛:

  • 使用适合给定图层的权重矩阵创建张量,并使用从标准正态分布中随机选择的数字填充它。
  • 将每个随机选择的数字乘以\(\frac{\sqrt{2}}{\sqrt{n}}\),其中n是从前一层输出到指定层的连接数(fan-in)
  • 偏差张量初始化为零。
def Kaiming(m, h):
return torch.randn(m, h) * math.sqrt(2. / m)

x = torch.randn(512)
for i in range(100):
a = Kaiming(512, 512)
x = torch.relu(a @ x)
print(x.mean(), x.std())
tensor(0.7144) tensor(1.0703)

参数范数与正则化

正则化(regularization)技术广泛应用在机器学习和深度学习算法中,其本质作用是防止过拟合、提高模型泛化能力。在早期的机器学习领域一般只是将范数惩罚叫做正则化技术,而在深度学习领域认为:能够显著减少方差,而不过度增加偏差的策略都可以认为是正则化技术,故推广的正则化技术还有:扩增样本集、早停止、Dropout、集成学习、多任务学习、对抗训练、参数共享等

范数

  1. P范数:

\[ L_p = (\sum_{i = 1}^n\vert x_i\vert^p)^{\frac{1}{p}} \]

  1. L0范数:表示向量中非零元素的个数
  2. L1范数:为向量元素绝对值之和

\[ \Vert x\Vert _1 = \sum_{i = 1}^n\vert x_i\vert \]

  1. L2范数:向量元素的平方和再开方,也称欧几里得距离

\[ \Vert x\Vert _2 = \sqrt{\sum_{i = 1}^nx_i^2} \]

  1. \(\infty\) 范数:即所有向量元素绝对值中的最大值

\[ \Vert x\Vert _\infty = \max_i\vert x_i\vert \]

  1. \(-\infty\) 范数:即所有向量元素绝对值中的最小值

\[ \Vert x\Vert _{-\infty} = \min_i\vert x_i\vert \]

简单数值假设分析

不同参数下的曲线拟合结果(左欠拟合,右过拟合)

对于右边的拟合曲线,有

\[ h_\theta(x) = \theta _0 + \theta _1x_1 + \theta _2x_2^2 + \theta _3x_3^3 + \theta _4x_4^4 \]

由于 \(\theta _3\)\(\theta _4\) 对应了高阶,导致拟合曲线是4阶曲线,出现了过拟合。正则化的目的为适当缩减 \(\theta _3\)\(\theta _4\) 的值,例如都为0.0001,则上述曲线本质上等价于

\[ h_\theta(x) = \theta _0 + \theta _1x_1 + \theta _2x_2^2 \]

也就是变成了中间的刚好合适的拟合曲线。对 \(\theta _3\)\(\theta _4\) 增加L2正则项后的代价函数表达式为

\[ J(\theta) = \min_\theta \frac{1}{n} \sum_{i = 1}^n{((h_\theta(x^i) - y^i)^2 + 1000\theta_3^2 + 1000\theta_4^2)} \]

从上式可以看出, \(\theta _3\)\(\theta _4\) 均大于0,其乘上了1000,要是 \(J(\theta)\) 最小,则会迫使模型学习到的 \(\theta _3\)\(\theta _4\) 会非常小,因为只有在 \(\theta _3\)\(\theta _4\) 非常小的情况下整个代价函数值才会取的较小值。在实际开发中,是对所有参数进行正则化,为了使代价函数尽可能的小,所有的参数 \(\theta\) 的值(不包括 \(\theta_0\) )都会在一定程度上减小,但是减少程度会不一样,从而实现了权重衰减、简化模型复杂度的作用。

参数范数与正则化的联系

如果有一批数据输入指数为50的函数分布,我们至少需要输入50组数据来记录所有的函数对应的参 数。但对于深度学习这种拥有百万级参数规模的学习模型来说,那简直是不可想象的。

  1. 因此我们放松限制,仅仅控制参数的数目,而不是从高到低的顺序限制参数。我们将不为0的参数数 量限制再 c 以内来达到限制模型的目的(L0范数惩罚)。
  2. 虽然我们已经放松了限制,但是以上表达式并不完美,对于实际应用并不是太友好,那么我们不妨再 放松一下限制,不要求非零的参数个数控制再 c 以内,但要求参数绝对值数值的和控制再 c 以内。这种 参数数值总和的限制被称之为L1范数惩罚,也被成为参数稀疏性惩罚
  3. 虽然我们已经更加放松了限制,但是这还是不完美,因为带有绝对值,我们都知道,绝对值函数再求 梯度时不可导,因此我们再次放宽限制,将求绝对值和变为求平方和,如下式所示,这就是L2范数惩 罚,也就是我们熟悉的权重衰减惩罚。我们可以通过控制 c 值的大小来限制模型的学习能力,c 越大, 模型能力就越强(过拟合),c 越小,模型能力就越弱(欠拟合)。该条件极值可以通过拉格朗日乘子 法来进行求解。

梯度下降法

优化算法的功能是通过改善训练方法,来最小化(或最大化)损失函数 \(J(\theta)\)

梯度下降背后的思想是:开始时我们随机选择一个参数的组合 \((\theta _0, \theta _1, \theta _2, \dots, \theta _n)\) ,计算损失函数,然后我们寻找下一个能让损失函数值下降最多的参数组合。我们持续这么做直到到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。

不同初始参数组合找到不同的极小值

梯度下降算法如下:

\[ \theta _j := \theta _j - \alpha\frac{\partial}{\partial\theta _j}J(\theta) \]

其中 \(\alpha\) 是学习率(learning rate),它决定了我们沿着该方向迈出的步子有多大。\(\alpha\) 太大或太小都不好,太小会导致收敛速度很慢,而太大可能会越过最低点,甚至无法收敛。

梯度下降法

传统的批量梯度下降法计算整个数据集梯度,但只进行一次更新,这在处理大型数据集时速度很慢且难以控制,甚至导致内存溢出。

权重的更新速度由学习率 \(\alpha\) 决定,并且可以在凸面误差曲线中收敛到全局最优值,在非凸曲面中可能趋于局部最优值。

此外,标准形式的批量梯度下降法在训练大型数据集时存在冗杂的权重更新。

梯度爆炸与梯度消失

梯度爆炸

误差梯度是神经网络训练过程中计算的方向和数量,用于以正确的方向和合适的量更新网络权重。 在深层网络或循环神经网络中,误差梯度可在更新中累积,变成非常大的梯度,然后导致网络权重的大幅更新,并因此使网络变得不稳定。在极端情况下,权重的值变得非常大,以至于溢出,导致 NaN 值。 网络层之间的梯度(值大于 1.0)重复相乘导致的指数级增长会产生梯度爆炸。在深度多层感知机网络中,梯度爆炸会引起网络不稳定,最好的结果是无法从训练数据中学习,而最坏的结果是出现无法再更新的NaN权重值。

梯度消失

在某些情况下,梯度会变得非常小,有效地阻止了权重值的变化。在最坏的情况下,这可能会完全停止神经网络的进一步训练。例如,传统的激活函数(如双曲正切函数)具有范围(0,1)内的梯度,反向传播通过链式法则计算梯度。这样做的效果是,用这些小数字的n乘以n来计算n层网络中“前端”层的梯度,这意味着梯度(误差信号)随n呈指数递减,而前端层的训练非常缓慢。

产生原因

主要是采用了不合适的损失函数, 如果我们使用标准化初始w,那么各个层次的相乘都是0-1之间的小数,而激活函数f的导数也是0-1之间的数,其连乘后,结果会变的很小,导致梯度消失。若我们初始化的w是很大的数,w大到乘以激活函数的导数都大于1,那么连乘后,可能会导致求导的结果很大,形成梯度爆炸。

解决方法

预训练并微调

基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出作为输入,而本层隐节点的输出作为下一层隐节点的输入,此过程就是逐层“预训练”(pre-training);在预训练完成后,再对整个网络进行“微调”(fine-tunning)。

梯度剪切与正则化

梯度剪切这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,然后更新梯度的时候,如果梯度超过这个阈值,那么就将其强制限制在这个范围之内。这可以防止梯度爆炸。

另外一种解决梯度爆炸的手段是采用权重正则化(weithts regularization)比较常见的是L1正则化,和L2正则化,在各个深度框架中都有相应的API可以使用正则化。

使用relu、leakrelu、elu等激活函数

Relu:思想也很简单,如果激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络都可以得到相同的更新速度,relu就这样应运而生。详见激活函数

批规范化

Batchnorm是深度学习发展以来提出的最重要的成果之一,目前已经被广泛的应用到了各大网络中,具有加速网络收敛速度,提升训练稳定性的效果,Batchnorm本质上是解决反向传播过程中的梯度问题。batchnorm全名是batch normalization,简称BN,即批规范化,通过规范化操作将输出信号x规范化到均值为0,方差为1保证网络的稳定性。

使用残差结构

自从残差提出后,几乎所有的深度网络都离不开残差的身影,相比较之前的几层,几十层的深度网络,在残差网络面前都不值一提,残差可以很轻松的构建几百层,一千多层的网络而不用担心梯度消失过快的问题,原因就在于残差的捷径(shortcut)部分。

LSTM(长短期记忆网络)

在RNN网络结构中,由于使用Logistic或者Tanh函数,所以很容易导致梯度消失的问题,即在相隔很远的时刻时,前者对后者的影响几乎不存在了,LSTM的机制正是为了解决这种长期依赖问题。

自适应学习率算法

学习率对模型的性能有显著的影响,是难以设置的超参数之一。损失通常高度敏感于参数空间中的某些方向,而不敏感于其他。动量算法可以在一定程度缓解这些问题,但这样做的代价是引入了另一个超参数。

Delta-bar-delta 算法 (Jacobs, 1988) 是一个早期的在训练时适应模型参数各自学习率的启发式方法。该方法基于一个很简单的想法,如果损失对于某个给定模型参数的偏导保持相同的符号,那么学习率应该增加。如果对于该参数的偏导变化了符号,那么学习率应减小。当然,这种方法只能应用于全批量优化中。最近,提出了一些增量(或者基于小批量)的算法来自适应模型参数的学习率。

AdaGrad

Adagrad方法是在每个时间步中,根据过往已计算的参数梯度,来为每个参数修改对应的学习率。能独立地适应所有模型参数的学习率,当参数损失偏导值比较大时,有一个较大的学习率;当参数的损失偏导值较小时,有一个较小的学习率。

Adagrad方法的主要好处是,不需要手工来调整学习率。大多数参数使用了默认值0.01,且保持不变。

Adagrad方法的主要缺点是,学习率总是在降低和衰减。

因为每个附加项都是正的,在分母中累积了多个平方梯度值,故累积的总和在训练期间保持增长。这反过来又导致学习率下降,变为很小数量级的数字,该模型完全停止学习,停止获取新的额外知识。

因为随着学习速度的越来越小,模型的学习能力迅速降低,而且收敛速度非常慢,需要很长的训练和学习,即学习速度降低。

Adagrad算法

RMSProp

RMSProp 算法 (Hinton, 2012) 修改 AdaGrad 以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均。

AdaGrad 旨在应用于凸问题时快速收敛。当应用于非凸函数训练神经网络时,学习轨迹可能穿过了很多不同的结构,最终到达一个局部是凸碗的区域。 AdaGrad 根据平方梯度的整个历史收缩学习率,可能使得学习率在达到这样的凸结构前就变得太小了。

RMSProp 使用指数衰减平均以丢弃遥远过去的历史,使其能够在找到凸碗状结构后快速收敛,它就像一个初始化于该碗状结构的 AdaGrad 算法实例。相比于 AdaGrad,使用移动平均引入了一个新的超参数 \(\rho\),用来控制移动平均的长度范围。经验上,RMSProp 已被证明是一种有效且实用的深度神经网络优化算法,是深度学习从业者经常采用的优化方法之一。

RMSProp算法
使用Nesterov动量的RMSProp算法

Adam

Adam (Kingma and Ba, 2014) 是另一种学习率自适应的优化算法,它可以被看作结合 RMSProp 和具有一些重要区别的动量的变种。

首先,在 Adam 中,动量直接并入了梯度一阶矩(指数加权)的估计。将动量加入 RMSProp 最直观的方法是将动量应用于缩放后的梯度。结合缩放的动量使用没有明确的理论动机。

其次, Adam 包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估计。 RMSProp 也采用了(非中心的)二阶矩估计,然而缺失了修正因子。因此,不像 Adam,RMSProp 二阶矩估计可能在训练初期有很高的偏置。

Adam 通常被认为对超参数的选择相当鲁棒,尽管学习率有时需要自行从默认值修改。

Adam算法

评估指标

分类指标

混淆矩阵(confusion matrix)是一个评估分类问题常用的工具,对于 k 元分类,其实它就是一个 k*k 的表格,用来记录分类器的预测结果。对于常见的二分类,它的混淆矩阵是 2*2 的。

在二分类问题中,可以将样例根据其真实类别和预测类别的组合划分为:

  • 真正例(true positive)TP
  • 假正例(false positive)FP
  • 真反例(true negative)TN
  • 假反例(false negative)FN

显然 TP + FP + TN + FN = 样例总数。分类结果的混淆矩阵如下:

真实情况 预测 结果
正例 反例
正例 TP(真正例) FN(假反例)
反例 FP(假正例) TN(真反例)

准确率(精度,Accuracy)

精度Accurac是指模型预测正确(包括真正例TP、真反例TN)的样本数与总体样本数的占比,即:

\[ Accuracy = \frac{Count(correct)}{Count(total)} \]

在二分类问题中:

\[ Accuracy = \frac{TP + TN}{TP + FP + FN + TN} \]

准确率是分类问题中最简单直观的指标,但是在实际中应用不多。原因是:当样本标签分布不均衡时,比如:正样本占比99%,只要模型把所有样本都预测为正样本,则准确率达到99%,但是实际上模型根本没有预测能力。

查准率(精确率,Precision)

查准率是从预测正例的角度出发(分子分母都是关于Positive):

\[ Precision = \frac{TP}{TP + FP} \]

假设我们用模型预测了一批西瓜,预测100个瓜为好瓜,其中60个为好瓜,40个坏瓜,则查准率就是60/100=60%.

查准率评估了模型预测的正例中的精度--准确更重要。

假设我们提高阈值,使得预测为正例的数量变少,预测精度更高,那么查准率就变得更高,因此单一查准率指标依然没法对模型性能进行准确评估。因为模型遗漏了大量正例,使得大量正例被误判为负例。

查全率(召回率,Recall)

召回率从实际正例的角度出发(真正例、假反例)

\[ Recall = \frac{TP}{TP + FN} \]

假设80个好瓜,模型预测出60个好瓜,20个好瓜未被正确预测,则查全率就是60/(60+20)=75%。

召回率评估了针对正例样本,表示样本中的正例有多少被预测正确--少漏更重要,要全。

假设我们降低阈值,就会使得预测为正例的样本数量增多,但查准率会降低。

所以查准率和查全率的矛盾,跟阈值相关。

P-R曲线、平衡点和F1衡量

P-R曲线

在上面分析查准率P,查全率R的时候,我们得到了不同阈值下对P、R的影响。那么当我们预测100的样本后(假设样本预测结果以概率形式输出),我们对样本结果进行排序,排在最前面(概率最大)的模型认为“最可能是”正例的样本,排在最后的是模型认为”最不可能“是正例的样本。按此顺序设置不同的阈值(阈值可以是排序后的概率值,或者固定划分点),在不同的阈值下,计算出当前阈值下的查准率P和查全率R。以查准率为纵轴,查全率为横轴作图,就可以得到查准率-查全率曲线,简称P-R曲线,显示改曲线的图称为”P-R图“。

P-R曲线与平衡点示意图

P-R图直观地显示出学习器在样本总体上的查全率,查准率。在进行比较时,若一个学习期的P-R曲线被另一个学习器完全”包住“,则可以断言后者的性能优于前者。例如图中,学习器A的性能优于学习器C;如果两个学习器的P-R曲线发生了交叉,例如图中的A和B,则难以一般性地断言两者优劣,只能在具体地查准率或者查全率条件下进行比较。

然而,在很多情况下,人们往往仍然希望把A和B比出个高低。这时,一个比较合理地判断依据是比较P-R曲线下面积的大小(Area under curve P-R,AUC-PR),它在一定程度上表征了学习器在查准率和查全率上取得相对”双高“的比例。但这个值不太容易估算,因此,人们设计了一些综合考虑查准率,查全率的性能度量,比如BEP度量,F1度量。

平衡点(Break-Even-Point,BEP)

平衡点(Break-Even-Point),它是”查准率=查全率“时的取值,例如图1中的学习器C的BEP是0.64,基于BEP的比较,可认为A优于B。

F1度量

BEP过于简单,这个平衡点是建立在”查准率=查全率“的前提下,无法满足实际不同场景的应用。我们引入加权调和平均 \(F_\beta\)

\[ \frac{1}{F_\beta} = \frac{1}{1 + \beta ^2}(\frac{1}{P} + \frac{\beta ^2}{R}) \]

\(\beta = 1\) 时,有 \(\frac{1}{F_1} = \frac{1}{2}(\frac{1}{P} + \frac{1}{R})\),即

\[ F_1 = \frac{2 * P * R}{P + R} \]

在一些应用中,对查准率和查全率的重视程度不同。例如在商品推荐中,为了尽可能少打扰用户,更希望推荐的内容确实是用户感兴趣的,此时查准率更重要;而在罪犯信息检索或者病人检查系统中,更希望尽可能少的漏判,此时查全率更重要。F1度量的一般形式是 \(F_\beta\),能让我们自定义对查准率/查全率的不同偏好:

\[ F_\beta = \frac{(1 + \beta ^2) * P * R}{(\beta ^2 * P) + R} \]

其中,\(\beta > 0\) 度量了查全率对查准率的相对重要性,\(\beta = 1\) 时退化为标准F1,\(\beta > 1\) 时查全率有更大影响;\(\beta < 1\) 时,查准率有更大影响。

多分类情况

很多时候我们有多个二分类混淆矩阵,例如进行多次训练/测试,每次得到一个混淆矩阵;或是在多个数据集上进行训练/测试,希望估计算法的全局性能;或者是执行分类任务,每两两类别的组合都对应一个混淆矩阵;总之是在n个二分类混淆矩阵上综合考察查准率和查全率。

一种直接的做法是现在各个混淆矩阵上分别计算出查准率和查全率,记为(P1,R1),(P2,R2),...(Pn,Rn),在计算平均值,这样就得到“宏观查准率”(macro-P),“宏观查全率”(macro-R)、“宏观F1”(macro-F1):

\[ macroP = \frac{1}{n}\sum^n_{i = 1} P_i\\ macroR = \frac{1}{n}\sum^n_{i = 1} R_i\\ macroF1 = \frac{2 * macroP * macroR}{macroP + macroR} \]

另一种方法可以将个混淆矩阵对应的元素进行平均,得到TP、FP、TN、FN的平均值,分别记为 \(\overline{TP}\)\(\overline{FP}\)\(\overline{FN}\)\(\overline{TN}\),再基于这些平均值计算出“微观查准率”(micro-P),“微观查全率”(micro-R)、“微观F1”(micro-F1):

\[ microP = \frac{\overline{TP}}{\overline{TP} + \overline{FP}}\\ microR = \frac{\overline{TP}}{\overline{TP} + \overline{FN}}\\ microF1 = \frac{2 * microP * microR}{microP + microR} \]

ROC与AUC

根据上面混淆矩阵的一系列指标计算,可以发现,将样本预测为正例或者负例是与一个分类阈值相关的。若大于阈值则分为正类,否则为反类。

实际上,根据概率预测结果,我们可以将测试样本进行排序,“最可能”是正例的排在最前面,“最不可能”是正例的排在最后面。这样,分类过程就相当于在这个排序中以某个“截断点”(cut point)将样本分为两部分,前一部分作为正例,后一部分作为反例。

在不同的任务中,我们可以根据任务需求采用不同的阈值,若我们更重视查准率,则选择排序中靠前的位置,若更重视查全率,则可以选择靠后的位置进行截。因此,排序本身的好坏,提现了综合考虑学习器在不同任务下的“期望泛化性能”的好坏。ROC曲线则是从这个角度出发来研究学习器泛化性能的有效工具。

ROC全称是“受试者工作特性”(Receiver Operating Characteristic)曲线。与上述介绍的P-R曲线相似,我们根据预测结果对样例进行排序,按此顺序逐个将样本预测结果作为阈值进行划分。之后计算两个指标:真正例率(True Positive Rate,简称TPR),假正例率(False Positive Rate,简称FPR),公式如下:

\[ TPR = \frac{TP}{TP + FN}\\ FPR = \frac{FP}{FP + TN} \]

以TPR为纵轴,FPR为横轴,得到ROC曲线。在现实任务中通常只有有限个样本来绘制ROC图,此时无法产生图a中光滑的曲线,只能绘制出图b所示的近似曲线。绘制过程如介绍公式时所描述的一样,对样本预测结果进行排序,然后取第一个结果作为阈值,此时所有样本均预测为反例,此时真正例率和假正例率均为0,在坐标(0,0)处标记一个点。随后将第二个样本预测结果作为阈值,得到坐标点,依次类推。

ROC曲线与AUC示意图

当要比较两个学习器的性能优劣时,与P-R曲线相似,若一个学习器的ROC曲线被另一个学习器的曲线完全“包住”,则可断言后者的性能优于前者;若两个学习器的ROC曲线发生交叉,则一般难以断言两者优劣。此时可以比较ROC曲线下的面积,即AUC(Area under ROC Curve)。

很明显,AUC的结果不会超过 1,通常ROC曲线都在 y = x 这条直线上面,所以,AUC的值一般在 0.5 ~ 1 之间。

从定义可知,AUC可以通过对ROC曲线下各部分的面积求和而得。假定ROC曲线是由坐标{(x1,y1),(x2,y2)...}的点连接而成。AUC可估算为

\[ AUC = \frac{1}{2}\sum^{m - 1}_{i = 1}(x_{i + 1} - x_i)(y_i + y_{i + 1}) \]

KS图(Kolomogorov Smirnov chart)

KS值是在模型中用于区分预测正负样本分隔程度的评价指标,一般应用于金融风控领域。如果将人口划分为两个独立的组,其中一组包含所有正例而另一组包含所有负例,则K-S值为100。

与ROC曲线相似,ROC是以FPR作为横坐标,TPR作为纵坐标,通过改变不同阈值,从而得到ROC曲线。而在KS曲线中,则是以阈值作为横坐标,以FPR和TPR作为纵坐标,ks曲线则为TPR-FPR,ks曲线的最大值通常为ks值。

为什么这样求KS值呢?我们知道,当阈值减小时,TPR和FPR会同时减小,当阈值增大时,TPR和FPR会同时增大。而在实际工程中,我们希望TPR更大一些,FPR更小一些,即TPR-FPR越大越好,即ks值越大越好。

可以理解TPR是收益,FPR是代价,ks值是收益最大。图中绿色线是TPR、蓝色线是FPR。

KS

在实际应用中,比如风控模型中,往往单一指标并不能真正比较两个学习器之间的优劣,比如A学习器KS:40,B学习器KS:39。并不能保证A学习器一定比B学习器表现好,就像考试100的同学一定比99分的同学优秀一样。在实际中,通常结合单一指标(比如KS)和图表,综合判断模型在实际应用中,哪一个模型更加有优势。

回归指标

均方误差(Mean Squared Error,MSE)与均方根误差(Root Mean Squared Error,RMSE)

MSE计算的是拟合数据和原始数据对应样本点的误差的平方和的均值,其值越小说明拟合效果越好。

\[ MSE = \frac{1}{N}\sum^N_{i = 1}(y^2_i - \^y^2_i) \]

由于MSE与我们的目标变量的量纲不一致,为了保证量纲一致性,我们需要对MSE进行开方,即均方根误差:

\[ RMSE = \sqrt{\frac{1}{N}\sum^N_{i = 1}(y^2_i - \^y^2_i)} \]

以下是RMSE需要考虑的要点:

  • “平方根”使该指标能够显示大的偏差。
  • 此度量标准的“平方”特性有助于提供更强大的结果,从而防止取消正负误差值。换句话说,该度量恰当地显示了错误的合理幅度。
  • 它避免使用绝对误差值,这在数学计算中是非常不希望的。
  • 当我们有更多样本时,使用RMSE重建误差分布被认为更可靠。
  • RMSE受到异常值的影响很大。因此,请确保在使用此指标之前已从数据集中删除了异常值。
  • 与平均绝对误差( mean absolute error)相比,RMSE提供更高的权重并惩罚大的错误。

平均绝对误差(Mean Absolute Error,MAE)

和 MSE 一样,这种度量方法也是在不考虑方向的情况下衡量误差大小。但和 MSE 的不同之处在于,MAE 需要像线性规划这样更复杂的工具来计算梯度。此外,MAE 对异常值更加稳健,因为它不使用平方。

\[ MAE = \frac{1}{N}\sum^N_{i = 1}\vert y_i - \^y_i\vert \]

决定系数 R方(R-squarded)

判定系数,其含义是也是解释回归模型的方差得分,其值取值范围是[0,1],越接近于1说明自变量越能解释因变量的方差变化,值越小则说明效果越差。又称为the coefficient of determination。判断的是预测模型和真实数据的拟合程度,最佳值为1,同时可为负值。如果结果是0,就说明我们的模型跟瞎猜差不多。如果结果是1。就说明我们模型无错误。如果结果是0-1之间的数,就是我们模型的好坏程度。如果结果是负数。说明我们的模型还不如瞎猜。

R方可以理解为因变量y中的变异性能能够被估计的多元回归方程解释的比例,它衡量各个自变量对因变量变动的解释程度,其取值在0与1之间,其值越接近1,则变量的解释程度就越高,其值越接近0,其解释程度就越弱

一般来说,增加自变量的个数,回归平方和会增加,残差平方和会减少,所以R方会增大;反之,减少自变量的个数,回归平方和减少,残差平方和增加。为了消除自变量的数目的影响,引入了调整的R方。

\[ \begin{aligned} R^2 & = 1- \frac{\sum^m_{i = 1}(f_i - y_i)^2}{\sum^m_{i = 1}(\overline{y_i} - y_i)^2}\\ & = \frac{\frac{1}{m}\sum^m_{i = 1}(f_i - y_i)^2}{\frac{1}{m}\sum^m_{i = 1}(\overline{y_i} - y_i)^2}\\ & = 1 - \frac{MSE(f, y)}{Var(y)} \end{aligned} \]

对百分比误差(MAPE)

MAPE(平均绝对百分比误差)MAPE 为0%表示完美模型,MAPE 大于 100 %则表示劣质模型。

MAPE是衡量预测准确性的统计指标,是百分比值,一般认为MAPE小于10时,预测精度较高

如果存在某个实际值At为0,那么MAPE则无法进行计算;

\[ MAPE = \frac{100\sum^n_{i = 1}\vert\frac{y_i - y'_i}{y_i}\vert}{n} \]

归一化

不同评价指标(即特征向量中的不同特征就是所述的不同评价指标)往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,

为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可比性。原始数据经过数据标准化处理后,各指标处于同一数量级,适合进行综合对比评价。其中,最典型的就是数据的归一化处理。

简而言之,归一化的目的就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。

奇异样本数据是指相对于其他输入样本特别大或特别小的样本矢量(即特征向量)

奇异样本数据的存在会引起训练时间增大,同时也可能导致无法收敛,因此,当存在奇异样本数据时,在进行训练之前需要对预处理数据进行归一化;反之,不存在奇异样本数据时,则可以不进行归一化。

归一化的好处

  1. 归一化后加快了梯度下降求最优解的速度,也即加快训练网络的收敛性;
  2. 归一化有可能提高精度

归一化的方法

最大最小标准化(Min-Max Normalization)

\[ x' = \frac{x - \min{(x)}}{\max{(x)} - \min{(x)}} \]

  1. 线性函数将原始数据线性化的方法转换到[0 1]的范围, 计算结果为归一化后的数据,X为原始数据;

  2. 本归一化方法比较适用在数值比较集中的情况;

  3. 缺陷:如果max和min不稳定,很容易使得归一化结果不稳定,使得后续使用效果也不稳定。实际使用中可以用经验常量来替代max和min。

应用场景:在不涉及距离度量、协方差计算、数据不符合正态分布的时候,如图像处理中,将RGB图像转换为灰度图像后将其值限定在[0 255]的范围。

z-score标准化

\[ x^* = \frac{x - \mu}{\sigma} \]

其中,\(\mu\)\(\sigma\) 分别为原始数据集的均值和方差。

  1. 将原始数据集归一化为均值为0、方差1的数据集。

  2. 该种归一化方式要求原始数据的分布可以近似为高斯分布,否则归一化的效果会变得很糟糕。

应用场景:在分类、聚类算法中,需要使用距离来度量相似性的时候、或者使用PCA技术进行降维的时候,Z-score standardization表现更好。

神经网络归一化

本归一化方法经常用在数据分化比较大的场景,有些数值很大,有些很小。通过一些数学函数,将原始值进行映射。

该方法包括对数、正切等,需要根据数据分布的情况,决定非线性函数的曲线:

对数函数归一化

\[ y = \log_{10}(x) \]

以10为底的对数转换函数,对应的归一化方法为:

\[ x' = \frac{\log_{10}(x)}{\log_{10}(max)} \]

其中max表示样本数据的最大值,并且所有样本数据均要大于等于1.

反正切函数归一化

\[ x' = \frac{2}{\pi}\arctan(x) \]

使用这个方法需要注意的是如果想映射的区间为[0,1],则数据都应该大于等于0,小于0的数据将被映射到[-1,0]区间上.

L2范数归一化

特征向量中每个元素均除以向量的L2范数:

\[ x'_i = \frac{x_i}{norm(x)} \]

什么时候使用归一化

  1. 如果对输出结果范围有要求,用归一化。

  2. 如果数据较为稳定,不存在极端的最大最小值,用归一化。

  3. 如果数据存在异常值和较多噪音,用标准化,可以间接通过中心化避免异常值和极端值的影响。

归一化与标准化不同

标准化/归一化的对比分析

首先明确,在机器学习中,标准化是更常用的手段,归一化的应用场景是有限的。原因有两点:

  1. 标准化更好保持了样本间距。当样本中有异常点时,归一化有可能将正常的样本“挤”到一起去。比如三个样本,某个特征的值为1,2,10000,假设10000这个值是异常值,用归一化的方法后,正常的1,2就会被“挤”到一起去。如果不幸的是1和2的分类标签还是相反的,那么,当我们用梯度下降来做分类模型训练时,模型会需要更长的时间收敛,因为将样本分开需要更大的努力!而标准化在这方面就做得很好,至少它不会将样本“挤到一起”。
  2. 标准化更符合统计学假设对一个数值特征来说,很大可能它是服从正态分布的。标准化其实是基于这个隐含假设,只不过是略施小技,将这个正态分布调整为均值为0,方差为1的标准正态分布而已。

Dropout

想要提高CNN的表达或分类能力,最直接的方法就是采用更深的网络和更多的神经元,即deeper and wider。但是,复杂的网络也意味着更加容易过拟合。于是就有了Dropout,大部分实验表明其具有一定的防止过拟合的能力。

最初的Dropout

Improving neural networks by preventing co-adaptation of feature Detectors

Dropout

如上图左,为没有Dropout的普通2层全连接结构,记为 \(r = a(Wv)\) ,其中 \(a\) 为激活函数。

如上图右,为在第2层全连接后添加Dropout层的示意图。即在模型训练时,随机让网络的某些节点不工作(输出置0),其它过程不变。

由于随机的让一些节点不工作了,因此可以避免某些特征只在固定组合下才生效,有意识地让网络去学习一些普遍的共性(而不是某些训练样本的一些特性)。

Bagging方法通过对训练数据有放回的采样来训练多个模型。而Dropout的随机意味着每次训练时只训练了一部分,而且其中大部分参数还是共享的,因此和Bagging有点相似。因此,Dropout可以看做训练了多个模型,实际使用时采用了模型平均作为输出。

训练时,我们通常设定一个dropout ratio \(p\),即每一个输出节点以概率 \(p\) 置0(不工作)。假设每一个输出都是相互独立的,每个输出都服从二项伯努利分布 \(B(1 - p)\),则大约认为训练时只使用了 \((1-p)\) 比例的输出。

测试时,最直接的方法就是保留Dropout层的同时,将一张图片重复测试 M 次,取 M 次结果的平均作为最终结果。假如有 N 个节点,则可能的情况为 \(R = 2^N\),如果 M 远小于 R,则显然平均效果不好;如果M ≈ N,那么计算量就太大了。因此作者做了一个近似:可以直接去掉Dropout层,将所有输出都使用起来,为此需要将尺度对齐,即比例缩小输出 $ r = r * (1 - p)$。即如下公式:

\[ E_M[a(M * W)v] \approx a(E_M[(M * W)v]) = a((1 - p)Wv) \]

特别的, 为了使用方便,我们不在测试时再缩小输出,而在训练时直接将输出放大1/(1-p)倍。

Dropout得到了广泛的使用,但具体用到哪里、训练一开始就用还是后面才用、dropout_ratio取多大,还要自己多多尝试。有时添加Dropout反而会降低性能。

DropConnect

Regularization of Neural Networks using DropConnect

Dropout-DropConnect

由图可知,DropConnect与Dropout的区别很明显:Dropout是将输出随机置0,而DropConnect是将权重随机置0。 文章说之所以这么干是因为原来的Dropout进行的不够充分,随机采样不够合理。这可以从下图进行理 解:

DropConnect

如上图所示,a表示不加任何Drop时的一层网络模型。添加Drop相当于给权重再乘以一个随机掩膜矩阵 \(M\)

\[ r = a(Wv)\ \ \ No-Drop\\ r = a((M\ldotp\times W)v)\ \ \ Drop\\ M_{ij}\sim Bernoulli(p) \]

不同的是,DropConnect由于直接对权重随机置0,因此其掩膜显得更加具有随机性,如b所示。而Dropout仅对输出进行随机置0,因此其掩膜相当于是对随机的行和列进行置0,如c所示。

训练的时候,训练过程与Dropout基本相同。测试的时候,我们同样需要一种近似的方法。

\[ r = a((M\ldotp\times W)v)\\ r_i = a(u_i)\\ u_i = \sum_j(W_{ij}v_j)M_{ij} \sim \mathcal{N}(\mu, \sigma^2)\\ \mu = pWv\\ \sigma = p(1 - p)(W \ast W)(v \ast v) \]

注意: 掩膜矩阵M的每一个元素都满足二项伯努利分布。假如M的维度为 \(m\ast n\),则可能的掩膜有 \(2^{m + n}\) 种,之前提到过我们可以粗暴的遍历所有的掩膜然后计算结果最后求平均。中心极限定理:和分布渐进于正态分布。 于是,我们可以不去遍历,而是通过计算每一维的均值与方差,确定每一维的正态分布,最后在此正态分布上做多次采样后求平均即可获得最终的近似结果。

具体测试时的算法流程如下:

DropConnect算法

其中,Z是在正态分布上的采样次数,一般来说越大越好,但会使得计算变慢。

实验: 作者当然要做很多对比试验,但其实发现效果并不比Dropout优秀太多,反而计算量要大很多,因此到目前DropConnect并没有得到广泛的应用。具体的对比,可以参看原文,这里贴一张图来说明对于Drop ratio的看法:

DropConnect实验结果

由此可以看出,drop ratio并不是越大越好,具体需要多做实验体会。

激活函数

神经网络中的每个神经元节点接受上一层神经元的输出值作为本神经元的输入值,并将输入值传递给下一层,输入层神经元节点会将输入属性值直接传递给下一层(隐层或输出层)。在多层神经网络中,上层节点的输出和下层节点的输入之间具有一个函数关系,这个函数称为激活函数。

不使用激活函数的话,神经网络的每层都只是做线性变换,多层输入叠加后也还是线性变换。因为线性模型的表达能力通常不够,所以这时候就体现了激活函数的作用了,激活函数可以引入非线性因素

不使用激活函数的神经网络
使用激活函数的神经网络

加入非线性激励函数后,神经网络就有可能学习到滑的曲线来分割面,而不是用复杂的线性组合逼滑曲线来分割面,使神经网络的表示能力更强了,能够更好的拟合目标函数。

sigmoid和tanh是“饱和激活函数”,而ReLU及其变体则是“非饱和激活函数”。使用“非饱和激活函数”的优势在于两点:

  1. "非饱和激活函数”能解决所谓的“梯度消失”问题。
  2. 它能加快收敛速度。

饱和激活函数

假设 \(h(x)\) 是一个激活函数, - 若当n趋向于正无穷,激活函数的导数趋近于0,那么我们称之为右饱和

\[ \lim\limits_{n\to + \infty}h'(x) = 0 \]

  • 若当n趋向于负无穷,激活函数的导数趋近于0,那么我们称之为左饱和

\[ \lim\limits_{n\to - \infty}h'(x) = 0 \]

当函数既满足左饱和也满足右饱和时,我们称之为饱和。典型的函数有Sigmoid、Tanh函数。

Sigmoid

\[ Sigmoid(x) = \frac{1}{1 + e^{- x}} \]

Sigmoid函数图像
Sigmoid导函数图像

Sigmoid函数在历史上曾经非常的常用,输出值范围为[0,1]之间的实数。但是现在它已经不太受欢迎,实际中很少使用。原因是sigmoid存在3个问题:

  1. sigmoid函数饱和使梯度消失(Sigmoidsaturate and kill gradients)。我们从导函数图像中可以看出sigmoid的导数都是小于0.25的,那么在进行反向传播的时候,梯度相乘结果会慢慢的趋于0导致梯度消失。除此之外,为了防止饱和,必须对于权重矩阵的初始化特别留意。如果初始化权重过大,可能很多神经元得到一个比较小的梯度,致使神经元不能很好的更新权重提前饱和,神经网络就几乎不学习。
  2. sigmoid函数输出不是“零为中心”(zero-centered)。一个多层的sigmoid神经网络,如果你的输入x都是正数,那么在反向传播中w的梯度传播到网络的某一处时,权值的变化是要么全正要么全负。
  3. 指数函数的计算是比较消耗计算资源的。

Tanh

实际上,tanh是sigmoid的变形。

\[ \begin{aligned} Tanh(x) & = 2 Sigmoid(2x) - 1\\ & = \frac{1 - e^{-2x}}{1 + e^{-2x}} \end{aligned} \]

Tanh函数图像

tanh与sigmoid不同的是,tanh是“零为中心”的。因此,实际应用中,tanh会比sigmoid更好一些。但是在饱和神经元的情况下,tanh还是没有解决梯度消失问题。

优点:tanh解决了sigmoid的输出非“零为中心”的问题

缺点:依然有sigmoid函数过饱和的问题,且依然进行的是指数运算

非饱和激活函数

ReLU

近年来,ReLU函数变得越来越受欢迎。全称是Rectified Linear Unit,修正线性单元。ReLU是Krizhevsky、Hinton等人在2012年《ImageNet Classification with Deep Convolutional Neural Networks》论文中提出的一种线性且不饱和的激活函数。

\[ ReLU(x) = \max(0, x) \]

ReLU函数图像

优点:

  1. ReLU解决了梯度消失的问题,至少x在正区间内,神经元不会饱和;
  2. 由于ReLU线性、非饱和的形式,在SGD中能够快速收敛;
  3. 运算速度要快很多。ReLU函数只有线性关系,不需要指数计算,不管在前向传播还是反向传播,计算速度都比sigmoid和tanh快

缺点:

  1. ReLU的输出不是“零为中心”(Notzero-centered output)。
  2. 随着训练的进行,可能会出现神经元死亡,权重无法更新的情况。这种神经元的死亡是不可逆转的死亡

训练神经网络的时候,一旦学习率没有设置好,第一次更新权重的时候,输入是负值,那么这个含有ReLU的神经节点就会死亡,再也不会被激活。设置一个合适的较小的学习率,会降低这种情况的发生。

为了解决神经元节点死亡的情况,有人提出了Leaky ReLU、P-ReLu、R-ReLU、ELU等激活函数。

Leaky ReLU

ReLU是将所有的负值设置为0,造成神经元节点死亡情况。相反,Leaky ReLU是给所有负值赋予一个非零的斜率。Leaky ReLU激活函数是在声学模型(2013)中首次提出来的。

\[ LeakyReLU(x) = \begin{cases}x,\ if\ x \geq 0\\ \alpha x,\ if\ x < 0 \end{cases} \]

Leaky ReLU函数图像

优点:

  1. 神经元不会出现死亡的情况。
  2. 对于所有的输入,不管是大于等于0还是小于0,神经元不会饱和。
  3. 由于Leaky ReLU线性、非饱和的形式,在SGD中能够快速收敛。
  4. 计算速度要快很多。Leaky ReLU函数只有线性关系,不需要指数计算,不管在前向传播还是反向传播,计算速度都比sigmoid和tanh快。

缺点:Leaky ReLU函数中的参数 \(\alpha\),需要通过先验知识人工赋值。

Leaky ReLU很好地解决了“dead ReLU”的问题。因为Leaky ReLU保留了x小于0时的梯度,在x小于0时,不会出现神经元死亡的问题。对于Leaky ReLU给出了一个很小的负数梯度值α,这个值是很小的常数。比如:0.01。这样即修正了数据分布,又保留了一些负轴的值,使得负轴信息不会全部丢失。

RReLU

RReLU的英文全称是“Randomized Leaky ReLU”,中文名字叫“随机修正线性单元”。RReLU是Leaky ReLU的随机版本。

\[ y_{ji} = \begin{cases}x_{ji},\ if\ x_{ji} \geq 0\\ \alpha_{ji} x_{ji},\ if\ x_{ji} < 0 \end{cases} \]

where

\[ \alpha_{ji} \sim U(l, u),\ l < u\ and\ l,\ u \in [0, 1) \]

RReLU函数图像

RReLU的核心思想是,在训练过程中,\(\alpha\) 是从一个高斯分布 \(U(l, u)\) 中随机出来的值,然后再在测试过程中进行修正。在测试阶段,把训练过程中所有的 \(\alpha_{ij}\) 取个平均值。

  1. RReLU是Leaky ReLU的random版本,在训练过程中,α是从一个高斯分布中随机出来的,然后再测试过程中进行修正。

  2. 数学形式与PReLU类似,但RReLU是一种非确定性激活函数,其参数是随机的

ELU

ELU的英文全称是“Exponential Linear Units”,中文全称是“指数线性单元”。它试图将激活函数的输出均值接零,从而加快学习速度。同时,它还能通过正值的标识来避免梯度消失的问题。根据一些研究显示,ELU分类精确度是高于ReLU的。

\[ ELU(x) = \begin{cases}x,\ if\ x > 0\\ \alpha(e^x - 1),\ if\ x \leq 0 \end{cases} \]

ReLU及其变种对比

优点:

  1. ELU包含了ReLU的所有优点。
  2. 神经元不会出现死亡的情况。
  3. ELU激活函数的输出均值是接*于零的。

缺点:计算的时候是需要计算指数的,存在计算效率低的问题。

Maxout

Maxout “Neuron” 是由Goodfellow等人在2013年提出的一种很有特点的神经元,它的激活函数、计算的变量、计算方式和普通的神经元完全不同,并有两组权重。先得到两个超平面,再进行最大值计算。激活函数是对ReLU和Leaky ReLU的一般化归纳,没有ReLU函数的缺点,不会出现激活函数饱和神经元死亡的情况。Maxout出现在ICML2013上,作者Goodfellow将maxout和dropout结合,称在MNIST,CIFAR-10,CIFAR-100,SVHN这4个数据集上都取得了start-of-art的识别率。

\[ f_i(x) = \max_{j\in [1, k]}z_{ij} \]

其中,\(z_{ij} = x^TW_{\ldots ij} + b_{ij}\),假设 \(W\) 是二维的,那么我们有

\[ f(x) = \max(w^T_1x + b_1, w^T_2x + b_2) \]

Maxout的拟合能力非常强,它可以拟合任意的凸函数。Goodfellow在论文中从数学的角度上也证明了这个结论,只需要2个Maxout节点就可以拟合任意的凸函数,前提是“隐含层”节点的个数足够多。

优点:

  1. Maxout具有ReLU的所有优点,线性、不饱和性。
  2. 同时没有ReLU的一些缺点。如:神经元的死亡。

缺点:从这个激活函数的公式中可以看出,每个neuron将有两组 \(w\),那么参数就增加了一倍。这就导致了整体参数的数量激增。

如何选择合适的激活函数?

在实践过程中更多还是需要结合实际情况,考虑不同激活函数的优缺点综合使用。

  1. 通常来说,不能把各种激活函数串起来在一个网络中使用。

  2. 如果使用ReLU,那么一定要小心设置学习率(learning rate),并且要注意不要让网络中出现很多死亡神经元。如果死亡神经元过多的问题不好解决,可以试试Leaky ReLU、PReLU、或者Maxout。

  3. 尽量不要使用sigmoid激活函数,可以试试tanh,不过还是建议非饱和激活函数。

损失函数

损失函数使用主要是在模型的训练阶段,每个批次的训练数据送入模型后,通过前向传播输出预测值,然后损失函数会计算出预测值和真实值之间的差异值,也就是损失值。得到损失值之后,模型通过反向传播去更新各个参数,来降低真实值与预测值之间的损失,使得模型生成的预测值往真实值方向靠拢,从而达到学习的目的。

基于距离度量的损失函数

MSE、L1、L2

相应部分

Smooth L1损失函数

Smooth L1损失是由Girshick R在Fast R-CNN中提出的,主要用在目标检测中防止梯度爆炸。

\[ L(Y|f(x)) = \begin{cases}\frac{1}{2}(Y - f(x))^2,\ if\ \vert Y - f(x)\vert < 1\\ \vert Y - f(x)\vert - \frac{1}{2},\ if\ x\vert Y - f(x)\vert \geq 1 \end{cases} \]

def Smooth_L1(x,y):
assert len(x)==len(y)
loss=0
for i_x,i_y in zip(x,y):
tmp = abs(i_y-i_x)
if tmp<1:
loss+=0.5*(tmp**2)
else:
loss+=tmp-0.5
return loss

Huber损失函数

huber损失是平方损失和绝对损失的综合,它克服了平方损失和绝对损失的缺点,不仅使损失函数具有连续的导数,而且利用MSE梯度随误差减小的特性,可取得更精确的最小值。尽管huber损失对异常点具有更好的鲁棒性,但是,它不仅引入了额外的参数,而且选择合适的参数比较困难,这也增加了训练和调试的工作量。

\[ L(Y|f(x)) = \begin{cases}\frac{1}{2}(Y - f(x))^2,\ if\ \vert Y - f(x)\vert \leq \delta\\ \delta\vert Y - f(x)\vert - \frac{1}{2}\delta^2,\ if\ x\vert Y - f(x)\vert > \delta \end{cases} \]

delta=1.0  # 先定义超参数

def huber_loss(x,y):
assert len(x)==len(y)
loss=0
for i_x,i_y in zip(x,y):
tmp = abs(i_y-i_x)
if tmp<=delta:
loss+=0.5*(tmp**2)
else:
loss+=tmp*delta-0.5*delta**2
return loss

Log-Cosh损失函数

Log-Cosh是应用于回归任务中的另一种损失函数,它比L2损失更平滑。Log-cosh是预测误差的双曲余弦的对数。

log-cosh损失函数比均方损失函数更加光滑,具有huber损失函数的所有优点,且二阶可导。因此可以使用牛顿法来优化计算,但是在误差很大情况下,一阶梯度和Hessian会变成定值,导致牛顿法失效。

\[ L(y, y^p) = \sum^n_{i = 1}\log(\cosh(y^p_i - y_i)) \]

# log cosh 损失
def logcosh(true, pred):
loss = np.log(np.cosh(pred - true))return np.sum(loss)

分位数损失函数

预测的是目标的取值范围而不是值。\(\gamma\) 是所需的分位数,其值介于0和1之间,\(\gamma\) 等于0.5时,相当于MAE。 设置多个 \(\gamma\) 值,得到多个预测模型,然后绘制成图表,即可知道预测范围及对应概率(两个 \(\gamma\) 值相减)

\[ L_\gamma(y, y^p) = \sum_{i = y_i < y^p_i}(\gamma - 1)\ldotp\vert y_i - y^p_i\vert + \sum_{i = y_i\geq y^p_i}(\gamma)\ldotp\vert y_i - y^p_i\vert \]

def quantile_loss(y_pred, y_true, r=0.5):
greater_mask = K.cast((y_true <= y_pred), 'float32')
smaller_mask = K.cast((y_true > y_pred), 'float32')
loss = K.sum((r-1)*K.abs(smaller_mask*(y_true-y_pred)), -1) +\
K.sum(r*K.abs(greater_mask*(y_true-y_pred)), -1)
return loss

基于概率分布度量的损失函数

基于概率分布度量的损失函数是将样本间的相似性转化为随机事件出现的可能性,即通过度量样本的真实分布与它估计的分布之间的距离,判断两者的相似度,一般用于涉及概率分布或预测类别出现的概率的应用问题中,在分类问题中尤为常用。

KL散度函数(相对熵)

KL散度( Kullback-Leibler divergence)也被称为相对熵,是一种非对称度量方法,常用于度量两个概率分布之间的距离。KL散度也可以衡量两个随机分布之间的距离,两个随机分布的相似度越高的,它们的KL散度越小,当两个随机分布的差别增大时,它们的KL散度也会增大,因此KL散度可以用于比较文本标签或图像的相似性。基于KL散度的演化损失函数有JS散度函数。JS散度也称JS距离,用于衡量两个概率分布之间的相似度,它是基于KL散度的一种变形,消除了KL散度非对称的问题,与KL散度相比,它使得相似度判别更加准确。

相对熵是恒大于等于0的。当且仅当两分布相同时,相对熵等于0。

\[ L(Y|f(x)) = \sum^n_{i = 1}Y_i \times \log(\frac{Y_i}{f(x_i)}) \]

def kl_loss(y_true:list,y_pred:list):
"""
y_true,y_pred,分别是两个概率分布
比如:px=[0.1,0.2,0.8]
py=[0.3,0.3,0.4]
"""
assert len(y_true)==len(y_pred)
KL=0
for y,fx in zip(y_true,y_pred):
KL+=y*np.log(y/fx)
return KL

交叉熵损失

交叉熵是信息论中的一个概念,最初用于估算平均编码长度,引入机器学习后,用于评估当前训练得到的概率分布与真实分布的差异情况。为了使神经网络的每一层输出从线性组合转为非线性逼近,以提高模型的预测精度,在以交叉熵为损失函数的神经网络模型中一般选用tanh、sigmoid、softmax或ReLU作为激活函数。

交叉熵损失函数刻画了实际输出概率与期望输出概率之间的相似度,也就是交叉熵的值越小,两个概率分布就越接近,特别是在正负样本不均衡的分类问题中,常用交叉熵作为损失函数。目前,交叉熵损失函数是卷积神经网络中最常使用的分类损失函数,它可以有效避免梯度消散。在二分类情况下也叫做对数损失函数

\[ L(Y|f(x)) = - \sum^n_{i = 1}Y_i\log f(x_i) \]

def CrossEntropy_loss(y_true:list,y_pred:list):
"""
y_true,y_pred,分别是两个概率分布
比如:px=[0.1,0.2,0.8]
py=[0.3,0.3,0.4]
"""
assert len(y_true)==len(y_pred)
loss=0
for y,fx in zip(y_true,y_pred):
loss+=-y * np.log(fx)
return loss

当正负样本不均衡的时候,通常会在交叉熵损失函数类别前面加个参数α

\[ CE = \begin{cases} -\alpha\log(p),\ y = 1\\ -(1 - \alpha)\log(1 - p),\ y = 0 \end{cases} \]

Softmax损失函数

从标准形式上看,softmax损失函数应归到对数损失的范畴,在监督学习中,由于它被广泛使用,所以单独形成一个类别。softmax损失函数本质上是逻辑回归模型在多分类任务上的一种延伸,常作为CNN模型的损失函数。softmax损失函数的本质是将一个k维的任意实数向量x映射成另一个k维的实数向量,其中,输出向量中的每个元素的取值范围都是(0,1),即softmax损失函数输出每个类别的预测概率。由于softmax损失函数具有类间可分性,被广泛用于分类、分割、人脸识别、图像自动标注和人脸验证等问题中,其特点是类间距离的优化效果非常好,但类内距离的优化效果比较差。

softmax损失函数具有类间可分性,在多分类和图像标注问题中,常用它解决特征分离问题。在基于卷积神经网络的分类问题中,一般使用softmax损失函数作为损失函数,但是softmax损失函数学习到的特征不具有足够的区分性,因此它常与对比损失或中心损失组合使用,以增强区分能力。

\[ L(Y|f(x)) = - \frac{1}{n}\sum^n_{i = 1}\log\frac{e^{f_{Y_i}}}{\sum^c_{j = 1}e^{f_j}} \]

def softmax(x):
x_exp = np.exp(x)
x_sum = np.sum(x_exp, axis=1, keepdims=True)
s = x_exp / x_sum
return s

# Tensorflow2.0版
softmax_fc = tf.keras.activations.softmax(x)
# pytorch版
softmax_fc = torch.nn.Softmax()
output = softmax_fc(x)

Focal loss

focal loss的引入主要是为了解决难易样本不均衡的问题,注意有区别于正负样本不均衡的问题。难易样本分为四个类型:

正难 正易
负难 负易

易分样本虽然损失很低,但是数量太多,对模型的效果提升贡献很小,模型应该重点关注那些难分样本,因此需要把置信度高的损失再降低一些。

\[ FE = \begin{cases}-\alpha(1 - p)^\gamma\log(p),\ y = 1\\ -(1 - \alpha)p^\gamma\log(1 - p),\ y = 0 \end{cases} \]

如何选择损失函数

通常情况下,损失函数的选取应从以下方面考虑:

  1. 选择最能表达数据的主要特征来构建基于距离或基于概率分布度量的特征空间。
  2. 选择合理的特征归一化方法,使特征向量转换后仍能保持原来数据的核心内容。
  3. 选取合理的损失函数,在实验的基础上,依据损失不断调整模型的参数,使其尽可能实现类别区分。
  4. 合理组合不同的损失函数,发挥每个损失函数的优点,使它们能更好地度量样本间的相似性。
  5. 将数据的主要特征嵌入损失函数,提升基于特定任务的模型预测精确度。

反向传播算法(公式推导)

反向传播算法(Backpropagation)是目前用来训练人工神经网络(Artificial Neural Network,ANN)的最常用且最有效的算法。其主要思想是:

  1. 将训练集数据输入到ANN的输入层,经过隐藏层,最后达到输出层并输出结果,这是ANN的前向传播过程;
  2. 由于ANN的输出结果与实际结果有误差,则计算估计值与实际值之间的误差,并将该误差从输出层向隐藏层反向传播,直至传播到输入层;
  3. 在反向传播的过程中,根据误差调整各种参数的值;不断迭代上述过程,直至收敛。

变量定义

神经网络

上图是一个三层人工神经网络,layer1至layer3分别是输入层、隐藏层和输出层。

定义变量:

变量 表示
\(w^l_{jk}\) \((l - 1)\) 层的第 \(k\) 个神经元连接到第 \(l\) 层的第 \(j\) 个神经元的权重
\(b^l_j\) \(l\) 层的第 \(j\) 个神经元的偏置
\(z^l_j\) \(l\) 层的第 \(j\) 个神经元的输入,即:\(z^l_j = \sum_kw^l_{jk}a^{l - 1}_k + b^l_j\)
\(a^l_j\) \(l\) 层的第 \(j\) 个神经元的输出,即:\(a^l_j = \sigma(z^l_j)\),其中 \(\sigma\) 表示激活函数

代价函数

代价函数被用来计算ANN输出值与实际值之间的误差。常用的代价函数是二次代价函数(Quadratic cost function):

\[ C = \frac{1}{2n}\sum_x\Vert y(x) - a^L(x)\Vert^2 \]

其中,\(x\) 表示输入的样本,\(y\) 表示实际的分类,\(a^L\) 表示预测的输出,\(L\)表示神经网络的最大层数。

公式及其推导

首先,将第 \(l\) 层第 \(j\) 个神经元中产生的错误(即实际值与预测值之间的误差)定义为:

\[ \delta^l_j = \frac{\partial C}{\partial z^l_j} \]

以一个输入样本为例,此时代价函数为:

\[ C = \frac{1}{2}\Vert y - a^L\Vert^2 = \frac{1}{2}\sum_j(y_j - a^L_j)^2 \]

计算最后一次神经网络产生的错误:

\[ \delta^L = \nabla_a C \odot \sigma'(z^L) \]

其中,\(\cdot\) 表示Hadamard乘积,用于矩阵或向量之间点对点的乘法运算。推导过程如下:

\[ \because \delta^L_j = \frac{\partial C}{\partial z^L_j} = \frac{\partial C}{\partial a^L_j}\cdot\frac{\partial a^L_j}{\partial z^L_j}\\ \therefore \delta^L = \frac{\partial C}{\partial a^L}\odot\frac{\partial a^L}{\partial z^L} = \nabla_a C \odot \sigma'(z^L)\\ \]

从后向前,计算每一层神经网络产生的错误

\[ \delta^l = ((w^{l + 1})^T\delta^{l+1})\odot\sigma'(z^l) \]

推导过程:

\[ \begin{aligned} \because \delta^l_j = \frac{\partial C}{\partial z^l_j} & = \sum_k\frac{\partial C}{\partial z^{l+1}_k}\cdot\frac{\partial z^{l+1}_k}{\partial a^l_j}\cdot\frac{\partial a^l_j}{\partial z^l_j}\\ & = \sum_k\delta^{l+1}_k\cdot\frac{\partial(w^(l+1)_{kj}a^l_j + b^{l+1}_k)}{\partial a^l_j}\cdot\sigma'(z^l_j)\\ & = \sum_k\delta^{l+1}_k\cdot w^{l+1}_{kj}\cdot\sigma'(z^l_j)\\ \therefore \delta^l = ((w^{l + 1})^T\delta^{l+1})\odot\sigma'(z^l) \end{aligned} \]

计算权重的梯度

\[ \frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k\delta^l_j \]

推导过程:

\[ \frac{\partial C}{\partial w^l_{jk}} = \frac{\partial C}{\partial z^l_j}\cdot\frac{\partial z^l_j}{\partial w^l_{jk}} = \delta^l_j\cdot\frac{\partial(w^l_{jk}a^{l-1}_k + b^l_j)}{\partial w^l_{jk}} = a^{l-1}_k\delta^l_j \]

计算偏置的梯度

\[ \frac{\partial C}{\partial b^l_j} = \delta^l_j \]

推导过程:

\[ \frac{\partial C}{\partial b^l_j} = \frac{\partial C}{\partial z^l_j}\cdot\frac{\partial z^l_j}{\partial b^l_j} = \delta^l_j\cdot\frac{\partial(w^l_{jk}a^{l-1}_k + b^l_j)}{\partial b^l_j} = \delta^l_j \]

过拟合与欠拟合

过拟合

定义1(摘自周志华机器学习):当学习器把训练样本学的“太好”了的时候,很可能已经把训练样本自身的一些特点当作了所有潜在样本都会具有的一般性质,这样就会导致泛化性能下降,这种现象称为过拟合。

定义2:具体表现就是最终模型在训练集上效果好;在测试集上效果差。模型泛化能力弱。

具体表现就是最终模型在训练集上效果好;在测试集上效果差。模型泛化能力弱。

产生过拟合的原因

  1. 训练数据中噪音干扰过大,使得学习器认为部分噪音是特征从而扰乱学习规则。
  2. 建模样本选取有误,例如训练数据太少,抽样方法错误,样本label错误等,导致样本不能代表整体。
  3. 模型不合理,或假设成立的条件与实际不符。
  4. 特征维度/参数太多,导致模型复杂度太高。
  5. 对于决策树模型,如果我们对于其生长没有合理的限制,其自由生长有可能使节点只包含单纯的事件数据(event)或非事件数据(no event),使其虽然可以完美匹配(拟合)训练数据,但是无法适应其他数据集。
  6. 对于神经网络模型:a)对样本数据可能存在分类决策面不唯一,随着学习的进行,,BP算法使权值可能收敛过于复杂的决策面;b)权值学习迭代次数足够多(Overtraining),拟合了训练数据中的噪声和训练样例中没有代表性的特征。

过拟合的解决办法

过拟合无法彻底避免,只能缓解。

数据角度

  • 从数据源头获取更多数据
  • 数据增强(Data Augmentation):通过一定规则扩充数据。如物体在图像中的位置、姿态、尺度、整体图片明暗度等都不会影响分类结果。我们可以通过图像平移、反转、缩放、切割等手段将数据库成倍扩充。
  • 保留验证集
  • 获取额外数据进行交叉验证

模型角度

  • 降低模型复杂度:
    • 对于神经网络:减少网络的层数、神经元个数等均可以限制网络的拟合能力。dropout,在向前传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型的泛化性更强,因为它不会太依赖某些局部的特征。
    • 对于决策树:限制树深,剪枝,限制叶节点数量。
    • 增大分割平面间隔
  • 特征选择、特征降维
  • early stopping、Dropout
  • 正则化(限制权值weight-decay):将权值的大小作为惩罚项加入到损失函数里。
  • 增加噪声:
    • 在输入中加噪声。噪声会随着网络传播,按照权值的平方放大,并传播到输出层,会在输出中生成 \(\sum_iw^2_i\cdot\sigma^2_i\) 的干扰项。训练时减小损失函数时也会减小权值,与L2正则化有类似效果。
    • 在权值上加噪声。在初始化网络的时候,用0均值的高斯分布作为初始化。
    • 对网络等响应加噪声。在前向传播的过程中,让某些神经元的输出变为random,从而打乱网络的训练过程,让训练更慢。

ensemble:

  • Bagging:从训练集中自助采样,训练多个相互独立的弱学习器,通过一定结合策略形成一个强学习器。
  • Boosting: 初始化训练一个基学习器→根据表现调整样本分布(预测错误的样本在后续收到更多关注)→训练下一个基学习器→多个学习器加权结合。

欠拟合

定义:欠拟合是指对训练样本的一般性质尚未学好。在训练集及测试集上的表现都不好。

产生欠拟合的原因

  1. 模型复杂度过低
  2. 特征量过少

欠拟合的解决办法

  • 增加特征数;当特征不足或者现有特征与样本标签的相关性不强时,模型易出现欠拟合。可以通过挖掘上下文特征,ID类特征,组合特征等新的特征,可以取得较好的效果。这属于特征工程相关的内容,如因子分解机,梯度提升决策树,deep_crossing都可以丰富特征。
  • 增加模型复杂度;模型简单时其表达能力较差,容易导致欠拟合,因此可以适当地增加模型复杂度,使模型拥有更强的拟合能力。如线性模型中添加高次项,神经网络中增加网络层数或神经元个数。尝试非线性模型,比如核SVM 、决策树、DNN等模型。
  • 减小正则化系数。正则化是用于防止过拟合的,但是当出现欠拟合时,就有必要针对性地减小正则化系数。
  • Boosting,Boosting 往往会有较小的 Bias。
  • 调整参数和超参数