pytorch에서 자동으로 해주기는한다.
하지만 수동으로 parameter를 원하는대로 초기화해야하는 경우가 분명 발생한다. 이를 수동으로 해결하는 방법은 기본적으로 아래와 같다.
class MultiLayerPerceptronClass(nn.Module):
"""
Multilayer Perceptron (MLP) Class
"""
def __init__(self,name='mlp',xdim=784,hdim=256,ydim=10):
super(MultiLayerPerceptronClass,self).__init__()
self.name = name
self.xdim = xdim
self.hdim = hdim
self.ydim = ydim
self.lin_1 = nn.Linear(
# FILL IN HERE
)
self.lin_2 = nn.Linear(
# FILL IN HERE
)
self.init_param() # initialize parameters
def init_param(self):
nn.init.kaiming_normal_(self.lin_1.weight)
nn.init.zeros_(self.lin_1.bias)
nn.init.kaiming_normal_(self.lin_2.weight)
nn.init.zeros_(self.lin_2.bias)
def forward(self,x):
net = x
net = self.lin_1(net)
net = F.relu(net)
net = self.lin_2(net)
return net
M = MultiLayerPerceptronClass(name='mlp',xdim=784,hdim=256,ydim=10).to(device)
loss = nn.CrossEntropyLoss()
optm = optim.Adam(M.parameters(),lr=1e-3)
print ("Done.")
pytorch의 큰 장점은 session이 없다는 것이다. 물론 tf도 ver 2부터는 session이 없기는하다.
session이 없어서 아래처럼 바로 forward를 할 수 있다.
본래 forward를 쓰지 않아도 아래와 같이 알아서 forward를 해준다.
하지만 명시하는 것이 읽기에 편하니, 써보자.
x_numpy = np.random.rand(2,784)
x_torch = torch.from_numpy(x_numpy).float().to(device)
y_torch = M.forward(x_torch) # forward path
# y_torch = M(x_torch) # forward path
y_numpy = y_torch.detach().cpu().numpy() # torch tensor to numpy array
print ("x_numpy:\n",x_numpy)
print ("x_torch:\n",x_torch)
print ("y_torch:\n",y_torch)
print ("y_numpy:\n",y_numpy)
애매하게 알고 썻던 내용인데 정리해본다.
BatchNormalization이나 DropOut 같이 학습 시에만 사용되고 predict 단계에서는 사용하면 안되는 것들이 있다. 이런 부분들을 막기 위해서 predict시에는 반드시 model.eval() 사용하는 것을 관례처럼 여기자.
원소의 수를 유지하면서 tensor의 차원을 바꿔주는 함수. numpy의 reshape이다.
차원에 -1을 넣어주면 pytorch가 알아서 설정하도록 하는 것이다.
batch_in.view(-1, 28*28)
tensor는 모두 tensor라는 객체로써 관리된다. 이를 실수와 같은 형태로 바꾸고 싶다면 item을 사용한다.
n_correct += (y_pred==y_trgt).sum().item()
print ("Start training.")
M.init_param() # initialize parameters
M.train()
EPOCHS,print_every = 10,1
for epoch in range(EPOCHS):
loss_val_sum = 0
for batch_in,batch_out in train_iter:
# Forward path
y_pred = M.forward(batch_in.view(-1, 28*28).to(device))
loss_out = loss(y_pred,batch_out.to(device))
# Update
optm.zero_grad() # reset gradient
loss_out.backward() # backpropagate
optm.step() # optimizer update
loss_val_sum += loss_out
loss_val_avg = loss_val_sum/len(train_iter)
# Print
if ((epoch%print_every)==0) or (epoch==(EPOCHS-1)):
train_accr = func_eval(M,train_iter,device)
test_accr = func_eval(M,test_iter,device)
print ("epoch:[%d] loss:[%.3f] train_accr:[%.3f] test_accr:[%.3f]."%
(epoch,loss_val_avg,train_accr,test_accr))
print ("Done")
앞서 optim을 아래와 같이 정의하여 어떠한 parameter를 학습할지 정의했다.
optm = optim.Adam(M.parameters(),lr=1e-3)
zero_grad()를 통해 해당 paramter의 gradient를 0으로 초기화하는 함수이다.
앞서 cross entropy로 정의한 loss function을 의미한다. loss에 매개변수로 모델의 출력인 y_pred와 학습 데이터인 batch_out을 넘겨주면 이에 대한 weight 객체를 반환한다.
각각의 weight에 대한 backward propagation을 수행한다.
앞서 정의한 optimizer의 learning rate와 여러 다른 hyper parameter를 통해, 인자로 넘겨받았던 parameter를 업데이트한다.