手の深さ学習PyTorch(4)重みの減衰


PyTorch(二)モデル選択,欠フィッティング,および過フィッティングを手作業で学習し,モデルの訓練誤差が試験セットでの誤差よりはるかに小さいという過フィッティング現象を観測した.トレーニングデータセットを大きくすると、オーバーフィットが軽減される可能性がありますが、追加のトレーニングデータを取得するにはコストがかかることが多いです.このセクションでは、オーバーフィット問題に対処するための一般的な方法:ウェイト減衰(weight decay)について説明します.
方法
重み減衰はL 2 L_に等しい2 L 2ノルム正規化(regularization).正規化は,モデル損失関数に罰則項を追加することによって学習したモデルパラメータ値を小さくし,過フィッティングに対応する常用手段である.まずL 2 L_について説明します2 L 2ノルムを正規化し、重み減衰と呼ばれる理由を説明します.
L 2 L_2 L 2ノルム正規化モデル原損失関数にL 2 L_を追加2 L 2ノルムペナルティ項は、トレーニングに必要な最小化関数を得る.L 2 L_2 L 2ノルムペナルティ項は、モデルウェイトパラメータの各要素の二乗と正の定数との積を指す.3.1節(線形回帰)における線形回帰損失関数
ℓ ( w 1 , w 2 , b ) = 1 n ∑ i = 1 n 1 2 ( x 1 ( i ) w 1 + x 2 ( i ) w 2 + b − y ( i ) ) 2\ell(w_1, w_2, b) =\frac{1}{n}\sum_{i=1}^n\frac{1}{2}\left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right)^2 ℓ(w1​,w2​,b)=n1​i=1∑n​21​(x1(i)​w1​+x2(i)​w2​+b−y(i))2
例として、w 1,w 2 w_1, w_2 w 1,w 2は重みパラメータ,b b bは偏差パラメータ,サンプルi i iの入力はx 1(i),x 2(i)x_1^{(i)}, x_2^{(i)}x 1(i),x 2(i),ラベルはy(i)y^{(i)}y(i),サンプル数はn n nである.重みパラメータをベクトルw=[w 1,w 2]boldsymbol{w}=[w_1,w_2]w=[w 1,w 2]でL 2 L_2 L 2ノルムペナルティ項の新しい損失関数は
ℓ ( w 1 , w 2 , b ) + λ 2 n ∥ w ∥ 2 ,\ell(w_1, w_2, b) +\frac{\lambda}{2n}\|\boldsymbol{w}\|^2, ℓ(w1​,w2​,b)+2nλ​∥w∥2,
スーパーパラメータλ > 0\lambda > 0 λ>0.ウェイトパラメータが0の場合、ペナルティアイテムは最小です.当λ\lambda λ大きな場合、ペナルティアイテムは損失関数に大きな比重を持ち、通常、学習したウェイトパラメータの要素を0に近づけます.当λ\lambda λ0に設定した場合、ペナルティはまったく機能しません.上式中L 2 L_2 L 2ノルム平方‖w‖2|boldsymbol{w}|^2‖w‖2展開後w 1 2+w 2 w_を得る1^2 + w_2^2 w12​+w22​.L 2 L_があった2 L 2ノルムペナルティ後,小ロットランダム勾配降下において,一節における重みw 1 w_に線形回帰する.1 w 1とw 2 w_2 w 2の反復方式が
w 1 ← ( 1 − η λ ∣ B ∣ ) w 1 − η ∣ B ∣ ∑ i ∈ B x 1 ( i ) ( x 1 ( i ) w 1 + x 2 ( i ) w 2 + b − y ( i ) ) , w 2 ← ( 1 − η λ ∣ B ∣ ) w 2 − η ∣ B ∣ ∑ i ∈ B x 2 ( i ) ( x 1 ( i ) w 1 + x 2 ( i ) w 2 + b − y ( i ) ) .\begin{aligned} w_1 &\leftarrow\left(1-\frac{\eta\lambda}{|\mathcal{B}|}\right)w_1 -\frac{\eta}{|\mathcal{B}|}\sum_{i\in\mathcal{B}}x_1^{(i)}\left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right),\\w_2 &\leftarrow\left(1-\frac{\eta\lambda}{|\mathcal{B}|}\right)w_2 -\frac{\eta}{|\mathcal{B}|}\sum_{i\in\mathcal{B}}x_2^{(i)}\left(x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}\right).\end{aligned} w1​w2​​←(1−∣B∣ηλ​)w1​−∣B∣η​i∈B∑​x1(i)​(x1(i)​w1​+x2(i)​w2​+b−y(i)),←(1−∣B∣ηλ​)w2​−∣B∣η​i∈B∑​x2(i)​(x1(i)​w1​+x2(i)​w2​+b−y(i)).​
L 2 L_2 L 2ノルム正規化重みw 1 w_1 w 1とw 2 w_2 w 2は、まず1未満の数を自乗し、罰項を含まない勾配を減算する.よって、L 2 L_2 L 2ノルム正規化は重み減衰とも呼ばれる.ウェイト減衰は,絶対値の大きいモデルパラメータを罰することによって学習が必要なモデルに制限を加え,これはオーバーフィットに有効である可能性がある.実際のシーンでは、罰項目に偏差要素の二乗和を追加することもあります.
高次元線形回帰実験
次に,高次元線形回帰を例に過フィッティング問題を導入し,過フィッティングに対応するために重み減衰を用いた.データサンプルフィーチャーの次元をp p pとする.トレーニングデータセットおよびテストデータセットの特徴はx 1,x 2,...,x p x_1, x_2,\ldots, x_px 1,x 2,...,xpのいずれかのサンプルは、次の線形関数を使用してサンプルのラベルを生成します.
y = 0.05 + ∑ i = 1 p 0.01 x i + ϵ y = 0.05 +\sum_{i = 1}^p 0.01x_i +\epsilon y=0.05+i=1∑p​0.01xi​+ϵ
ノイズこうもくϵ\epsilon ϵ平均値0、標準差0.01の正規分布に従う.フィッティングを容易に観察するために,次元p=200 p=200 p=200 p=200を設定するなど,高次元線形回帰問題を考慮した.また,訓練データセットのサンプル数を特に20のように低く設定した.
%matplotlib inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append("..") 
import d2lzh_pytorch as d2l

n_train, n_test, num_inputs = 20, 100, 200
true_w, true_b = torch.ones(num_inputs, 1) * 0.01, 0.05

features = torch.randn((n_train + n_test, num_inputs))
labels = torch.matmul(features, true_w) + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)
train_features, test_features = features[:n_train, :], features[n_train:, :]
train_labels, test_labels = labels[:n_train], labels[n_train:]

ゼロから実現
まず、ゼロからウェイト減衰を実現する方法について説明します.ターゲット関数の後にL 2 L_を追加することで2 L 2ノルムペナルティ項は、重み減衰を達成するために使用される.
モデルパラメータの初期化
まず、モデルパラメータをランダムに初期化する関数を定義します.この関数は各パラメータに勾配を付けます.
def init_params():
    w = torch.randn((num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]

L 2 L_の定義2 L 2ノルムペナルティ
以下、L 2 L_を定義する2 L 2範数罰則項.ここでは、モデルのウェイトパラメータのみが罰せられます.
def l2_penalty(w):
    return (w**2).sum() / 2

トレーニングとテストの定義
次に、トレーニングデータセットとテストデータセットでモデルをそれぞれトレーニングおよびテストする方法を定義します.前述の節とは異なり,ここでは最終的な損失関数を計算する際にL 2 L_を追加した.2 L 2範数罰則項.
batch_size, num_epochs, lr = 1, 100, 0.003
net, loss = d2l.linreg, d2l.squared_loss

dataset = torch.utils.data.TensorDataset(train_features, train_labels)
train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=True)

def fit_and_plot(lambd):
    w, b = init_params()
    train_ls, test_ls = [], []
    for _ in range(num_epochs):
        for X, y in train_iter:
            #    L2     
            l = loss(net(X, w, b), y) + lambd * l2_penalty(w)
            l = l.sum()
            
            if w.grad is not None:
                w.grad.data.zero_()
                b.grad.data.zero_()
            l.backward()
            d2l.sgd([w, b], lr, batch_size)
        train_ls.append(loss(net(train_features, w, b), train_labels).mean().item())
        test_ls.append(loss(net(test_features, w, b), test_labels).mean().item())
    d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
                 range(1, num_epochs + 1), test_ls, ['train', 'test'])
    print('L2 norm of w:', w.norm().item())

フィッティングを観察
次に,高次元線形回帰モデルを訓練し,テストした.lambdを0に設定すると、ウェイト減衰は使用されません.その結果,訓練誤差は試験セット上の誤差よりはるかに小さい.これは典型的なオーバーフィット現象である.
fit_and_plot(lambd=0)

出力:
L2 norm of w: 15.114808082580566

ウェイトフォールオフの使用(Use Weight Falloff)
次に、ウェイト減衰(Weight Attenuation)を使用します.訓練誤差は向上したが,テストセットでの誤差は低下したことがわかる.オーバーフィット現象はある程度緩和された.また、重みパラメータのL 2 L_2 L 2ノルムは、ウェイト減衰を使用しない場合よりも小さく、このときのウェイトパラメータは0に近い.
fit_and_plot(lambd=3)

出力:
L2 norm of w: 0.035220853984355927

シンプルな実装
ここでは、オプティマイザインスタンスを構築する際に、weight_decayパラメータによって重み減衰スーパーパラメータを直接指定します.デフォルトでは、PyTorchは重みと偏差を同時に減衰します.ウェイトと偏差のそれぞれに対してオプティマイザインスタンスを構築し,ウェイトのみを減衰させることができる.
def fit_and_plot_pytorch(wd):
    #        。        weight  
    net = nn.Linear(num_inputs, 1)
    nn.init.normal_(net.weight, mean=0, std=1)
    nn.init.normal_(net.bias, mean=0, std=1)
    optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr, weight_decay=wd) #        
    optimizer_b = torch.optim.SGD(params=[net.bias], lr=lr)  #         
    
    train_ls, test_ls = [], []
    for _ in range(num_epochs):
        for X, y in train_iter:
            l = loss(net(X), y).mean()
            optimizer_w.zero_grad()
            optimizer_b.zero_grad()
            
            l.backward()
            
            #    optimizer      step  ,           
            optimizer_w.step()
            optimizer_b.step()
        train_ls.append(loss(net(train_features), train_labels).mean().item())
        test_ls.append(loss(net(test_features), test_labels).mean().item())
    d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
                 range(1, num_epochs + 1), test_ls, ['train', 'test'])
    print('L2 norm of w:', net.weight.data.norm().item())

ゼロから重み減衰を実現する実験現象と同様に,重み減衰を用いてオーバーフィット問題をある程度緩和できた.
fit_and_plot_pytorch(0)

出力:
L2 norm of w: 12.86785888671875
fit_and_plot_pytorch(3)

出力:
L2 norm of w: 0.09631537646055222

小結
  • 正規化はモデル損失関数にペナルティ項目を追加することによって学習したモデルパラメータ値を小さくし,過フィッティングに対応する常用手段である.
  • 重み減衰はL 2 L_に等しい2 L 2ノルムは正規化され、通常は学習した重みパラメータの要素を0に近づけます.
  • 重み減衰は、オプティマイザのweight_decayスーパーパラメータによって指定できます.
  • は、異なるモデルパラメータに対して異なる反復法を使用する複数のオプティマイザインスタンスを定義することができる.