这周主要对张量计算中的模态积进行了总结,然后学习了权重衰减和丢弃法两种防止过拟合的方法。
一、模态积:
张量与矩阵相乘即为模态积,假设n1×n2×....×nd的张量X,同时给定一个大小为m×nk的矩阵A,则张量X与矩阵A的k模态积记为X×kA,其大小为,对于每个元素而言,有
可以看出模态积是张量、矩阵和模态的一种组合运算。
例子:若给定张量X为
其大小为2×2×2,另外给定矩阵,假设y=X×1A则对于张量y在任意索(i,j,k)上的值为
,利用这一运算规则,以(1,1,1)和(1,1,2)位置为例,
以此类推可得张量y为
另外在模态积中y=X×kA与y=AX×k是等价的。
二、权重衰减
应对过拟合的最好办法是扩大有效样本,但很多时候,没有什么办法比优化自己的样本数据集更加有效,有时我们常常过于重视调整损失函数,优化方法或者模型结构这些,而忽视了对原始样本的处理。
权重衰减等价于L2范数正则化,以线性回归为例损失由下式
变为
为什么我们首先使用L2范数,而不是L1范数,事实上,这些选择在整个统计领域中都是有效的和受欢迎的。L2正则化线性模型构成经典的岭回归(ridge regression)算法,L1正则化线性回归是统计学中类似的基本模型,通常被称为套索回归(lasso regression)。使用L2范数的一个原因是它对权重向量的大分量施加了巨大的惩罚。这使得我们的学习算法偏向于在大量特征上均匀分布权重的模型。在实践中,这可能使它们对单个变量中的观测误差更为鲁棒。相比之下,L1惩罚会导致模型将其他权重清除为零而将权重集中在一小部分特征上。这称为特征选择,这可能是其他场景下需要的(例如在压缩感知中)。
三、Dropout
dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
在标准dropout正则化中,通过按保留(未丢弃)的节点的分数进行归一化来消除每一层的偏差。换言之,每个中间激活值h以丢弃概率p由随机变量h′替换,如下所示:
根据设计,期望值保持不变,即E[h′]=h。
Dropout简而言之就是:我们在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征,如下图所示。
Dropout解决过拟合的原因:
(1)取平均的作用:在标准的模型即没有dropout,我们用相同的训练数据去训练5个不同的神经网络,一般会得到5个不同的结果,此时我们可以采用 “5个结果取均值”或者“多数取胜的投票策略”去决定最终结果。例如3个网络判断结果为数字9,那么很有可能真正的结果就是数字9,其它两个网络给出了错误结果。这种“综合起来取平均”的策略通常可以有效防止过拟合问题。
(2)减少神经元之间复杂的共适应关系:因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。迫使网络去学习更加鲁棒的特征 ,这些特征在其它的神经元的随机子集中也存在。
Dropout代码:
import torch
from torch import nn
from d2l import torch as d2l
def dropout_layer(X, dropout):
assert 0 <= dropout <= 1
# 在本情况中,所有元素都被丢弃。
if dropout == 1:
return torch.zeros_like(X)
# 在本情况中,所有元素都被保留。
if dropout == 0:
return X
mask = (torch.Tensor(X.shape).uniform_(0, 1) > dropout).float()
return mask * X / (1.0 - dropout)
X= torch.arange(16).reshape((2, 8))
print(X)
print(dropout_layer(X, 0.))
print(dropout_layer(X, 0.5))
print(dropout_layer(X, 1.))
丢弃概率分别取0、0.5、1的结果:
tensor([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15]])
tensor([[ 0, 1, 2, 3, 4, 5, 6, 7],
[ 8, 9, 10, 11, 12, 13, 14, 15]])
tensor([[ 0., 0., 0., 6., 8., 10., 0., 14.],
[ 0., 0., 0., 22., 24., 26., 0., 0.]])
tensor([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]])
定义具有两个隐藏层的多层感知机,每个隐藏层包含256个单元
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
定义模型
dropout1, dropout2 = 0.2, 0.5
class Net(nn.Module):
def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
is_training = True):
super(Net, self).__init__()
self.num_inputs = num_inputs
self.training = is_training
self.lin1 = nn.Linear(num_inputs, num_hiddens1)
self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
self.lin3 = nn.Linear(num_hiddens2, num_outputs)
self.relu = nn.ReLU()
def forward(self, X):
H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
# 只有在训练模型时才使用dropout
if self.training == True:
# 在第一个全连接层之后添加一个dropout层
H1 = dropout_layer(H1, dropout1)
H2 = self.relu(self.lin2(H1))
if self.training == True:
# 在第二个全连接层之后添加一个dropout层
H2 = dropout_layer(H2, dropout2)
out = self.lin3(H2)
return out
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
训练与测试
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss()
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
结果:
没加dropout的结果:
可以看出加了dropout的效果更优。