【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도 유용합니다.
분류기 학습 순서
- torchvision 을 사용하여 CIFAR10의 학습용 / 시험용 데이터셋을 불러오고, 정규화(nomarlizing)합니다.
- 합성곱 신경망(Convolution Neural Network)을 정의합니다.
- 손실 함수를 정의합니다.
- 학습용 데이터를 사용하여 신경망을 학습합니다.
- 시험용 데이터를 사용하여 신경망을 검사합니다.
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 해준다.
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)))
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)