web-dev-qa-db-ja.com

nn。ドロップアウトvs. F.ドロップアウトpyTorch

PyTorchを使用すると、torch.nn.Dropouttorch.nn.F.Dropoutをドロップアウトする2つの方法があります。

それらの使用の違いを見つけるのに苦労しています
-何を使用するか?
-違いはありますか?
切り替えたときにパフォーマンスの違いは見られません。

21
CutePoison

技術的な違いは、もう一方の回答ですでに示されています。ただし、主な違いは、nn.Dropoutはトーチモジュール自体であり、利便性があることです。

いくつかの違いを説明する短い例:

import torch
import torch.nn as nn

class Model1(nn.Module):
    # Model 1 using functional dropout
    def __init__(self, p=0.0):
        super().__init__()
        self.p = p

    def forward(self, inputs):
        return nn.functional.dropout(inputs, p=self.p, training=True)

class Model2(nn.Module):
    # Model 2 using dropout module
    def __init__(self, p=0.0):
        super().__init__()
        self.drop_layer = nn.Dropout(p=p)

    def forward(self, inputs):
        return self.drop_layer(inputs)
model1 = Model1(p=0.5) # functional dropout 
model2 = Model2(p=0.5) # dropout module

# creating inputs
inputs = torch.Rand(10)
# forwarding inputs in train mode
print('Normal (train) model:')
print('Model 1', model1(inputs))
print('Model 2', model2(inputs))
print()

# switching to eval mode
model1.eval()
model2.eval()

# forwarding inputs in evaluation mode
print('Evaluation mode:')
print('Model 1', model1(inputs))
print('Model 2', model2(inputs))
# show model summary
print('Print summary:')
print(model1)
print(model2)

出力:

Normal (train) model:
Model 1 tensor([ 1.5040,  0.0000,  0.0000,  0.8563,  0.0000,  0.0000,  1.5951,
         0.0000,  0.0000,  0.0946])
Model 2 tensor([ 0.0000,  0.3713,  1.9303,  0.0000,  0.0000,  0.3574,  0.0000,
         1.1273,  1.5818,  0.0946])

Evaluation mode:
Model 1 tensor([ 0.0000,  0.3713,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,
         0.0000,  0.0000,  0.0000])
Model 2 tensor([ 0.7520,  0.1857,  0.9651,  0.4281,  0.7883,  0.1787,  0.7975,
         0.5636,  0.7909,  0.0473])
Print summary:
Model1()
Model2(
  (drop_layer): Dropout(p=0.5)
)

だからどちらを使うべきですか?

ドロップアウトの適用に関しては両方とも完全に同等であり、使用法の違いはそれほど大きくはありませんが、nn.Dropoutよりもnn.functional.dropoutを優先する理由がいくつかあります。

ドロップアウトはトレーニング中にのみ適用されるように設計されているため、モデルの予測または評価を行う場合、ドロップアウトをオフにする必要があります。

ドロップアウトモジュールnn.Dropoutはこれを便利に処理し、モデルが評価モードに入るとすぐにドロップアウトをシャットオフしますが、機能的なドロップアウトは評価/予測モードを気にしません。

canで機能ドロップアウトをtraining=Falseに設定して無効にしても、nn.Dropoutのような便利な解決策ではありません。

また、ドロップ率はモジュールに保存されるため、追加の変数に保存する必要はありません。大規模なネットワークでは、異なるドロップレートで異なるドロップアウトレイヤーを作成する必要がある場合があります-ここでnn.Dropoutは読みやすさを向上させ、レイヤーを複数回使用する場合にも便利です。

最後に、モデルに割り当てられているすべてのモジュールがモデルに登録されます。したがって、モデルクラスはそれらを追跡します。そのため、eval()を呼び出してドロップアウトモジュールをオフにすることができます。機能的ドロップアウトを使用する場合、モデルはそれを認識しないため、サマリーには表示されません。

22
blue-phoenox

nn.Dropout および Functional.Dropout のソースコードを見ると、Functionalがインターフェイスであり、nnモジュールが関数を実装していることがわかります。このインターフェイスに関して。
nnクラスの実装を見てください:

from .. import functional as F
class Dropout(_DropoutNd):
    def forward(self, input):
        return F.dropout(input, self.p, self.training, self.inplace)

class Dropout2d(_DropoutNd):
    def forward(self, input):
        return F.dropout2d(input, self.p, self.training, self.inplace)

等々。

Functionalクラスの実装:

def dropout(input, p=0.5, training=False, inplace=False):
    return _functions.dropout.Dropout.apply(input, p, training, inplace)

def dropout2d(input, p=0.5, training=False, inplace=False):
    return _functions.dropout.FeatureDropout.apply(input, p, training, inplace)

以下の例を見て理解してください。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(320, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 320)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x)

forward()関数にはF.dropoutがあり、__init__()関数にはnn.Dropoutがあります。これが説明です:

PyTorchでは、モデルをtorch.nn.Moduleのサブクラスとして定義します。

init関数では、使用するレイヤーを初期化することになっています。ケラスとは異なり、Pytorchはより低レベルになり、すべてが一致するようにネットワークのサイズを指定する必要があります。

Forwardメソッドでは、レイヤーの接続を指定します。これは、作成したデータの転送パスごとに同じレイヤーを再利用するために、既に初期化したレイヤーを使用することを意味します。

torch.nn.Functionalには、使用可能な畳み込み操作であるアクティベーション関数などの便利な関数が含まれています。ただし、これらは完全なレイヤーではないため、任意の種類のレイヤーを指定する場合は、torch.nn.Moduleを使用する必要があります。

Torch.nn.Functional conv操作を使用して、たとえば畳み込み操作でカスタムレイヤーを定義しますが、標準の畳み込みレイヤーは定義しません。

2

torch.nn.functionalの実装を確認します。

 if p < 0. or p > 1.:
        raise ValueError("dropout probability has to be between 0 and 1, "
                         "but got {}".format(p))
    return (_VF.dropout_(input, p, training)
            if inplace
            else _VF.dropout(input, p, training))

チェック:torch.nn.dropoutの実装:

def forward(self, input):
        return F.dropout(input, self.p, self.training, self.inplace)

そのため、内部操作は同じです。インターフェイスは異なります。 _VFに関しては、C/C++コードだと思います。

0
Jiapeng Zhang