PyTorch Implementation

Simple version

가장 일반적인 파이토치 구현 방법으로 케라스된 예제 1-1을 변환한다.


In [1]:
import torch
import numpy as np

x = np.array([0, 1, 2, 3, 4]).astype('float32').reshape(-1,1) 
y = x * 2 + 1

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        self.layer = torch.nn.Linear(1,1)
    def forward(self, x):
        return self.layer(x)
model = Model()
Optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(1000):
    x_tr = torch.from_numpy(x[:2,:1]).type(torch.FloatTensor)
    y_tr = torch.from_numpy(y[:2,:1]).type(torch.FloatTensor)
    y_pr = model(x_tr)
    loss = torch.pow(torch.abs(y_tr - y_pr),2)
    Optimizer.zero_grad()
    torch.sum(loss).backward()
    Optimizer.step()
print(model(torch.from_numpy(x).type(torch.FloatTensor)).detach().numpy())


[[1.0002644]
 [2.999837 ]
 [4.999409 ]
 [6.9989815]
 [8.998554 ]]

Detail version with monitoring variables

파이토치로 변환된 코드가 제대로 동작하는지 중간 중간을 모니터링 한다.


In [2]:
import torch
import numpy as np

x = np.array([0, 1, 2, 3, 4]).astype('float32').reshape(-1,1) 
y = x * 2 + 1

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        self.layer = torch.nn.Linear(1,1)
    def forward(self, x):
        return self.layer(x)
model = Model()
Optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

print('w=', list(model.parameters())[0].detach().numpy())
print('b=', list(model.parameters())[1].detach().numpy())
print()

for epoch in range(1000):
    x_tr = torch.from_numpy(x[:2,:1]).type(torch.FloatTensor)
    y_tr = torch.from_numpy(y[:2,:1]).type(torch.FloatTensor)
    y_pr = model(x_tr)
    loss = torch.pow(torch.abs(y_tr - y_pr),2)
    if epoch < 3:
        print(f'Epoch:{epoch}')
        print('y_pr:', y_pr.detach().numpy())
        print('y_tr:', y[:2,:1])
        print('loss:', loss.detach().numpy())
        print()
    Optimizer.zero_grad()
    torch.sum(loss).backward()
    Optimizer.step()
print(model(torch.from_numpy(x).type(torch.FloatTensor)).detach().numpy())


w= [[-0.2695837]]
b= [-0.89686084]

Epoch:0
y_pr: [[-0.89686084]
 [-1.1664445 ]]
y_tr: [[1.]
 [3.]]
loss: [[ 3.598081]
 [17.359262]]

Epoch:1
y_pr: [[-0.7755947]
 [-0.9618495]]
y_tr: [[1.]
 [3.]]
loss: [[ 3.1527367]
 [15.696251 ]]

Epoch:2
y_pr: [[-0.6608458 ]
 [-0.76786363]]
y_tr: [[1.]
 [3.]]
loss: [[ 2.7584085]
 [14.196797 ]]

[[1.0002294]
 [2.9998584]
 [4.999487 ]
 [6.999116 ]
 [8.998745 ]]

Compatible version

케라스에서 사용한 코드를 최대한 고치지 않고 사용하는 방법이다. 모델 클래스를 작성할 때 입력에 대해 부가적인 처리를 함으로 나머지 코드는 케라스 경우와 비슷하게 사용할 수 있다. 먼저 forward(.)에서 Numpy의 어레이 입력을 토치 어레이로 바꾸는 과정을 포함한다. 그리고 앞선 Simple version에서 모델을 학습하는 코드를 fit()라는 모델 클래스 함수를 만들어 처리하도록 해 주었다. 그러고 나면 실제 수행코드는 케라스의 경우와 매우 유사하게 작성이 가능함을 알 수 있다.


In [3]:
import torch
import numpy as np

x = np.array([0, 1, 2, 3, 4]).astype('float32').reshape(-1,1) 
y = x * 2 + 1

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        self.layer = torch.nn.Linear(1,1)
        self.Optimizer = torch.optim.SGD(self.parameters(), lr=0.01)
    def forward(self, x):
        x = torch.from_numpy(x).type(torch.FloatTensor)
        return self.layer(x)
    def fit(self, x, y, epochs):
        for epoch in range(epochs):
            y_tr = torch.from_numpy(y).type(torch.FloatTensor)
            y_pr = model(x)
            loss = torch.pow(torch.abs(y_tr - y_pr),2)
            self.Optimizer.zero_grad()
            torch.sum(loss).backward()
            self.Optimizer.step()
model = Model()

model.fit(x[:2], y[:2], epochs=1000)
print(model(x))


tensor([[1.0004],
        [2.9998],
        [4.9992],
        [6.9986],
        [8.9980]], grad_fn=<AddmmBackward>)

GPU Version

GPU 버전으로 파이토치 코드를 작성할 경우는 model.to(device), x.to(device), y.to(device)라는 세가지 과정이 필요하다. 아래 코드는 예제 1-1을 파이토치 코드로 바꾼 뒤에 타켓 프로세서에 맞게 돌도로 디바이스가 CPU인지 GPU인지를 검사하여 해당 프로세서에 맞게 동작하게 만드는 코드이다.


In [4]:
import torch
import numpy as np

GPU인지 CPU인지 검사

프로세서로 GPU를 사용하는 있는지 아닌지를 검사하고 device 변수에 프로세서 타입을 적어넣는다.


In [5]:
if torch.cuda.is_available():
    device = torch.device('cuda')
else:
    device = torch.device('cpu')
    
print('Using PyTorch version:', torch.__version__, ' Device:', device)


Using PyTorch version: 1.0.1.post2  Device: cpu

In [6]:
x = np.array([0, 1, 2, 3, 4]).astype('float32').reshape(-1,1) 
y = x * 2 + 1

class Model(torch.nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        self.layer = torch.nn.Linear(1,1)
        self.Optimizer = torch.optim.SGD(self.parameters(), lr=0.01)
    def forward(self, x):
        x = torch.from_numpy(x).type(torch.FloatTensor).to(device)
        return self.layer(x)
    def fit(self, x, y, epochs):
        for epoch in range(epochs):
            y_tr = torch.from_numpy(y).type(torch.FloatTensor).to(device)
            y_pr = model(x)
            loss = torch.pow(torch.abs(y_tr - y_pr),2)
            self.Optimizer.zero_grad()
            torch.sum(loss).backward()
            self.Optimizer.step()
model = Model().to(device)

model.fit(x[:2], y[:2], epochs=1000)
print(model(x))


tensor([[1.0005],
        [2.9997],
        [4.9989],
        [6.9982],
        [8.9974]], grad_fn=<AddmmBackward>)

In [ ]: