👩‍💻LEARN : ML&Data/Code

[파이토치 튜토리얼] #1. PYTORCH 소개

쟈니유 2023. 5. 26. 17:06
728x90

파이토치 한국커뮤니티가 워낙에 잘 되어있어서 

튜토리얼 중 중요한 것들은 모두 번역이 되어 있다 🥹 부지런한 한국 사람들 최고...

 

아래 내용은 파이토치 한국 튜토리얼에 있는 내용을 따라하며 정리한 내용들이며,

추가적으로 부가 설명이 필요한 경우 (for me..!) 추가 서술이 되어있다. 

 

1. Pytorch Tensor 

파이토치에서 텐서는 기본적인 데이터 형태이다. 2017년 cs231n에는 텐서 외에도 다른 데이터 유형이 있었는데, 이를 모두 텐서로 병합했다. 가장 기본적인 자료 형태이니만큼 텐서의 종류엔 무엇이 있는 지, 무엇을 할 수 있을 지 알아보면 좋지만 이는 나중에 다른 글로 정리할 예정이다. 

 

이번 정리에서는 간단하게 텐서 다루는 방법만 나온다. 

 

텐서 생성 및 유형 확인 

import torch

z = torch.zeros(5,3)
print(z)
print(z.dtype)

tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.], [0., 0., 0.], [0., 0., 0.]]) torch.float32

텐서 생성 및 유형 변경

i = torch.ones((5,3), dtype=torch.int16)
print(i)

tensor([[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype=torch.int16)

 

📌 기본적으로는 float으로 선언되나 dtype 기본값을 변경하면 데이터타입 변경 가능

학습 가중치 무작위 초기화 시 텐서 사용법 

torch.manual_seed(1729)
r1 = torch.rand(2,2)
print('랜덤 텐서값')
print(r1)

r2 = torch.rand(2,2)
print('\n다른 랜덤 텐서값')
print(r2)

torch.manual_seed(1729)
r3 = torch.rand(2,2)
print('\n 동일한 랜덤 텐서값')
print(r3)

랜덤 텐서값 tensor([[0.3126, 0.3791], [0.3087, 0.0736]]) 다른 랜덤 텐서값 tensor([[0.4216, 0.0691], [0.2332, 0.4047]]) 동일한 랜덤 텐서값 tensor([[0.3126, 0.3791], [0.3087, 0.0736]])

 

📌 seed 번호를 동일하게 하면 랜덤 결과를 재현할 수 있음 

 

사용 가능한 수학 연산 예제 

#임의의 텐서를 생성한다 
r = (torch.rand(2,2) - 0.5)*2 

print(r)

tensor([[-0.1568, -0.8619], [-0.5336, -0.1907]])

print('\nr의 절대값:')
print(torch.abs(r))

# 삼각함수
print('\nr의 역 사인 함수:')
print(torch.asin(r))

# 행렬식 및 특이값 분해와 같은 선형 대수 연산
print('\nr의 행렬식:')
print(torch.det(r))
print('\nr의 특이값 분해:')
print(torch.svd(r))

# 통계 및 집합 연산
print('\nr의 평균 및 표준편차:')
print(torch.std_mean(r))
print('\nr의 최대값:')
print(torch.max(r))

 

2. 파이토치 모델 

LeNet-5 구조를 활용하여 이미지 분류를 진행할 예정 

 

#필요한 패키지를 가져온다 

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

import torchvision
import torchvision.transforms as transforms

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#1. 들어오는 이미지를 파이토치 텐서로 변환

transform = transforms.Compose(
    [transforms.ToTensor(),#Pillow 패키지 사용해서 이미지를 텐서로 변환해줌 
     transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]#텐서 평균이 0, 표준편차 0.5로 값 조정
)
#2. 데이터 가져오기. 
'''
데이터셋을 인스턴스화할 때 몇 가지 파라미터를 선언해야 합니다.
-데이터를 저장하려는 파일 시스템 경로입니다.
-데이터셋을 학습에 사용하는지 여부를 확인하여 대부분의 데이터셋은 학습 및 테스트 데이터셋으로 분할됩니다.
-데이터셋을 다운로드할지에 대한 여부를 확인합니다.
-데이터에 적용하려는 변환 객체를 넣어줍니다
'''

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)

#DataLoader 에서에서 무작위 추출(shuffle=True )한 4개의 batch 이미지를 trainset 에서 추출하고 
#disk에서 데이터를 로드하기 위해 2개의 workers를 spin up 
trainloader = DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testloader = DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)
#3. 데이터 시각화
classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
           
def imshow(img):
  img = img/2 +0.5
  npimg = img.numpy()
  plt.imshow(np.transpose(npimg,(1,2,0)))

dataiter= iter(trainloader) #무작위로 트레인로더에서 데이터 뽑아오긔 
images,labels = next(dataiter)

imshow(torchvision.utils.make_grid(images)) #뽑아온거 보여줘! 
print('.      '.join('%5s'%classes[labels[j]] for j in range(4)))

                                                    cat.                      bird.                      cat.                      truck

 

#3. 모델 설정 

#모델링 

class Net(nn.Module):
  def __init__(self):
    super(Net,self).__init__()
    self.conv1 = nn.Conv2d(3,6,5)
    self.pool = nn.MaxPool2d(2,2)
    self.conv2 = nn.Conv2d(6,16,5)
    self.fc1 = nn.Linear(16*5*5, 120)
    self.fc2 = nn.Linear(120,84)
    self.fc3 = nn.Linear(84,10)

  def forward(self,x):
    x = self.pool(F.relu(self.conv1(x)))
    x = self.pool(F.relu(self.conv2(x)))
    x = x.view(-1,16*5*5)
    x = F.relu(self.fc1(x))
    x = F.relu(self.fc2(x))
    x = self.fc3(x)
    return x 

net = Net()

#4. 오차랑 최적화 

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum = 0.9)

#5. 학습 실행

for epoch in range(2):

  running_loss = 0.0
  for i, data in enumerate(trainloader,0): #trainloader에서 0부터 시작한다는 의미 
    inputs, labels = data
    optimizer.zero_grad()

    outputs = net(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()

    running_loss +=loss.item()
    if i%2000 == 1999:
      print('[%d, %5d]loss : %.3f'% (epoch+1, i+1, running_loss/2000))
      running_loss = 0.0

print("Finished")

[1, 2000]loss : 2.151 [1, 4000]loss : 1.786 [1, 6000]loss : 1.667 [1, 8000]loss : 1.591 [1, 10000]loss : 1.512 [1, 12000]loss : 1.479 [2, 2000]loss : 1.398 [2, 4000]loss : 1.402 [2, 6000]loss : 1.381 [2, 8000]loss : 1.351 [2, 10000]loss : 1.327 [2, 12000]loss : 1.284 Finished

 

#6. 테스트 
#다른 성능 지표 사용해도 되는데 우선 초반이니까 에러율로만 확인 

correct = 0
total = 0

with torch.no_grad():
  for data in testloader:
    images,labels = data
    outputs = net(images)
    _,predicted = torch.max(outputs.data,1) 
    #앞의 _, 이거는 첫번째 변수 저장 안하려고. torch.max를 시행하면 value와 indices가 나오는데 여기에서는
    #index가 정답 라벨과 맞는지만 보려고 하는 것이므로 값이 필요 없음 
    total += labels.size(0)
    correct += (predicted ==labels).sum().item()

print(100*correct/total)