코드를 짤 때 torch.nn 과 torch.nn.functional 이 있는것은 알았지만 평소에는 nn.Conv2d를 이용해 CNN layer를 쌓는다. 그런데 torch.nn.functional에서도 conv2d가 있어서 궁금해서 차이를 알아보았다.
nn.Conv2d 와 nn.functional.conv2d 에 제일 큰 차이는 weight이다. F.conv2d (nn.functional을 편의상 F.conv2d라 부르겠다)에서 보면 input,weight을 입력으로 받는다. 또한, 다른 filter을 사용하여 weight을 따로 만들어 다른 weight을 적용해주는 기법이다. 예시로 Dynamic Region Aware Convolution [CVPR 2021] 논문에서도 input image에 따라 adaptive 하게 weight을 Feature module을 사용하여 생성한다.
위 그림은 convolution 연산이며 nn.conv2d 와 F.conv2d가 코드와 output에서 어떻게 차이가 나는지 보자.
import torch
import torch.nn.functional as F
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
input = torch.Tensor(np.array([[[
[0,1,0,1,0],
[0,1,0,0,1],
[0,1,0,1,1],
[1,0,1,1,1],
[0,0,1,0,0]
]]]))
input = Variable(input, requires_grad=True)
conv1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3,3))
print('conv1:', conv1)
print('conv1 weight:', conv1.weight)
output = conv1(input)
print(output)
weight이 매번 실행할때마다 바뀌기때문에 weight 출력을 따로 해주었으며 nn.Conv2d 는 weight을 따로 입력으로 안받기에 filter이 따로 없다.
conv1: Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1))
conv1 weight: Parameter containing:
tensor([[[[ 0.0674, -0.1552, 0.1951],
[-0.2577, -0.1085, 0.1606],
[-0.2145, -0.0488, -0.3306]]]], requires_grad=True)
tensor([[[[-0.4153, -0.6430, -0.4768],
[-0.9116, -0.5119, -0.4495],
[-0.6858, 0.1631, -0.4830]]]], grad_fn=<ThnnConv2DBackward>)
import torch
import torch.nn.functional as F
import torch.nn as nn
from torch.autograd import Variable
import numpy as np
input = torch.Tensor(np.array([[[
[0,1,0,1,0],
[0,1,0,0,1],
[0,1,0,1,1],
[1,0,1,1,1],
[0,0,1,0,0]
]]]))
input = Variable(input, requires_grad=True)
filter = torch.randn(1,1,3,3) # weight in this case.
filter = Variable(filter)
fconv1 = F.conv2d(input, filter, padding=0, bias=None)
print('fconv1 output', fconv1)
input과 filter (weight) 텐서를 random으로 뽑고 F.Conv2d로 연산한 결과이다.
fconv1 output tensor([[[[ 0.1745, 2.6804, 0.0466],
[ 1.2668, -0.1850, 2.2837],
[ 0.4173, 2.7320, 3.3201]]]], grad_fn=<ThnnConv2DBackward>)
F.Conv2d를 사용하게되면 filter (weight) 을 다양하게 사용할수있으며 만약에 nn.Conv2d랑 weight이 같다면 결과값도 같을 것 이다.
출처: