在寫代碼時發現我們在定義Model時,有兩種定義方法:
torch.nn.Conv2d()和torch.nn.functional.conv2d()
那么這兩種方法到底有什么區別呢,我們通過下述代碼看出差別,先拿torch.nn.Conv2d
- torch.nn.Conv2d
class Conv2d(_ConvNd): def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros'): kernel_size = _pair(kernel_size) stride = _pair(stride) padding = _pair(padding) dilation = _pair(dilation) super(Conv2d, self).__init__( in_channels, out_channels, kernel_size, stride, padding, dilation, False, _pair(0), groups, bias, padding_mode) def forward(self, input): return self.conv2d_forward(input, self.weight)
- torch.nn.functional.conv2d
def conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1): if input is not None and input.dim() != 4: raise ValueError("Expected 4D tensor as input, got {}D tensor instead.".format(input.dim())) f = _ConvNd(_pair(stride), _pair(padding), _pair(dilation), False, _pair(0), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.deterministic,torch.backends.cudnn.enabled) return f(input, weight, bias)
對比上述代碼我們可以發現,torch.nn.Conv2d是一個類,而torch.nn.functiona.conv2d()是一個函數,並且torch.nn.Conv2d中的forward()函數
是由torch.nn.functiona.conv2d()實現的(在Module類中有一個__call__實現了forward的調用)所以他們在功能的使用上並沒有什么區別,但是我
們有了一個疑問,為什么要有着兩個功能一樣的方法呢?
其實主要的原因在乎我們構建計算圖的時候,有些操作不需要進行體現在計算圖中的,例如ReLu層,池化層。但是像卷積層、全連接層還是
需要體現在計算圖中的。如果所有的層我們都用torch.nn.functional來定義,那么我們需要將卷積層和全連接層中的weights、bias全部手動寫入
計算圖中去,這樣是非常不方便的。如果我們全部使用類的方式來構建計算圖,這樣即使是非常簡單的操作都需要構建類,這樣是寫代碼的效率是
非常低的。所以我們將卷積層、全連接層使用類的方式來進行定義,將池化和激活操作使用函數的方式進行使用,這樣使我們更方便的構建計算圖。