PyTorch:Train 和 Test/Validation 的不同转发方法
PyTorch: Different Forward Methods for Train and Test/Validation
我目前正在尝试扩展基于 FairSeq/PyTorch 的 a model。在训练期间,我需要训练两个编码器:一个使用目标样本,另一个使用源样本。
所以当前的前向函数是这样的:
def forward(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
decoder_out = self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
return decoder_out
基于这个 this idea 我想要这样的东西:
def forward_test(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
decoder_out = self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
return decoder_out
def forward_train(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
autoencoder_out = self.encoder(tgt_tokens, src_lengths=src_lengths, **kwargs)
concat = some_concatination_func(encoder_out, autoencoder_out)
decoder_out = self.decoder(prev_output_tokens, encoder_out=concat, **kwargs)
return decoder_out
有什么办法吗?
编辑:
这些是我的限制,因为我需要扩展 FairseqEncoderDecoderModel:
@register_model('transformer_mass')
class TransformerMASSModel(FairseqEncoderDecoderModel):
def __init__(self, encoder, decoder):
super().__init__(encoder, decoder)
编辑 2:
传递给 Fairseq 中前向函数的参数可以通过实现您自己的 Criterion 来改变,例如参见 [=19=],其中 sample['net_input']
被传递给模型的 __call__
函数,它调用forward
方法。
默认情况下,调用 model()
调用 forward
方法,这在您的案例中是向前训练的,因此您只需要为模型中的 test/eval 路径定义新方法 class,像这里一样:
代码:
class FooBar(nn.Module):
"""Dummy Net for testing/debugging.
"""
def __init__(self):
super().__init__()
...
def forward(self, x):
# here will be train forward
...
def evaltest(self, x):
# here will be eval/test forward
...
示例:
model = FooBar() # initialize model
# train time
pred = model(x) # calls forward() method under the hood
# test/eval time
test_pred = model.evaltest(x)
评论:
我想推荐你把这两条前向路径拆分成两个独立的方法,因为这样更容易调试,也可以避免反向传播时可能出现的一些问题。
首先,您应该始终使用和定义forward
,而不是您在torch.nn.Module
实例上调用的其他方法。
绝对不要重载 eval()
,如 as it's evaluation method defined by PyTorch (see here 所示。 此方法允许将模型中的层置于评估模式(例如特定Dropout
或 BatchNorm
).
等层的推理模式更改
此外,您应该使用 __call__
魔术方法调用它。为什么?因为挂钩和其他 PyTorch 特定的东西是正确注册的。
其次,不要使用 建议的一些外部mode
字符串变量。这就是 PyTorch 中 train
变量的用途,通过它来区分模型是处于 eval
模式还是 train
模式是标准的。
话虽这么说,你最好这样做:
import torch
class Network(torch.nn.Module):
def __init__(self):
super().__init__()
...
# You could split it into two functions but both should be called by forward
def forward(
self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs
):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
if self.train:
return self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
autoencoder_out = self.encoder(tgt_tokens, src_lengths=src_lengths, **kwargs)
concat = some_concatination_func(encoder_out, autoencoder_out)
return self.decoder(prev_output_tokens, encoder_out=concat, **kwargs)
您可以(并且可以说应该)将上面的方法拆分为两个单独的方法,但这并不算太糟糕,因为该函数相当短且可读性强。如果可能的话,只要坚持使用 PyTorch 的处理方式,而不是一些临时解决方案。而且不,反向传播不会有问题,为什么会有一个?
我目前正在尝试扩展基于 FairSeq/PyTorch 的 a model。在训练期间,我需要训练两个编码器:一个使用目标样本,另一个使用源样本。
所以当前的前向函数是这样的:
def forward(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
decoder_out = self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
return decoder_out
基于这个 this idea 我想要这样的东西:
def forward_test(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
decoder_out = self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
return decoder_out
def forward_train(self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
autoencoder_out = self.encoder(tgt_tokens, src_lengths=src_lengths, **kwargs)
concat = some_concatination_func(encoder_out, autoencoder_out)
decoder_out = self.decoder(prev_output_tokens, encoder_out=concat, **kwargs)
return decoder_out
有什么办法吗?
编辑: 这些是我的限制,因为我需要扩展 FairseqEncoderDecoderModel:
@register_model('transformer_mass')
class TransformerMASSModel(FairseqEncoderDecoderModel):
def __init__(self, encoder, decoder):
super().__init__(encoder, decoder)
编辑 2:
传递给 Fairseq 中前向函数的参数可以通过实现您自己的 Criterion 来改变,例如参见 [=19=],其中 sample['net_input']
被传递给模型的 __call__
函数,它调用forward
方法。
默认情况下,调用 model()
调用 forward
方法,这在您的案例中是向前训练的,因此您只需要为模型中的 test/eval 路径定义新方法 class,像这里一样:
代码:
class FooBar(nn.Module):
"""Dummy Net for testing/debugging.
"""
def __init__(self):
super().__init__()
...
def forward(self, x):
# here will be train forward
...
def evaltest(self, x):
# here will be eval/test forward
...
示例:
model = FooBar() # initialize model
# train time
pred = model(x) # calls forward() method under the hood
# test/eval time
test_pred = model.evaltest(x)
评论: 我想推荐你把这两条前向路径拆分成两个独立的方法,因为这样更容易调试,也可以避免反向传播时可能出现的一些问题。
首先,您应该始终使用和定义forward
,而不是您在torch.nn.Module
实例上调用的其他方法。
绝对不要重载 eval()
,如 Dropout
或 BatchNorm
).
此外,您应该使用 __call__
魔术方法调用它。为什么?因为挂钩和其他 PyTorch 特定的东西是正确注册的。
其次,不要使用mode
字符串变量。这就是 PyTorch 中 train
变量的用途,通过它来区分模型是处于 eval
模式还是 train
模式是标准的。
话虽这么说,你最好这样做:
import torch
class Network(torch.nn.Module):
def __init__(self):
super().__init__()
...
# You could split it into two functions but both should be called by forward
def forward(
self, src_tokens=None, src_lengths=None, prev_output_tokens=None, **kwargs
):
encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs)
if self.train:
return self.decoder(prev_output_tokens, encoder_out=encoder_out, **kwargs)
autoencoder_out = self.encoder(tgt_tokens, src_lengths=src_lengths, **kwargs)
concat = some_concatination_func(encoder_out, autoencoder_out)
return self.decoder(prev_output_tokens, encoder_out=concat, **kwargs)
您可以(并且可以说应该)将上面的方法拆分为两个单独的方法,但这并不算太糟糕,因为该函数相当短且可读性强。如果可能的话,只要坚持使用 PyTorch 的处理方式,而不是一些临时解决方案。而且不,反向传播不会有问题,为什么会有一个?