[バナキュラー機械学習シリーズ] バナキュラードロップアウト

バナキュラードロップアウト

ここに画像の説明を挿入

ドロップアウトとは何ですか

ドロップアウトは、指定された確率ppでトレーニングされるニューラル ネットワークの正則化手法です。p (一般的な値はp = 0.5 p=0.5p=0.5 ) ユニットを (接続とともに) 破棄します。テスト時にはすべての単位が存在しますが、重みはpppスケーリング (つまり、pw pw.pw)。

この考えは、ニューラル ネットワークが特定の接続に過度に依存する共適応を防ぐことです。これは過剰学習の症状である可能性があるためです。直観的には、ドロップアウトは、隠れたニューラル ネットワークのアンサンブルを作成するものと考えることができます。

この定義によれば、PyTorch は「確率ppnn.Dropoutのベルヌーイ分布からのサンプルを使用します」p は、入力テンソルのいくつかの要素をランダムにゼロにします。各チャネルは、通話が転送されるたびに独立してゼロに設定されます。

ドロップアウトは、与えられた確率ppと考えることができます。p は、入力テンソルの一部の要素をゼロにランダム化します。これが発生すると、出力の一部が失われます。これを考慮して、出力も1 1 − p \frac{1}{1-p}1 p1

スケーリングにより、入力平均と出力平均がほぼ等しくなります。

ズームを理解する

多くの人は、ドロップアウト層が入力をスケーリングする方法と理由について混乱しているかもしれません。詳細な説明は次のとおりです。

PyTorch の公式ドキュメントには次のように記載されています。

また、トレーニング中の出力は1 1 − p \frac{1}{1-p}です。1 p1スケーリング。これは、評価時にモジュールが恒等関数を計算するだけであることを意味します。

では、これはどのように行われるのでしょうか? どうしてそれをするの?Pytorch のコードを見てみましょう。

ドロップ率を作成するp = 0.4 p=0.4p=0.4のドロップアウト層m:

import torch
import numpy as np
p = 0.4
m = torch.nn.Dropout(p)

PyTorch のドキュメントでは次のように説明されています。

トレーニング中に、ベルヌーイ分布からのサンプルが確率ppで使用されます。p は、入力テンソルのいくつかの要素をランダムにゼロにします。ゼロ化された要素は、転送呼び出しごとにランダム化されます。

ドロップアウト層にランダム入力を入れて約40%を確認( p = 0.4 p=0.4p=0.4 ) 要素が 0 になりました。

nbig = 5000000
inp = torch.rand(nbig, 10)
outp = m(inp)
print(f'输入中0元素的比例为: {
      
      (outp==0).numpy().mean():.5f}, p={
      
      p}')

上記のコードを実行した後の出力:

$ 输入中0元素的比例为: 0.40007, p=0.4

スケーリングの部分に移りましょう。

小さなランダム入力を作成し、それをドロップアウト層に置きます。入力と出力を比較します。

np.random.seed(42)
inp = torch.rand(5, 4)
inp

上記のコードは 5 行 4 列のランダム テンソルを作成し、出力は次のようになります。

$ tensor([[0.6485, 0.3114, 0.1626, 0.1022],
          [0.7352, 0.4634, 0.8206, 0.4228],
          [0.0322, 0.9399, 0.9163, 0.4169],
          [0.2574, 0.0467, 0.2213, 0.6171],
          [0.4146, 0.2288, 0.0388, 0.7752]])

以下の 2 つのテンソルの非ゼロ要素を比較すると、トレーニング中の出力は1 1 − p \frac{1}{1-p}であることがわかります。1 p1ズーム時間:

outp = m(inp)
inp/(1-p)
$ tensor([[1.0808, 0.5191, 0.2710, 0.1703],
          [1.2254, 0.7723, 1.3676, 0.7046],
          [0.0537, 1.5665, 1.5272, 0.6948],
          [0.4290, 0.0778, 0.3689, 1.0284],
          [0.6909, 0.3813, 0.0646, 1.2920]])

出力output

$ tensor([[1.0808, 0.5191, 0.2710, 0.0000],
          [0.0000, 0.7723, 0.0000, 0.0000],
          [0.0000, 1.5665, 1.5272, 0.6948],
          [0.4290, 0.0778, 0.3689, 1.0284],
          [0.6909, 0.0000, 0.0646, 0.0000]])

この観察結果をコードで主張できます。

idx_nonzero = outp!=0
assert np.allclose(outp[idx_nonzero].numpy(), (inp/(1-p))[idx_nonzero].numpy())

では、なぜそれをするのでしょうか?

基本的に、ドロップアウト層は恒等関数となり、評価/テスト/推論中に入力を変更しません。Dropout はトレーニング中にのみアクティブになり、スケーリングを行わない推論中はアクティブではないため、要素がランダムにドロップされなくなる (0 に設定される) ため、予想される出力は推論中に大きくなります。ただし、ドロップアウト層を通過するかどうかに関係なく、期待される出力が同じであることが必要です。したがって、トレーニング中にドロップアウト層の出力を1 1 − p \frac{1}{1−p}で増幅します。1 p1補正するスケール係数。pppが大きいほど、ドロップアウトがより積極的であることを意味します。つまり、より多くの補正、つまりスケーリング係数1 1 − p \frac{1}{1−p}1 p1より大きい。

以下のコードは、スケール係数によって出力が入力と同じスケールにどのように復元されるかを示しています。

inp = torch.rand(nbig, 10)
outp = m(inp)
print(f'dropout 层的平均输出 ({
      
      outp.mean():.4f}) 接近平均输入 ({
      
      inp.mean():.4f})')
$ dropout 层的平均输出 (0.5000) 接近平均输入 (0.5000)

例えば

100 個のテンソルを使用した例を使用して、ドロップアウトとそのスケーリングが入力にどのような影響を与えるかを示します。

import torch
import torch.nn as nn

# 生成 100 个 1
x = torch.ones(100) 
$ tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
          1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
          1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
          1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
          1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
          1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

ドロップ率p = 0.1 の場合 p = 0.1p=0.1、約 10 個の値を 0 に設定する必要があります。スケーリング係数は
1 1 − 0.1 = 1 0.9 = 1.1 ˙ \frac{1}{1-0.1} = \frac{1}{0.9} = 1.\dot{1} です。10.11=0.91=1.1˙

# 输入 Dropout 层
output = nn.Dropout(p=0.1)(x)     
$ tensor([1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 0.0000, 0.0000, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111, 1.1111, 0.0000, 0.0000,
         1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 1.1111,
         1.1111, 1.1111, 1.1111, 1.1111, 1.1111, 0.0000, 1.1111, 1.1111, 1.1111,
         1.1111])

結果は予想どおりで、10 個の値が完全にゼロになり、入力と出力の平均が同じになるように、または可能な限り近い値になるように結果がスケーリングされました。

print(x.mean(), output.mean())
$ tensor(1.) tensor(1.0000)

この例では、入力と出力の平均は 1.0 です。

おすすめ

転載: blog.csdn.net/jarodyv/article/details/131287713