nn.Dropout против F.dropout pyTorch

С помощью pyTorch есть два способа отсева torch.nn.Dropout а также torch.nn.F.Dropout,

Я изо всех сил, чтобы увидеть разницу между их использованием
- когда использовать что?
- Есть ли разница?
Я не вижу разницы в производительности, когда я их переключил.

2 ответа

Решение

Технические различия уже были показаны в другом ответе. Однако главное отличие в том, что 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 удобно обрабатывает это и отключает выпадение, как только ваша модель переходит в режим оценки, в то время как функциональный выпад не заботится о режиме оценки / прогнозирования.

Даже если вы можете установить функциональный выпадение на training=False чтобы выключить его, это все еще не такое удобное решение, как с nn.Dropout,

Также в модуле хранится частота выпадения, поэтому вам не нужно сохранять ее в дополнительной переменной. В более крупных сетях вы можете захотеть создать разные слои отсева с разной частотой выпадения - здесь nn.Dropout может повысить удобочитаемость и может принести некоторое удобство при многократном использовании слоев.

Наконец, все модули, которые назначены для вашей модели, зарегистрированы в вашей модели. Итак, ваш модельный класс отслеживает их, поэтому вы можете просто отключить выпадающий модуль, вызвав eval(), При использовании функциональных выпадений ваша модель не знает об этом, поэтому она не будет отображаться ни в какой сводке.

Если вы посмотрите на исходный код 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)

E сть F.dropout в forward() функция и nn.Dropout в __init__() функция. Теперь это объяснение:

В PyTorch вы определяете свои Модели как подклассы torch.nn.Module.

В функции init вы должны инициализировать слои, которые хотите использовать. В отличие от keras, Pytorch выходит на более низкий уровень, и вам нужно указать размеры вашей сети, чтобы все совпадало.

В прямом методе вы указываете соединения ваших слоев. Это означает, что вы будете использовать уже инициализированные слои, чтобы повторно использовать один и тот же слой для каждого прямого прохода данных, который вы делаете.

torch.nn.Functional содержит некоторые полезные функции, такие как функции активации и операции свертки, которые вы можете использовать. Однако это не полные слои, поэтому, если вы хотите указать слой любого вида, вы должны использовать torch.nn.Module.

Вы должны использовать torch.nn.Functional conv операции, чтобы определить пользовательский уровень, например, с операцией свертки, но не определить стандартный слой свертки.

Проверьте 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++.

Другие вопросы по тегам