투빅스 11기&12기 7주차 프레임워크(PyTorch) - 12기 신윤종

by yj posted Sep 16, 2019
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

+ - Up Down Comment Print

※ html파일 링크 : http://www.datamarket.kr/xe/?module=file&act=procFileDownload&file_srl=63462&sid=b20955b1ef5715549e5b6bbf22c8adcc


# 1번 과제

1
2
#!/usr/bin/env python
# coding: utf-8
 
# In[ ]:
 
 import numpy as np
import pandas as pd
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
 
 
# In[3]:
 
 
from google.colab import drive
drive.mount('/content/drive')
 
 
# In[4]:
 
 
train_data = pd.read_csv('/content/drive/My Drive/data/fashionmnist/fashion-mnist_train.csv')
test_data = pd.read_csv('/content/drive/My Drive/data/fashionmnist/fashion-mnist_test.csv')
train_data.head()
 
 
# In[5]:
 
 
# 이미지 데이터와 라벨 데이터 분리
train_x = np.array(train_data.iloc[:,1:])
train_y = np.array(train_data['label'])
test_x = np.array(test_data.iloc[:,1:])
test_y = np.array(test_data['label'])
 
print(train_x.shape)
print(train_y.shape)
print(test_x.shape)
print(test_y.shape)
 
 
# 시각화 
# 임의로 3번사진을 가져옵니다.
image_array = np.array(train_x[3]).reshape(28,28)
pic = Image.fromarray(image_array.astype('uint8'))
plt.imshow(pic)
 
 
# In[6]:
 
 
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch
from torch import nn
 
if torch.cuda.is_available():
    device = torch.device('cuda')
else:
    device = torch.device('cpu')
    
print('Using PyTorch version:', torch.__version__, ' Device:', device)
 
 
# In[ ]:
 
 
# 파라미터 선택
random_seed = 0
learning_rate = 0.0001
num_epochs = 40
batch_size = 32
 
input_size = 784
h1_size = 512
h2_size = 512 
output_size = 10
 
 
# In[8]:
 
 
# 데이터셋을 클래스로 만들고 파이토치의 dataloader로 만들어주면 손쉽게 훈련에서 사용할 수 있습니다.
# 함수들은 dataloader로 데이터를 끌고올 때 사용됩니다.
class FashionDataset(torch.utils.data.Dataset):
    def __init__(self, X, Y):
        # import and initialize dataset
        self.X = X
        self.Y = Y
 
    def __getitem__(self, idx):
        return self.X[idx], self.Y[idx]
 
    def __len__(self):
        # returns length of data
        return len(self.X)
    
dataset = FashionDataset(train_x, train_y)
testset = FashionDataset(test_x, test_y)
print(type(dataset))
print(len(dataset))
dataloader = torch.utils.data.DataLoader(dataset, batch_size = batch_size, shuffle = True)
test_loader = torch.utils.data.DataLoader(testset, batch_size = batch_size, shuffle = True)
 
dataloader
 
 
# In[ ]:
 
 
# 다층 신경망 클래스 정의
class MLP(nn.Module):
    def __init__(self, input_size, output_size, h1_size, h2_size):
        super(MLP, self).__init__()
        # 파라미터 정의
        self.input_size = input_size
        self.output_size = output_size
        self.h1_size = h1_size
        self.h2_size = h2_size  
        
        # 신경망 정의
        # Sequential로 한꺼번에 묶어서 처리 할 수 있습니다.
        self.layers = nn.Sequential(
            nn.Linear(self.input_size, self.h1_size, bias=True),
            nn.ReLU(),
            nn.Linear(self.h1_size, self.h2_size, bias=True),
            nn.ReLU(),
            nn.Linear(self.h2_size, self.output_size, bias=True)
        )
 
    def forward(self, x):
        # 학습을 위해 텐서 shape을 바꿔줌
        x = x.view(-1784)
        x = self.layers(x.float())
        return x
 
 
# In[10]:
 
 
my_mlp = MLP(input_size, output_size, h1_size, h2_size).to(device)
print(my_mlp)
 
 
# In[ ]:
 
 
optimizer = torch.optim.Adam(my_mlp.parameters(), lr=0.0001)
criterion = nn.CrossEntropyLoss()
 
 
# In[68]:
 
 
# 성능 측정 데이터를 쌓을 dictionary
performance = {'test_acc': [],'test_loss': []} 
 
for epoch in range(num_epochs):
    # train
    my_mlp.train()
    # iter, image, label 반복문
    for i, (x, y) in enumerate(dataloader):
        # 모델에 데이터를 흘려 넣어줍니다.
        x, y = x.to(device), y.to(device) 
        outputs = my_mlp(x)
        loss = criterion(outputs, y)
        # optimizer의 변화도 버퍼(gradient buffer)를 0으로 설정하고, 무작위 값으로 역전파를 합니다.
        optimizer.zero_grad()
        loss.backward()
        # 가중치 업데이트 
        optimizer.step()
 
    # eval
    y_pred, y_true = [], []
    test_acc = 0
    test_loss = 0
    my_mlp.eval()
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            # Loss
            outputs = my_mlp(x)   # 예측 label 
            loss = criterion(outputs, y)
            test_loss += loss.item()
            # Accuracy
            y_true += list(y.cpu())   # 정답 label
            y_pred += list(np.argmax(F.softmax(outputs).cpu(), axis=1)) # 소프트맥스 확률값에서 argmax로 제일 높은 인덱스를 뽑자
            # sklearn의 정확도 측정 모듈 accuracy_score
            acc = accuracy_score(y_true, y_pred)
            test_acc += acc
 
        # 누적된 통계치들에 batch를 반복한 횟수로 나누자
        # 반복 횟수 = batch size 32로 잡았으면 testset size가 1만이니까 10k / 32 해서 313
        test_acc = test_acc / len(test_loader.batch_sampler)
        test_loss = test_loss / len(test_loader.batch_sampler)
 
        performance["test_acc"].append(test_acc)
        performance["test_loss"].append(test_loss)
 
        # 성능 출력
        if epoch % 5 == 0:
            print(f"Epoch: {epoch}, Test Loss: {test_loss:.5f}, Test Acc: {test_acc:.5f}")
 
 
# ### 참고자료
# * https://medium.com/biaslyai/pytorch-introduction-to-neural-network-feedforward-neural-network-model-e7231cff47cb
# * https://www.kaggle.com/pinocookie/pytorch-simple-mlp
# * https://tutorials.pytorch.kr/beginner/pytorch_with_examples.html
 
cs
# 2번 과제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#!/usr/bin/env python
# coding: utf-8
 
# In[6]:
 
 
import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
if torch.cuda.is_available():
    device = torch.device('cuda:0')
else:
    device = torch.device('cpu')
    
print('Using PyTorch version:', torch.__version__, ' Device:', device)
 
 
# In[ ]:
 
 
input_size = 32 * 32 * 3
hidden_size = 128
output_size = 10
epoch_size = 50
batch_size = 32
learning_rate = 0.0001
 
 
# In[8]:
 
 
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models
import torch.optim as optim
 
# CIFAR 10 dataload
# torchvision에서 여러 데이터를 제공한다. 만약 여기에 없으면 어쩔 수 없이 전처리를 다 해줘야 한다...
 
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.50.50.5), (0.50.50.5))])
 
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,
                                          shuffle=True, num_workers=2)
 
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,
                                         shuffle=False, num_workers=2)
 
 
# In[9]:
 
 
trainloader.dataset
 
 
# ## Batch Normalization
# * 기존의 신경망 성능을 높이려는 시도들이 있어왔다. 대표적으로 input과 weight을 표준화시킨는 것.
# * 그러나 문제는 hidden layer가 학습을 진행하면서 input distribution이 불안정해지게 된다.이를 Internal Covariate Shift
# 라고 한다. 예를 들자면 가족오락관에서 귀마개를 끼고서하는 게임에서 사람을 거칠 수록 이상한 정답이 나오는 이치와 비슷하다고 함. 두 번째 가중치 값이 있다면 이 가중치는 이전 가중치 W1와 입력값에 따라 분포가 달라진다. 즉 W2가 불안정해진다.
# 1단계
# * hidden input -> Batch Normalization -> Activation Funciton 의 구조를 가지면 된다.
# * 보통 신경망은 mini batch로 학습하니 각 batch마다 표준화를 시킨다.
# * batch_size = m일 때 
# * $ {\ μ_β} = {1 \over m} * {\sum_i}X_iW_i  $  (배치 평균)
# * $ {\ σ_β} = {1 \over m} * {\sum_i}(X_iW_i - μ_β$)2 (배치 표준편차)
# * Activation $ a = f({\ XW_i - μ_β \over \ σ_β})$
# 2단계
# * 그러나 이 상태라면 grdient update에서 bias가 무시된다. sigmoid의 경우 활성화 결과값들이 sigmoid의 중간 선형부분에 위치하게 된다. 이런식으로 나쁜 Normalization을 고칠 감마와 베타라는 파라미터가 추가된다.
# * $ {\ a} = γ*({\ XW_i - μ_β \over \ σ_β}) + β $ (이 친구도 마치 또 다른 신경망 같다. 얘네도 학습이 된다는 것)
# * 이 값을 실제 신경망의 활성화 함수 입력으로 넣어주면 된다.
# Test단계
# * 평가 시에는 학습 때 썼던 Batch별 통계값의 평균을 사용하거나 move average를 사용한다.
# * $ \hat{\mu} \gets \alpha \hat{\mu} + (1-\alpha) \mu_{\mathcal{B}}^{(i)}$ (알파는 momentum값으로 누구는 0.9를 사용하라고 하고, 파이토치에서는 default가 0.1이다.)
# * $ \hat{\sigma} \gets \alpha \hat{\sigma} + (1-\alpha) \sigma_{\mathcal{B}}^{(i)}$
# 장점
# 1.   bias 무시 X
# 2.   hidden input 표준화
# 3.   vanishing gradient 방지(actiation값을 적당한 크기로 유지)
# 4.   interval covariate shift 방지
# 5.   Dropout 안해도 됨. 같은 효과를 내기 떄문이라고 함
# 6.   Learning Rate 크게 해도 됨 -> 시간단축
# 텐서플로나 파이토치에서 쉽게 신경망에 추가할 수 있는 클래스를 제공한다.
 
# ## 드롭아웃
# * 과적합을 막는 방법 중 하나
# * 뉴런의 연결을 임의로 삭제
# * 단, 테스트 시 모든 노드 사용함.
# * 일정 확률로 강력한 뉴런이 무시될 수도 있다. 강력한 뉴런은 학습 데이터에 확신을 가지고 있다는 뜻이고, 그러한 뉴런이 많으면 일반화 능력이 떨어질 수 있다. 
 
# In[10]:
 
 
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) # input, output
        self.fc2 = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        x = x.view(-1, self.num_flat_features(x))        
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features
 
 
# Dropout
class DropoutNet(nn.Module):
    def __init__(self):
        super(DropoutNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) # input, output
        self.fc2 = nn.Linear(hidden_size, output_size)
        self.dropout = nn.Dropout(p=0.5)
 
    def forward(self, x):
        x = x.view(-1, self.num_flat_features(x))
        x = self.dropout(F.relu(self.fc1(x)))
        x = self.fc2(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features
 
# Batch Normalization
class BNNet(nn.Module):
    def __init__(self):
        super(BNNet, self).__init__()
        self.linear1 = nn.Linear(input_size, hidden_size)
        self.bn1 = nn.BatchNorm1d(hidden_size)
        self.linear2 = nn.Linear(hidden_size, output_size)
 
    def forward(self, x):
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.bn1(self.linear1(x)))
        x = self.linear2(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features
 
# 골라서 해보자
# net = Net().to(device)
# net = DropoutNet().to(device)
net = BNNet().to(device)
print(net)
 
 
# In[ ]:
 
 
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=learning_rate)
 
 
# In[12]:
 
 
performance = {'test_acc': [],'test_loss': []} 
 
for epoch in range(epoch_size):
    net.train()
    for i, (x, y) in enumerate(trainloader):
        inputs, labels = x.to(device), y.to(device)
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        
    total_label = 0
    correct = 0
    test_loss = 0
    net.eval()
    with torch.no_grad():
        for x, y in testloader:
            images, labels = x.to(device), y.to(device)
            outputs = net(images)
            loss = criterion(outputs, labels)
            test_loss += loss.item()
            _, predicted = torch.max(outputs, 1)
            correct += (predicted == labels).sum().item()
            total_label += labels.size(0)
 
        test_acc = 100*correct/total_label
        test_loss = test_loss / len(testloader.batch_sampler)
        performance["test_acc"].append(test_acc)
        performance["test_loss"].append(test_loss)
 
    if epoch % 5 == 0:
        print(f"Epoch: {epoch}, loss: {test_loss:.5f}, acc: {test_acc:.5f}")
 
 
# In[ ]:
 
 
# 시각화
# 갓대웅님의 시각화 코드 참조 했습니다.
fig = plt.figure()
ax_acc = fig.add_subplot()
ax_acc.plot(range(epoch_size), performance['test_acc'], label='acc', color='darkred')
ax_acc.grid(linestyle='--', color='lavender')
plt.xlabel('epochs')
plt.ylabel('Validation Accuracy(%)')
 
ax_loss = ax_acc.twinx()
ax_loss.plot(range(epoch_size), performance['test_loss'], label='loss', color='darkblue')
ax_loss.grid(linestyle='--', color='lavender')
plt.ylabel('Validation Error')
ax_loss.yaxis.tick_right()
plt.show()
 
 
# * Basic NN
# * hidden_size = 128, LR = 0.0001
# * 빠르게 과적합하는 모습을 확인할 수 있었습니다.
# ![basic_128.png](attachment:basic_128.png)
# * Dropout
# ![do_256.png](attachment:do_256.png)
# * Batch Normalize
# ![bn_1.png](attachment:bn_1.png)
# * 60까지 찍어주고 있습니다
 
cs

Articles

2 3 4 5 6 7 8 9 10 11

나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Designed by sketchbooks.co.kr / sketchbook5 board skin

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5