Linear scaling learning rate

使用大的batch size可能会减慢模型的训练过程。对于凸优化的问题,随着batch size的增加,收敛的速度会降低,神经网络也有类似的验证结果。随着batch size的增大,处理相同数据量的速度会越来越快,但是到达相同精度所需要的epoch数量会越来越多。也就是说,相同的epoch数量,大的batch_size训练的模型比小的batch_size训练的模型相比,验证准确率会减小。在mini-batch随机梯度下降中,梯度下降的值是随机的,因为每一个batch的数据是随机的选择,增大batch size不会改变梯度的期望,但是会降低它的方差。也就是说,大的batch size会降低梯度中的噪声,所以我们可以通过增大学习率来加快收敛的速度。
在论文Bag of Tricks for Image Classification with Convolutional Neural Networks中介绍的是,在ResNet原论文中,batch size为256时候学习率为0.1,当把batch size 变为一个比较大的数b的时候,学习率可以相应的改变为 $0.1 \times b/256$

Label-smoothing

在分类问题中,最后一层一般是全连接层,输出对应着one-hot编码的标签(在pytorch中分类的交叉熵损失nn.CrossEntropyLoss(input, target)中target不是one-hot的而是类别的索引值,这边应该是内部实现直接用索引索引出损失)。这种编码的方式与通过交叉损失来计算损失可能存在一些问题。其中计算出的softmax的结果为每个类别的概率值。
$$q_i = \frac{\exp(z_i)}{\sum_j^k \exp(z_j)}$$
对于目标标签的定义为。

$$p_i=
\begin{cases}
1& \text{$i=y$}\
0& \text{$i \neq y$}
\end{cases}$$
交叉熵的计算公式为:
$$\mathcal{l(p, q)}=-\sum_i^kp_i\log q_i$$
将softmax的结果$q_i$带入上式得
$$\mathcal{l(p, q)}=-z_y+\log(\sum_j^k\exp(z_j))$$

所以以one-hot为目标,交叉损失为损失函数,最小化损失最终得到的最优的$z_y^*$为:

$$z_y^*=
\begin{cases}
+\infty& \text{$i=y$}\
-\infty& \text{$i \neq y$}
\end{cases}$$

这种方式会鼓励模型对不同类别的输出分数差异非常大,或者说,模型过分相信它的判断。但是,对于一个由多人标注的数据集,不同人标注的准则可能不同,每个人的标注也可能会有一些错误。模型对标签的过分相信会导致过拟合。也就是说,网络会驱使自身往正确标签和错误标签差值大的方向学习,在训练数据不足以表征所有的样本特征的情况下,这就会导致网络过拟合。

$$p_i=
\begin{cases}
1-\epsilon& \text{$i=y$}\
\epsilon/(K-1)& \text{$i \neq y$}
\end{cases}$$

这种方式会鼓励模型对不同类别的输出分数差异非常大,或者说,模型过分相信它的判断。但是,对于一个由多人标注的数据集,不同人标注的准则可能不同,每个人的标注也可能会有一些错误。模型对标签的过分相信会导致过拟合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class LabelSmoothing(nn.Module):
def __init__(self, eps=0.0):
super(LabelSmoothing, self).__init__()
self.eps = eps
if self.eps > 0:
self.criterion = nn.KLDivLoss(reduction='batchmean')
else:
self.criterion = nn.NLLLoss()
self.confidence = 1.0 - self.eps

def _smooth_label(self, num_classes):
smooth_label = torch.zeros(1, num_classes)
smooth_label.fill_(self.eps / (num_classes - 1))
return smooth_label

def forward(self, input, target):
scores = F.log_softmax(input, dim=1)
num_classes = input.size(-1)
target = target.view(-1)
if self.confidence < 1:
classes = target.detach()
smooth_label = self._smooth_label(num_classes)
if target.is_cuda:
smooth_label = smooth_label.cuda()
smooth_label = smooth_label.repeat(target.size(0), 1)
smooth_label.scatter_(1, classes.unsqueeze(1), self.confidence)
target = smooth_label.detach()
loss = self.criterion(scores, target)
return loss

if __name__ == "__main__":
outputs = torch.FloatTensor([[0, 0.2, 0.7, 0.1, 0],
[0, 0.9, 0.2, 0.1, 0],
[0, 0.9, 0.2, 0.1, 0]])
labels = torch.LongTensor([2, 1, 0])
criterion = LabelSmoothing(0.1)
loss = criterion(outputs, labels)
print(loss)

Knowledge Distillation

[1] https://www.zhihu.com/question/41631631
[2] https://mp.weixin.qq.com/s?__biz=MzI4MjA0NDgxNA==&mid=2650722499&idx=1&sn=b489bb77ba12be14df197fdc77893b22&chksm=f3958022c4e20934aee7516645a415a379275423b1805da63e7419766ad38460e1f8cd18fc6d&mpshare=1&scene=23&srcid=0303HrF8UEJNThmdJNHWNSqd#rd