딥러닝이란 하나의 레고(layer)를 정의한 후 이 블럭을 쌓아 올리는 구조라고 이해할 수 있다.
딥러닝을 구성하는 Layer의 base class는 torch.nn.Module
이다.
input
, output
, forward
, backward
(autograd) 정의한다.
학습이 대상이 되는 parameter(tensor)로 정의한다.
Tensor 객체의 상속 객체
nn.Module
내에 attribute가 될 때는 requred_grad = True
로 지정되어 학습 대상이 되는 Tensor가 된다.
우리가 직접 지정할 일은 없지만 기본적인 구성은 아래와 같다.
class MyLinear(nn.Module):
def __init__(self, in_f, out_f):
super().__init__()
self.in_f = in_f
self.out_f = out_f
self.weights = nn.Parameter(
torch.randn(in_f, out_f)
)
self.bias = nn.Parameter(
torch.randn(out_f)
)
def forward(self, x: Tensor):
return x @ self.weights + self.bias
Backward시 Layer에 있는 Parameter들의 미분을 수행한다.
Forward의 결과값(예측치)과 실제값간의 차이(loss)에 대한 미분을 수행한다.
해당값으로 Parameter를 업데이트한다.
optimizer.zero_grad()의 의미
이전의 기울기 값이 현재 영향을 주지 않기 위해 초기화 시키는 코드
실제 backward는 Module단계에서 직접 지정가능하다. 하지만 AutoGrad기능으로 자동으로 해주기 때문에 해줄 필요가 없다.
Module에서 backward와 optimizer 오버라이딩이 가능하다.
사용자가 직접 미분 수식을 써야하는 부담이 있지만 순서에 대해선 이해할 필요가 있다.
class LR(nn.Module):
def __init__(self, dim, lr=torch.scalar_tensor(0.01)):
super(LR, self).__init__()
# intialize parameters
self.w = torch.zeros(dim, 1, dtype=torch.float).to(device)
self.b = torch.scalar_tensor(0).to(device)
self.grads = {"dw": torch.zeros(dim, 1, dtype=torch.float).to(device),
"db": torch.scalar_tensor(0).to(device)}
self.lr = lr.to(device)
def forward(self, x):
## compute forward
z = torch.mm(self.w.T, x) + self.b
a = self.sigmoid(z)
return a
def sigmoid(self, z):
return 1/(1 + torch.exp(-z))
def backward(self, x, yhat, y):
## compute backward
self.grads["dw"] = (1/x.shape[1]) * torch.mm(x, (yhat - y).T)
self.grads["db"] = (1/x.shape[1]) * torch.sum(yhat - y)
def optimize(self):
## optimization step
self.w = self.w - self.lr * self.grads["dw"]
self.b = self.b - self.lr * self.grads["db"]
위의 코드는 pytorch를 쓰지 않고 직접 Logistic Regression을 구현한 것이다.
pytorch를 사용하면 위 처럼 밑단을 구현할 필요는 없지만 어떤식으로 동작하는지는 알아야 할 필요가 있다.