본문 바로가기
Python

[PyTorch] CustomANN Example: From Celsius to Fahrenheit

by ds31x 2024. 4. 12.

Optional Libraries

  • torchviz: 0.0.2
  • torchsummary: 1.5.1
pip install --quiet torchviz
pip install torchsummary

Required Libraries

  • torch : 2.2.1+cu121
  • np : 1.25.2
import numpy as np
import torch
import matplotlib.pyplot as plt
# import torchviz, torchsummary

from torch.nn import Module, init, Linear, Parameter, ReLU
from torch import optim

Simple Data Generation

def gen_xy(cnt, std=4.):

    x = np.linspace(-10,10,cnt)
    y_ideal = 1.8 * x +32.
    y = y_ideal + std * np.random.randn((cnt))

    x = torch.tensor(x).float().reshape(-1,1)
    y = torch.tensor(y).float().reshape(-1,1)
    y_ideal = torch.tensor(y_ideal).float().reshape(-1,1)

    return x,y,y_ideal

 

다음의 코드로 데이터 생성 및 확인.

sample_cnt = 20

x, y, y_ideal = gen_xy(sample_cnt)

fig, axes = plt.subplots(1,2, figsize=(6,3))
axes[0].plot(x.detach(),y_ideal.detach())
axes[1].scatter(x.detach(),y.detach())
fig.suptitle('celsius to fahrenheit')
print(x.shape, y.shape, y_ideal.shape)


Model 구현

class DsANN (Module): #custom module

    def __init__(self,
                 n_in_f,  # input vector의 차원수.
                 n_out_f, # output vector의 차원수.
                 ):
        super().__init__() # required!

        self.linear0 = Linear(n_in_f, 32)
        self.relu0 = ReLU()

        self.linear1 = Linear(32, 32)
        self.relu1 = ReLU()

        self.linear2 = Linear(32, n_out_f)

        with torch.no_grad():
            init.constant_(self.linear0.bias, 0.)
            init.xavier_uniform_(self.linear0.weight)

    def forward(self,x):
        x = self.linear0(x)
        x = self.relu0(x)
        x = self.linear1(x)
        x = self.relu1(x)
        y = self.linear2(x)
        return y

model 내부 확인하기.

parameters 확인하기.

# for idx, c in enumerate(model.named_parameters()):
for idx, c in enumerate(model.parameters()):
  print(idx, c.shape)

children 확인하기

내부 구성 확인.

# for idx, cl in enumerate(model.named_children()):
for idx, cl in enumerate(model.children()):
  print(idx, cl)

구성 modules 확인하기

# for idx, modu in enumerate(model.named_modules()):
for idx, modu in enumerate(model.modules()):
  print (idx, modu)

torchsummary 사용하기.

from torchsummary import summary

summary(model, (1,))

 

결과는 다음과 같음.

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Linear-1                   [-1, 32]              64
              ReLU-2                   [-1, 32]               0
            Linear-3                   [-1, 32]           1,056
              ReLU-4                   [-1, 32]               0
            Linear-5                    [-1, 1]              33
================================================================
Total params: 1,153
Trainable params: 1,153
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.00
Estimated Total Size (MB): 0.01
----------------------------------------------------------------

Loss Function 구현.

torch.nn.MSELoss 를 그대로 이용.

from torch.nn import MSELoss

loss_fnc = MSELoss() # MSELoss 객체를 반환.
l = loss_fnc(pred, y)
l

Training Loop 구현.

def training_loop(
    x, y,
    model,
    lr,
    n_epochs,
    ):

  model.train()
  optimizer = optim.SGD(
    model.parameters(),
    lr = lr,
  )
  print(n_epochs)

  for epoch in range(n_epochs):
    pred = model(x)
    l = loss_fnc(pred, y)
    if torch.isinf(l).any():
      print('Error: diverge!')
      break

    optimizer.zero_grad()
    l.backward()
    optimizer.step()

    if epoch % 1000 == 0:
      print(f'Epoch {epoch}: Loss {float(l):0.4f}')

  return model

Training 수행

model = DsANN(1,1)
model = training_loop(
    x,y,
    model,
    1e-3,
    7000,
)

모델 성능 확인

간단한 예이므로 굳이 test set을 분리하여 처리하지 않고 training set을 사용하여 수행.

pred = model(x)

fig, axes = plt.subplots(1,1)
axes.scatter(x.detach().numpy(),y.detach().numpy())
axes.plot(x.detach().numpy(),pred.detach().numpy(), color='r')
axes.plot(x.detach().numpy(),y_ideal, color='g')
fig.suptitle('celsius to fahrenheit')


Linear 모델의 경우 확인.

linear_model = training_loop(
    x,y,
    Linear(1,1),
    1e-3,
    7000,
)
pred = linear_model(x)

fig, axes = plt.subplots(1,1)
axes.scatter(x.detach().numpy(),y.detach().numpy())
axes.plot(x.detach().numpy(),pred.detach().numpy(), color='r')
axes.plot(x.detach().numpy(),y_ideal, color='g')
fig.suptitle('celsius to fahrenheit')


https://gist.github.com/dsaint31x/1cdb36470462b3397224a6e22f3a3f96

 

dl_custom_ann_pytorch_ex.ipynb

dl_custom_ann_pytorch_ex.ipynb. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com