2018년 12월 16일 일요일

PyTorch Example XOR using pandas DataFrame(pandas DataFrame 를 이용한 XOR PyTorch 예제)

pandas DataFrame 를 이용한 XOR PyTorch 예제

아래 예제는 csv 파일을 읽고 pytorch로 learning 후 결과를 출력하는 예제입니다.

일반적인 DataSet은 3가지가 주어집니다.

Training set은 Train하기 위한 데이터입니다.
Validation dataset은 검증하기 위한 데이터고요, 그리고 Test dataset는 최종 예측이나 값을 테스트 하기 위한 데이터입니다.

3가지 데이터가 파일로 주어질때 처리하는 방법에 대해 예제로 작성하였습니다. 3가지 데이터이지만 실제는 2가지로 주어지는 경우가 많습니다. 아래 참고
train.csv 파일은 xor의 입력은 2개이지만 출력은 일반적으로 1개입니다. 좀 더 범용적인 예제를 만들기위해서 y1,y2를 넣었으며, y2는 y1의 negative 값으로 넣었습니다. 만약 출력이 하나만 필요하다고 생각한다면 하나는 삭제하면 됩니다.
train.csv
x1,x2,y1,y2
0,0,0,1
0,1,1,0
1,0,1,0
1,1,0,1
0,1,1,0
1,1,0,1
1,0,1,0
1,1,0,1
0,1,1,0
1,1,0,1
1,0,1,0
1,1,0,1
0,1,1,0
1,1,0,1
0,1,1,0
1,1,0,1
1,0,1,0
1,1,0,1
1,1,0,1
0,1,1,0
1,1,0,1
1,0,1,0
1,1,0,1
0,1,1,0
1,1,0,1

test.csv
x1,x2
0,1
0,0
1,0
1,1
0,1
0,0
1,0
1,1
0,1
0,0
1,0
1,1

위와 같이 일반적으로 train.csv , test.csv 2가지 파일만 존재합니다. 해당 파일의 가장 큰 차이점은 y값 즉, 최종 target값을 모르기 때문에 해당값을 예측하는것이 Deep learning의 목표(goal)가 됩니다.
두개의 dataset이 주어질때 validation dataset이 필요하게 됩니다. 그것은 training set에서 일부를 validation dataset으로 사용하게 됩니다.
아래 소스에서 아래 부분입니다.
train_df : training set
val_df :validation dataset
train_df = input_df[0:int(input_row_size/2)]
val_df = input_df[int(input_row_size/2):input_row_size]

XOR 소스
import pandas as pd
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable

input_df = pd.read_csv("train.csv", header=0)

input_row_size, input_column_size = input_df.shape

# 입력의 일부를 validation 용으로 나눈다.
train_df = input_df[0:int(input_row_size/2)]
val_df = input_df[int(input_row_size/2):input_row_size]

train_X = train_df.drop(['y1', 'y2'], axis=1)
train_Y = train_df[['y1', 'y2']]

val_X = val_df.drop(['y1', 'y2'], axis=1)
val_Y = val_df[['y1', 'y2']]

train_inputs = (torch.from_numpy(train_X.values))
train_inputs = train_inputs.float()
train_targets = (torch.from_numpy(train_Y.values))
train_targets = train_targets.float()

val_inputs = (torch.from_numpy(val_X.values))
val_inputs = val_inputs.float()
val_targets = (torch.from_numpy(val_Y.values))
val_targets = val_targets.float()

EPOCHS_TO_TRAIN = 10000

use_cuda = torch.cuda.is_available()

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(2, 3, True)
        self.fc2 = nn.Linear(3, 2, True)

    def forward(self, x):
        x = F.sigmoid(self.fc1(x))
        x = self.fc2(x)
        x = F.sigmoid(x)
        return x
  
    def name(self):
        return "Net"
  
model = Net()
if use_cuda:
    model = model.cuda()

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

print("Training loop:")
for epoch in range(0, EPOCHS_TO_TRAIN):
 for phase in ['train','valid']:
  running_loss = 0.0
  if phase == 'train':
   model.train(True)
   for input, target in zip(train_inputs, train_targets):
    if use_cuda:
     input, target = input.cuda(), target.cuda()
    optimizer.zero_grad()   # zero the gradient buffers
    input = Variable(input)
    target = Variable(target)
    output = model(input)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()    # Does the update
    if use_cuda:
     running_loss += loss.data.cpu().numpy()
    else:
     running_loss += loss.data.numpy()
   if epoch % 1000 == 0:
    print("train:",epoch, running_loss)
  else:
   model.train(False)
   for input, target in zip(val_inputs, val_targets):
    if use_cuda:
     input, target = input.cuda(), target.cuda()
    input = Variable(input)
    target = Variable(target)
    output = model(input)
    loss = criterion(output, target)
    if use_cuda:
     running_loss += loss.data.cpu().numpy()
    else:
     running_loss += loss.data.numpy()
   if epoch % 1000 == 0:
    print("validation:",epoch, running_loss)

# test
test_df = pd.read_csv("test.csv", header=0)
test_inputs = (torch.from_numpy(test_df.values))
test_inputs = test_inputs.float()

print("Final results:")
for input in test_inputs:
 input = Variable(input)
 output = model(input)
 print("Input:",input,",output:",output)
 
#torch.save(model.state_dict(), model.name())

결과
Training loop:
train: 0 8.562797486782074
validation: 0 9.413674592971802
train: 1000 7.372614145278931
validation: 1000 7.221763789653778
train: 2000 4.808089405298233
validation: 2000 3.305788993835449
train: 3000 3.6996061131358147
validation: 3000 1.8894704058766365
train: 4000 3.199199952185154
validation: 4000 1.4243120700120926
train: 5000 2.6419421173632145
validation: 5000 1.1351843103766441
train: 6000 1.8101112879812717
validation: 6000 0.8552077151834965
train: 7000 1.100499752908945
validation: 7000 0.6019697394222021
train: 8000 0.7131331823766232
validation: 8000 0.4354256521910429
train: 9000 0.5095871035009623
validation: 9000 0.33376642130315304
Final results:
Input: tensor([ 0.,  1.]) ,output: tensor([ 0.9737,  0.0267])
Input: tensor([ 0.,  0.]) ,output: tensor([ 0.1409,  0.8564])
Input: tensor([ 1.,  0.]) ,output: tensor([ 0.9735,  0.0268])
Input: tensor([ 1.,  1.]) ,output: tensor([ 0.0151,  0.9848])
Input: tensor([ 0.,  1.]) ,output: tensor([ 0.9737,  0.0267])
Input: tensor([ 0.,  0.]) ,output: tensor([ 0.1409,  0.8564])
Input: tensor([ 1.,  0.]) ,output: tensor([ 0.9735,  0.0268])
Input: tensor([ 1.,  1.]) ,output: tensor([ 0.0151,  0.9848])
Input: tensor([ 0.,  1.]) ,output: tensor([ 0.9737,  0.0267])
Input: tensor([ 0.,  0.]) ,output: tensor([ 0.1409,  0.8564])
Input: tensor([ 1.,  0.]) ,output: tensor([ 0.9735,  0.0268])
Input: tensor([ 1.,  1.]) ,output: tensor([ 0.0151,  0.9848])


출력이 0~1 사이의 값을 나타내므로 loss function은 BCELoss 함수를 사용하였습니다.

필요에 따라 Net의 Model과 EPOCH값을 적절히 조절하면 다른곳에서도 사용하기 좋은 예제가 될것입니다.

Batch 처리 부분은 빠져있습니다. 한번에 다루기 어려운 많은 메모리 사용을 위해서는 batch 처리가 필요합니다. CUDA가 없는 환경이라 CUDA 병렬처리 부분 구현이 미흡합니다.



댓글 없음:

댓글 쓰기