正則化的基本概念之前博客已有記錄, 這里僅對正則化的實現做一點介紹
權重衰減(weight decay)
模型的復雜性——如何衡量函數與0的距離——Lp范數
L2正則化線性模型構成經典的嶺回歸(ridge regression)算法, L1正則化線性回歸通常被稱為套索回歸(lasso regression)。實踐中多使用L2范數。
使用L2范數的一個原因是它對權重向量的大分量施加了巨大的懲罰, 這使得學習算法偏向於在大量特征上均勻分布權重的模型。
在實踐中,這可能使它們對單個變量中的觀測誤差更為穩定。 相比之下,L1懲罰會導致模型將權重集中在一小部分特征上, 而將其他權重清除為零。
L2正則化線性模型,使用驗證數據擬合:
L2正則化回歸的小批量隨機梯度下降更新如下式:
從零實現
將線性模型從零實現的損失函數做一些修改即可
簡潔實現
線性模型從零實現的優化算法需要修改:
trainer = torch.optim.SGD([ {"params":net[0].weight,'weight_decay': wd}, {"params":net[0].bias}], lr=lr)
在實例化優化器時直接通過weight_decay
指定weight decay超參數。
默認情況下,PyTorch同時衰減權重和偏移。 這里只為權重設置了weight_decay
,所以偏置參數b不會衰減。
暫退法(dropout)
模型簡單性的另一個角度是平滑性,即函數不應該對其輸入的微小變化敏感。
在訓練過程中,在計算后續層之前向網絡的每一層注入噪聲。 當訓練一個有多層的深層網絡時,注入噪聲只會在輸入-輸出映射上增強平滑性。 這個想法被稱為暫退法(dropout)。
暫退法在前向傳播過程中,計算每一內部層的同時注入噪聲,這已經成為訓練神經網絡的常用技術。 這種方法之所以被稱為暫退法,因為我們從表面上看是在訓練過程中丟棄(drop out)一些神經元。 在整個訓練過程的每一次迭代中,標准暫退法包括在計算下一層之前將當前層中的一些節點置零。
從零實現
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.rand(X.shape) > dropout).float() return mask * X / (1.0 - dropout) 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)))) if self.training == True: H1 = dropout_layer(H1, dropout1) H2 = self.relu(self.lin2(H1)) if self.training == True: 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(reduction='none') 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)
簡潔實現
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), nn.Dropout(dropout1), nn.Linear(256, 256), nn.ReLU(), nn.Dropout(dropout2), nn.Linear(256, 10)) 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)