En utilisant pyTorch, il existe deux méthodes pour abandonner torch.nn.Dropout
et torch.nn.F.Dropout
.
J'ai du mal à voir la différence entre leur utilisation
- quand utiliser quoi?
- Est-ce que cela fait une différence?
Je ne vois aucune différence de performance lorsque je les ai permutées.
Les différences techniques ont déjà été montrées dans l'autre réponse. Cependant, la principale différence est que nn.Dropout
est un module de torche lui-même qui présente certaines commodités:
Un court exemple pour illustrer certaines différences:
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)
Sortie:
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)
)
Alors, que dois-je utiliser?
Les deux sont complètement équivalents en termes d’abandon et, même si les différences d’utilisation ne sont pas si grandes, il existe certaines raisons de favoriser le nn.Dropout
par rapport à nn.functional.dropout
:
Le décrochage est conçu pour ne s'appliquer que pendant la formation. Ainsi, lorsque vous effectuez des prédictions ou une évaluation du modèle, vous souhaitez désactiver le décrochage.
Le module de suppression nn.Dropout
gère cela de manière pratique et ferme la suppression dès que votre modèle passe en mode d'évaluation, tandis que la suppression fonctionnelle ne se préoccupe pas du mode d'évaluation/prévision.
Même si vous pouvez définir le décrochage fonctionnel sur training=False
pour l'éteindre, ce n'est toujours pas une solution aussi pratique que avec nn.Dropout
.
De plus, le taux de chute est stocké dans le module, vous n'avez donc pas besoin de l'enregistrer dans une variable supplémentaire. Dans les réseaux plus importants, vous pouvez créer différentes couches de suppression avec des taux de perte différents. Dans ce cas, nn.Dropout
peut améliorer la lisibilité et peut également s'avérer très pratique lorsque vous utilisez les couches plusieurs fois.
Enfin, tous les modules affectés à votre modèle sont enregistrés dans votre modèle. Donc, votre classe de modèle en garde trace, c'est pourquoi vous pouvez simplement désactiver le module de décrochage en appelant eval()
. Lorsque vous utilisez le décrochage fonctionnel, votre modèle n'en a pas connaissance. Il n'apparaîtra donc pas dans les résumés.
Si vous regardez le code source de nn.Dropout et Functional.Dropout , vous pouvez voir que Functional
est une interface et que nn
module implémente des fonctions. en ce qui concerne cette interface.
Regardez les implémentations dans la classe 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)
Etc.
Implémentation de la classe 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)
regardez l'exemple ci-dessous pour comprendre:
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)
Il existe une fonction F.dropout
dans forward()
et une fonction nn.Dropout
dans __init__()
. Maintenant, voici l'explication:
Dans PyTorch, vous définissez vos modèles en tant que sous-classes de torch.nn.Module.
Dans la fonction init , vous êtes censé initialiser les calques que vous souhaitez utiliser. Contrairement aux keras, Pytorch va plus bas niveau et vous devez spécifier les tailles de votre réseau pour que tout corresponde.
Dans la méthode de transfert, vous spécifiez les connexions de vos couches. Cela signifie que vous utiliserez les couches que vous avez déjà initialisées afin de réutiliser la même couche pour chaque transfert de données en avant.
torch.nn.Functional contient des fonctions utiles, telles que les fonctions d’activation et les opérations de convolution que vous pouvez utiliser. Cependant, ce ne sont pas des calques complets. Par conséquent, si vous souhaitez spécifier un calque, utilisez plutôt torch.nn.Module.
Vous utiliseriez les opérations torch.nn.Functional conv pour définir un calque personnalisé, par exemple avec une opération de convolution, mais pas pour définir un calque de convolution standard.
Vérifiez l'implémentation de 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))
Vérifiez: la mise en œuvre de torch.nn.dropout
:
def forward(self, input):
return F.dropout(input, self.p, self.training, self.inplace)
Donc: leur fonctionnement interne est le même. Les interfaces sont différentes. En ce qui concerne _VF
, je suppose que c'est du code C/C++.