【Pytorch】 Pytorch 튜토리얼 4 - pytorch로 딥러닝하기

아래의 주석을 참고해서 공부하기 바랍니다.

jupyter nootbook을 markdown으로 바꾸는 방법

$ jupyter nbconvert --to markdown <.\4Classifier-copy.ipynb>

outputprepend Error 해결방법

참고 사이트 - html-notebook-json-is-invalid-outputprepend

4장 공부내용

주요 팁

  • 이미지는 Pillow나 OpenCV 같은 패키지가 유용합니다.
    특별히 영상 분야를 위한 torchvision 이라는 패키지 -> torchvision.datasets and torch.utils.data.DataLoader.
  • 오디오를 처리할 때는 SciPy와 LibROSA가 유용하고요.
  • 텍스트의 경우에는 그냥 Python이나 Cython을 사용해도 되고, NLTK나 SpaCy도 유용합니다.

분류기 학습 순서

  1. torchvision 을 사용하여 CIFAR10의 학습용 / 시험용 데이터셋을 불러오고, 정규화(nomarlizing)합니다.
  2. 합성곱 신경망(Convolution Neural Network)을 정의합니다.
  3. 손실 함수를 정의합니다.
  4. 학습용 데이터를 사용하여 신경망을 학습합니다.
  5. 시험용 데이터를 사용하여 신경망을 검사합니다.

1. 데이터 Load 하기

import torch
import torchvision
import torchvision.transforms as transforms
# loader하
# transforms 라이브러리는 다음을 참조 : https://pytorch.org/docs/stable/torchvision/transforms.html
transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# 순서대로 : https://pytorch.org/docs/stable/torchvision/datasets.html#cifar
#         : https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader  <- 위의 글들도 읽으면 좋다.

# torchvision dataset을 이용해서 'Train' dataset가져오기.
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)

# torchvision dataset을 이용해서 'Test' dataset가져오기.
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

# trainset, trainloader 로 궁금증 해소해보는것은 나중에 하자.. 
# 아래의 dataiter를 list화 하고 확인하는 등의 작업을 하면 된다.
Files already downloaded and verified
Files already downloaded and verified
# 심심풀이로, 데이터 한번 확인해보기.
# 1. iter, next 함수 : https://dojang.io/mod/page/view.php?id=2408
import matplotlib.pyplot as plt
import numpy as np

# 이미지를 보여주기 위한 함수

def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# 학습용 이미지를 무작위로 가져오기
# 위에서 사용한 DataLoader를 이런식으로 사용하는 구나.
dataiter = iter(trainloader)
images, labels = dataiter.next()


# 이미지 보여주기 - 위에서 정의한 imshow 함수를 이용한다. 
imshow(torchvision.utils.make_grid(images)) # 왜 4장이 오는지 모르겠다.
# 정답(label) 출력
print(' '.join('%5s' % classes[labels[j]] for j in range(4))) # class 정보의 str을 print 해준다. 

svg

dog   dog  bird horse

2. 합성곱 신경망(Convolution Neural Network) 정의하기

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


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3,6,5) # channel 3 -> 6, 5*5 kernel 
        self.pool = nn.MaxPool2d(2,2) # kennel 2 , stride 2
        self.conv2 = nn.Conv2d(6, 16, 5)  # 이후 최종 output size = 16c * 5h * 5w
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # print('input x 의 사이즈는 (배치까지 고려하여...) :' ,x.size())
        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()
# print(net)

3. 손실 함수와 Optimizer 정의하기

import torch.optim as optim

criterion = nn.CrossEntropyLoss()                               # 나중에 이런 식으로 loss를 정의할 예정이다. loss = criterion(out, target) 
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # 그리고 나중에 loss.backward(); optimizer.step(); 를 할 예정

4. 신경망 학습하기

total = 0
for epoch in range(2):  # loop over the dataset multiple times
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):  # enumerate(iter variable,))for문을 돌기 시작할 index를 적는다. 
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data
        total += labels.size(0)
        

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item() # 2000 mini-batches의 모든 loss를 합친다.
        if i % 2000 == 1999:    # print every 2000 mini-batches
            # print('input size, type : {}, {} , labels : {}'.format(inputs.size(), type(inputs), labels))
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0
    print('total image : %d장'%(total)) # -> 50000장

print('Finished Training! total image : %d 장'%(total))
[1,  2000] loss: 2.190
[1,  4000] loss: 1.830
[1,  6000] loss: 1.674
[1,  8000] loss: 1.580
[1, 10000] loss: 1.509
[1, 12000] loss: 1.467
total image : 50000장
[2,  2000] loss: 1.403
[2,  4000] loss: 1.391
[2,  6000] loss: 1.335
[2,  8000] loss: 1.300
[2, 10000] loss: 1.300
[2, 12000] loss: 1.284
total image : 100000장
Finished Training! total image : 100000 장

input size, type : torch.Size([4, 3, 32, 32]), <class ‘torch.Tensor’> , labels : tensor([2, 2, 2, 1])
이것으로 보아, 4장의 이미지를 미니 배치로 사용한다.
labels는 4장의 이미지 각각의 class를 0~9를 사용해 표현했다.
[1, 2000] loss: 2.190
[1, 4000] loss: 1.826
[1, 8000] loss: 1.568
[1, 12000] loss: 1.427
print(‘total image : %d장’%(total)) [2, 4000] loss: 1.353

Finished Training! total image : 100000 장

추가 중요 팁! : jupyter notebook 에서 위의 cell을 계속 다시 실행하면, 학습이 누적된다.

# 학습시킨 모델 가중치 모두 저장하기 https://pytorch.org/docs/stable/nn.html?highlight=state_dict#torch.nn.Module.state_dict
PATH = './cifar_net.pth' # pytorch에서는 가중치를 저장하는 파일로, pth를 사용하는 구나.
torch.save(net.state_dict(), PATH)


5. Test용 데이터로 신경망 검사하기

# testloader를 이용해서 test이미지를 가져와서 사진과, 정답 labels을 확인해보자
dataiter = iter(testloader) # 이렇게 iter를 사용할 필요가 없다. 1개의 mini-batch에 대한 평가만 하려고 하는 짓거리다.
images, labels = dataiter.next()
# images, labels = dataiter.next().next()
# print images
imshow(torchvision.utils.make_grid(images))
# print labels
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

svg

GroundTruth:    cat  ship  ship plane
# 모델을 저장하고 다시 불러오는 작업은 여기에서는 불필요하지만, 어떻게 하는지 설명을 위해 해보겠습니다
# outputs = net(images)

# 하나의 미지배치(4장의 사진)에 대해서만, 예측값 뽑아보기
net1 = Net() # net과 똑같은 net1을 만들어서, 가중치를 붙여넣는다.
net1.load_state_dict(torch.load(PATH))

# outputs = net(images)
outputs = net1(images)

'''
# outputs
tensor([[ 0.9325, -3.3154,  3.2897,  1.7889,  2.5571,  1.6230, -1.0427,  0.8774,
         -2.9875, -3.0614],
        [ 2.2483,  4.3386, -1.2291, -2.5435, -0.0399, -3.8688, -4.3639, -2.1145,
          3.0017,  4.3678],
        [ 6.3519, -0.1864,  2.2633, -1.3706,  0.1879, -3.8894, -3.5882, -4.2822,
          6.0977, -1.1683],
        [ 0.0072, -2.0762,  1.1485,  0.7453,  0.5172, -0.2358,  0.5444, -1.1512,
          1.6059, -0.7272]], grad_fn=<AddmmBackward>)
'''
"""
# torch.max(outputs, 1) 
torch.return_types.max(
        values=tensor([3.2897, 4.3678, 6.3519, 1.6059], grad_fn=<MaxBackward0>),
        indices=tensor([2, 9, 0, 8]))
"""
_, predicted = torch.max(outputs,1) # 1은 dimention을 의미한다. 

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

Predicted:   bird plane   car plane
# 전체 데이터 셋에 대해서 accuracy를 판단해보자. 
correct = 0
total = 0
with torch.no_grad():  # 2장에서 배웠던, 이것을 Evaluation 하거나, Test 데이터 확인할 때 사용하는구나!
    for data in testloader: # 위에서 처럼 iter를 사용하지 않고 이렇게 편하게 사용하면 된다. 
        # 1개의 mini-batch를 평가할 때와 똑같은 방법으로 (바로 위의 방법) 똑같이 하면 된다.)
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1) 

        total += labels.size(0) # 몇장의 사진을 예측했는지. 즉 labels.size(0) == 4 이므로 4를 계속 더해간다.
        correct += (predicted == labels).sum().item() # 4개 중 몇개를 맞췄는지 확인한다.
        # 내가 가진 testloader의 data가 없어질 때까지 과정을 반복한다.

print('Accuracy of the network on the 10000 test images: %5d %% / total : %5d ' % (100 * correct / total, total))
Accuracy of the network on the 10000 test images:    54 % / total : 10000 
# 각 class/label 별로, accuracy가 어떻게 되는지, 분류해서 확인해보자
# 신경망 통과는 당연히 다시해댜한다 ^^ 
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))
Accuracy of plane : 67 %
Accuracy of   car : 76 %
Accuracy of  bird : 53 %
Accuracy of   cat : 50 %
Accuracy of  deer : 39 %
Accuracy of   dog : 29 %
Accuracy of  frog : 51 %
Accuracy of horse : 57 %
Accuracy of  ship : 68 %
Accuracy of truck : 57 %

6. GPU 사용하기

Tensor를 GPU로 이동했던 것처럼, 신경망 또한 GPU로 옮길  있습니다.(1장에서 배움)    
먼저 (CUDA를 사용할  있다면) 첫번째 CUDA 장치를 사용하도록 설정합니다.
  File "<ipython-input-13-b15bb06280db>", line 1
    Tensor를 GPU로 이동했던 것처럼, 신경망 또한 GPU로 옮길 수 있습니다.(1장에서 배움)
               ^
SyntaxError: invalid syntax
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# CUDA 기기가 존재한다면, 아래 코드가 CUDA 장치를 출력합니다:
print(device)  # >> cuda:0
# 아래를 통해 재귀적으로 모든 모듈의 매개변수와 버퍼를 CUDA tensor로 변경합니다!!
net.to(device)
# 주의할점!! 각 단계에서 입력(input)과 정답(target)도 GPU로 보내야 한다는 것도 기억해야 합니다:
## 위에서 이렇게 활용하는 부분에서.. for i, data in enumerate(trainloader, 0):  
inputs, labels = data[0].to(device), data[1].to(device)


© All rights reserved By Junha Song.