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++.