2020년 2월 21일 금요일

파이토치 MNIST (CNN)

2020/02/21
3.5기 3팀 최웅준,송근영,김정민
장소: 능곡역 지노스 까페
합성곱을 이용한 신경망을 구성하여 Mnist를 학습하였다.
28 x 28 사이즈의 이미지셋으로 총 60000장을 라이브러리 'torchvision'에서제공해준다.
모델구조 
구글에 있는 MNIST 모델을 참조하였습니다.


import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import random

위와 같은 라이브러리를 import 하였습니다.

class MnistClassifier(nn.Module) :
  def __init__(self):
    super(MnistClassifier,self).__init__()
    self.conv1 = nn.Conv2d(1,6,3)
    self.pool1 = nn.MaxPool2d(2)

    self.conv2 = nn.Conv2d(6,16,3)
    self.pool2 = nn.MaxPool2d(2)

    self.Fc1 = nn.Linear(5*5*16,128)
    self.Fc2 =  nn.Linear(128,10)

    self.conv_model = nn.Sequential(
        self.conv1,
        nn.ReLU(),
        self.pool1,
        self.conv2,
        nn.ReLU(),
        self.pool2,

    )
    self.fc_model = nn.Sequential(
        self.Fc1,
        nn.ReLU(),
        self.Fc2
    )
    #Fc3

  def forward(self,x) :
    mnist_model = self.conv_model(x)
    dim = 1
    for d in mnist_model.size()[1:] :
      dim = dim *d
    mnist_model = mnist_model.view(-1,dim)
    mnist_model = self.fc_model(mnist_model)
    return torch.nn.functional.softmax(mnist_model,dim=1)

Mnist CNN network 클래스를 정의한 것입니다.
nn.Module을 상속받으면서 네트워크를 만들길래 그방법을 차용했습니다.
nn.Sequential 이라는 함수를 사용하면 자동적으로 layer를 이어서 모델로 만들어줍니다. 
cnn output이 차원이 3이므로 FC 에 input으로 주기 위해서 차원을 1로 변경해줍니다.
1~10의 숫자를 분류하는것이 이 네트워크의 목적이기 때문에 softmax를 사용해줍니다.

training_epoch = 10
batch_size = 100

mnist_train = dsets.MNIST(root='MNIST_data/',
                          train=True,
                          transform=transforms.ToTensor(),
                          download=True)

mnist_test = dsets.MNIST(root='MNIST_data/',
                         train=False,
                         transform=transforms.ToTensor(),
                         download=True)
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

DataLoader라는 클래스를 사용했는데  이는 모델 제작자가 data를 배치만큼 쪼개서 input으로 주고 shuffle해주는 과정을 DataLoader라는 클래스가 대신해주는 것입니다. 안써도 상관 없지만 , 편의를 위해서 사용해줍니다.

criterion = nn.CrossEntropyLoss()
# backpropagation method
learning_rate = 1e-3
mnist_train_model = MnistClassifier()
optimizer = torch.optim.Adam(mnist_train_model.parameters(), lr=learning_rate)
trn_loss_list=[]
for epoch in range(1,training_epoch) :
  trn_loss=0.0
  for i, x in enumerate(data_loader) :
    data ,label = x
    model_output = mnist_train_model(data)
    

    #gradient 초기화
    optimizer.zero_grad()
    #loss 함수
    loss = criterion(model_output,label)
    #back_propagation
    loss.backward()
    #weight_update
    optimizer.step()
    trn_loss += loss.item()
    # del (memory issue)
    del loss
    del model_output

    print("epoch: {}/{} | step: {}/{} | trn loss: {:.4f} ".format(
                epoch+1, training_epoch, i+1, batch_size, trn_loss / 100
            ))            
            
    trn_loss_list.append(trn_loss/100)
    trn_loss = 0.0

loss 함수로는 cross_entropy , optimizer 는 Adam을 사용했습니다.
weight update 는 mini gradient descent 방법으로 update했습니다.

test_loader = torch.utils.data.DataLoader(dataset=mnist_test,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

correct = 0.0
with torch.no_grad():
  for i, x in enumerate(test_loader) :
    data, label  = x
    test_output = mnist_train_model(data)
    prediction = test_output.data.max(1)[1]
    correct += prediction.eq(label.data).sum()
print('Test set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))

Test 정확도는 98.27% 나왔습니다.

와인 분류하기

사이킷런에 포함된 와인 데이터 집합을 학습 데이터로 사용할 것이다.


2020/02/21
3.5기 3팀 최웅준,송근영,김정민
장소: 능곡역 지노스 까페
직접신경망을 구성하기에는 아직 미숙하여 'pytorch를 활용한 머신러닝,딥러닝 철저 입문' 서적에 있는 
신경망을 이용한 와인분류 부분의 코드를 직접 코랩을 이용하면서 실행해보고 분석해보았다. 

sklearn 라이브러리('사이킷런')에는 여러가지 데이터들을 제공해주는데 wine 데이터 집합을 활용하였다. 
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
위의 코드들로 라이브러리를 임포트하면 wine데이터를 이용할 수있다.

wine변수의 내용은 아래와 같다.
DESCR:데이터 집합의 상세 정보
data:와인 성분 데이터(설명변수)
feature_names:와인의 성분명
target:와인의 품종 데이터(목적변수)
target_names:와인의 품종 이름
신경망 구조
#학습 데이터 준비
#Pytorch 라이브러리 임포트

import torch
import numpy as np  
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim 
from torch.utils.data import DataLoader, TensorDataset 

# scikit-learn 라이브러리 임포트

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split


# Pandas 라이브러리 임포트
import pandas as pd
#와인 데이터 읽어 들이기
#사이킷런에 포함된 와인 데이터 집합을 학습 데이터로 사용할 것이다.
#와인 데이터 집합을 읽어 들여 wine 변수에 저장한다.
#사이킷런에는 다양한 데이터가 저장되어 있다.

wine = load_wine()
wine
# 데이터프레임에 담긴 설명변수 출력
# wine.data의 타입은 Numpy 배열이므로 한번에 내용을 파악하기 어렵다. 그러므로
# 여기서 판다스에서 제공하는 데이터프레임 타입으로 변환해서 내용을 볼것이다.
pd.DataFrame(wine.data, columns=wine.feature_names)




#목적 변수 데이터 출력
#이번에는 와인 품종 데이터(목적변수)를 확인해 보자. wine.target으로 이 데이터에 접근할 수 있다.
#wine.target의 크기는 178행 1열로,0부터 3까지의 값 중 하나를 갖는 Numpy 배열이다.

wine.target = wine.data
#설명변수와 목적변수를 변수에 대입#목적변수의 값은 0~2 까지 3가지이지만 이번에는 0과 1로 2가지로 제한한다. 
#설명변수와 목적변수 모두 앞에서부터 130건까지만 추려낸다. 
#설명변수의 변수명은 wine_data로 하고, 목적변수의 변수명은 wine_target으로 한다.
wine_data = wine.data [0:130]
wine_target = wine.target[0:130]


#데이터 집합을 훈련 데이터와 테스트 데이터로 분할
train_X, test_X, train_Y, test_Y = train_test_split(wine_data, wine_target, test_size = 0.2)

#데이터 건수 확인
print(len(train_X))
print(len(test_X))

#데이터 집합을 훈련 데이터와 테스트 데이터로 분할한다.
#훈련 데이터는 모형을 만들 때 사용하며, 테스트 데이터는 생성한 모형을 검증하는 데 사용한다.
#테스트 데이터는 전체 데이터의 20%가 되도록 한다.
#훈련 데이터 설명변수의 변수명은 train_X, 목적 변수의 변수명은 train_Y,
#테스트 데이터 설명변수의 변수명은 test_X, 목적변수 변수명은 test_Y로 한다
# 훈련 데이터 및 테스트 데이터의 건수는 각각 104건과 26건이다.


# 텐서 생성

# 훈련 데이터 텐서변환
train_X = torch.from_numpy(train_X).float()
train_Y = torch.from_numpy(train_Y).long()

# 테스트 데이터 텐서 변환
test_X = torch.from_numpy(test_X).float()
test_Y = torch.from_numpy(test_Y).long()

# 텐서로 변환한 데이터 건수 확인
print(train_X.shape)
print(train_Y.shape)

# 훈련 데이터의 설명변수 train_X와 목적변수 train_Y, 테스트 데이터의 설명변수 test_X와 목적변수 test_Y를 각각 텐서로 변환하고
# 변수명과 같은 이름으로 저장한다. 이때 설명변수의 타입은 Float,목적변수의 타입은 Long으로 한다.
# 텐서라는 용어는 다차원 배열이라는 의미로 보면 된다.


# 신경망 구성
class Net(nn.Module):
  def __init__(self):
    super(Net,self).__init__()
    self.fc1 = nn.Linear(13,96)
    self.fc2 = nn.Linear(96,2)

  def forward(self,x):
    x= F.relu(self.fc1(x))
    x = self.fc2(x)
    return F.log_softmax(x)


model=Net()

# 모형학습하기
criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(model.parameters(),lr=0.01)

for epoch in range(300):
  total_loss = 0

  for train_X, train_Y in train_loader:
    
    train_X, train_Y = Variable(train_X), Variable(train_Y)
    optimizer.zero_grad()
    output = model(train_X)
    loss = criterion(output, train_Y)
    loss.backward()
    optimizer.step()
    total_loss += loss.data

    if (epoch+1) % 50 == 0:
      print(epoch+1,total_loss)

결과 값


#계산 그래프 구성
test_x,test_y = Variable(test_X), Variable(test_Y)

#출력이 0 혹은 1이 되게 함
result = torch.max(model(test_x).data,1)[1]
#모형의 정확도 측정
accuracy=sum(test_y.data.numpy()==result.numpy())/len(test_y.data.numpy())
#모형의 정확도 출력
accuracy

정확도 65퍼센트가 나오는것을 확인 할 수 있다.
<전체 코드>
import torch
import numpy as np
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim 
from torch.utils.data import DataLoader, TensorDataset 

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split

import pandas as pd

wine = load_wine()
wine

pd.DataFrame(wine.data, columns=wine.feature_names)

wine.target

wine_data = wine.data [0:130]
wine_target = wine.target[0:130]

train_X, test_X, train_Y, test_Y = train_test_split(wine_data, wine_target, test_size = 0.2)

print(len(train_X))
print(len(test_X))

train_X = torch.from_numpy(train_X).float()
train_Y = torch.from_numpy(train_Y).long()


test_X = torch.from_numpy(test_X).float()
test_Y = torch.from_numpy(test_Y).long()

print(train_X.shape)
print(train_Y.shape)

train = TensorDataset(train_X, train_Y)

print(train[0])

train_loader = DataLoader(train, batch_size= 16, shuffle=True)




class Net(nn.Module):
  def __init__(self):
    super(Net,self).__init__()
    self.fc1 = nn.Linear(13,96)
    self.fc2 = nn.Linear(96,2)

  def forward(self,x):
    x= F.relu(self.fc1(x))
    x = self.fc2(x)
    return F.log_softmax(x)



model=Net()


criterion = nn.CrossEntropyLoss()

optimizer = optim.SGD(model.parameters(),lr=0.01)

for epoch in range(300):
  total_loss = 0

  for train_X, train_Y in train_loader:
    
    train_X, train_Y = Variable(train_X), Variable(train_Y)
    optimizer.zero_grad()
    output = model(train_X)
    loss = criterion(output, train_Y)
    loss.backward()
    optimizer.step()
    total_loss += loss.data

    if (epoch+1) % 50 == 0:
      print(epoch+1,total_loss)

test_x,test_y = Variable(test_X), Variable(test_Y)

result = torch.max(model(test_x).data,1)[1]
accuracy=sum(test_y.data.numpy()==result.numpy())/len(test_y.data.numpy())

accuracy