1. 如果更改第一层和第二层的暂退法概率,会发生什么情况?具体地说,如果交换这两个层,会发生什么情况?设计一个实验来回答这些问题,定量描述该结果,并总结定性的结论。
dropout1, dropout2 = 0.2, 0.5
dropout1, dropout2 = dropout2, dropout1
首先引入大的暂退概率,使得训练准确率和测试准确率更接近,也就是更好的泛化,更少的过拟合。
2. 增加训练轮数,并将使用暂退法和不使用暂退法时获得的结果进行比较。
num_epochs, lr, batch_size = 30, 0.5, 256
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
dropout1, dropout2 = dropout2, dropout1
net = nn.Sequential(nn.Flatten(),
nn.Linear(num_inputs, num_hiddens1),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
nn.Dropout(dropout1),
nn.Linear(num_hiddens1, num_hiddens2),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
nn.Dropout(dropout2),
nn.Linear(num_hiddens2, num_outputs))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
net = nn.Sequential(nn.Flatten(),
nn.Linear(num_inputs, num_hiddens1),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
# nn.Dropout(dropout1),
nn.Linear(num_hiddens1, num_hiddens2),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
# nn.Dropout(dropout2),
nn.Linear(num_hiddens2, num_outputs))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
3. 当应用或不应用暂退法时,每个隐藏层中激活值的方差是多少?绘制一个曲线图,以显示这两个模型的每个隐藏层中激活值的方差是如何随时间变化的。
without dropout
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2, False)
import numpy as np
y1 = np.array([v.detach().numpy() for v in net.var1])
y2 = np.array([v.detach().numpy() for v in net.var2])
x = np.arange(y1.shape[0])
d2l.plot(x, [y1, y2], xlabel='', ylabel='var', legend=['var1', 'var2'], figsize=(20, 2.5))
with dropout
net_dropout = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2, True)
import numpy as np
y1_dropout = np.array([v.detach().numpy() for v in net_dropout.var1])
y2_dropout = np.array([v.detach().numpy() for v in net_dropout.var2])
x = np.arange(y1_dropout.shape[0])
d2l.plot(x, [y1_dropout, y2_dropout], xlabel='', ylabel='var', legend=['var1_dropout', 'var2_dropout'], figsize=(20, 2.5))
4. 为什么在测试时通常不使用暂退法?
暂退法(Dropout)是一种在训练深度神经网络时常用的正则化技术,其主要目的是防止过拟合。在训练过程中应用暂退法时,它会在每次迭代中随机“丢弃”(即暂时移除)网络中的一些神经元,这迫使网络不能依赖于任何单一的神经元,而是学会让多个神经元共同贡献于最终的输出。这种方法可以模拟出多个不同的网络,从而增加模型的鲁棒性。
然而,在测试阶段通常不使用暂退法,原因如下:
-
集成效应:暂退法在训练过程中相当于同时训练多个不同的模型(由于每次随机丢弃的神经元不同),而在测试时,如果不使用暂退法,相当于评估所有这些模型的平均效果,这通常被称为模型的“集成”效果,往往能提供更好的性能。
-
确定性:在测试或部署模型时,我们通常需要确定性的输出。暂退法由于其随机性,在每次前向传播时都可能产生不同的结果,这在实际应用中是不受欢迎的。
-
性能最大化:在测试阶段的目标是尽可能准确地评估模型的性能,而暂退法由于其随机性,可能会导致模型性能的波动,从而无法准确反映模型的真实能力。
-
计算效率:由于暂退法在训练过程中需要额外的计算来处理随机丢弃的神经元,这会增加训练的计算负担。在测试阶段,由于不需要考虑模型更新,可以移除这一步骤,从而提高效率。
-
实用性:在实际应用中,模型需要处理未知的新数据,而没有时间进行随机化的暂退操作。因此,测试时不使用暂退法可以更好地模拟模型在实际应用中的表现。
总的来说,暂退法是一种训练技巧,用于提高模型的泛化能力,而在测试时,我们更关注模型的确定性和稳定性,因此通常不使用暂退法。
5. 以本节中的模型为例,比较使用暂退法和权重衰减的效果。如果同时使用暂退法和权重衰减,会发生什么情况?结果是累加的吗?收益是否减少(或者说更糟)?它们互相抵消了吗?
net = nn.Sequential(nn.Flatten(),
nn.Linear(num_inputs, num_hiddens1),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
nn.Dropout(dropout1),
nn.Linear(num_hiddens1, num_hiddens2),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
nn.Dropout(dropout2),
nn.Linear(num_hiddens2, num_outputs))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
trainer = torch.optim.SGD(net.parameters(), lr=lr, weight_decay=1e-5)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
net = nn.Sequential(nn.Flatten(),
nn.Linear(num_inputs, num_hiddens1),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
# nn.Dropout(dropout1),
nn.Linear(num_hiddens1, num_hiddens2),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
# nn.Dropout(dropout2),
nn.Linear(num_hiddens2, num_outputs))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
trainer = torch.optim.SGD(net.parameters(), lr=lr, weight_decay=1e-8)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
6. 如果我们将暂退法应用到权重矩阵的各个权重,而不是激活值,会发生什么?
将Dropout应用于权重矩阵的各个权重,而不是激活值,是一种不常规的做法,但它是一个有趣的思想实验。在标准的Dropout中,我们通常将Dropout应用于激活值,即在训练过程中随机地将一些激活值设置为零。这种方法的目的是减少神经元之间复杂的共适应关系,从而促进模型的泛化能力。
如果我们将Dropout应用于权重矩阵的各个权重,那么在每次前向传播时,我们会随机地将一些权重设置为零。以下是这种做法可能带来的一些潜在影响:
-
稀疏权重矩阵:这将导致一个稀疏的权重矩阵,其中许多权重为零。这意味着每个神经元的输入可能只来自少数几个其他神经元,从而减少了网络中的连接数。
-
减少过参数化:在某种程度上,这可能有助于减少模型的过参数化问题,因为权重矩阵的稀疏化可以看作是减少了模型的容量。
-
计算效率:稀疏权重矩阵可能会提高计算效率,因为许多乘法操作将是零,从而可以减少实际需要执行的计算量。
-
训练难度:这种方法可能会使模型训练变得更加困难,因为权重的随机置零可能会破坏梯度的流动,导致优化过程中的不稳定性。
-
减少特定路径的影响:类似于激活值Dropout减少了对特定神经元的依赖,权重Dropout可能减少对特定连接路径的依赖。
-
正则化效果:这可能提供了一种新的正则化效果,通过减少权重之间的共适应性,促进了权重的独立性。
然而,这种非标准Dropout的应用可能会带来一些挑战和问题:
- 梯度消失/爆炸:由于权重随机地被置为零,这可能导致梯度消失或爆炸,影响梯度下降算法的稳定性。
- 学习率调整:可能需要更仔细地调整学习率和优化器的策略,以适应权重Dropout带来的不稳定性。
- 超参数调整:Dropout率的选择可能需要更精细的调整,以找到最佳的稀疏化程度。
在实践中,标准的激活值Dropout已经证明是非常有效的,而权重Dropout的应用并不常见。如果考虑尝试这种方法,可能需要进行大量的实验来确定其对模型性能的影响,并找到合适的超参数设置。此外,这种方法可能需要对现有的深度学习框架进行定制或扩展,因为它们通常不支持对权重矩阵直接应用Dropout。