본문 바로가기

프로그래머/Pytorch

ants/bees classification CNN model에서 배울 수 있는 소소한 팁들(python)

ants/bees classification CNN model에서 배울 수 있는 소소한 팁들(python)

파일 목록 생성

for i, d in enumerate(dirs):
    files = os.listdir('./hymenoptera_data/' + d)

이미지 읽어 들이기

img = Image.open('./hymenoptera_data/' + d + '/' + f, 'r')

채널별로 분리해서 [0,1] 구간으로 정규화

r,g,b = resize_img.split()
r_resize_img = np.asarray(np.float32(r)/255.0)
g_resize_img = np.asarray(np.float32(g)/255.0)
b_resize_img = np.asarray(np.float32(b)/255.0)
# convert inputs to an array
rgb_resize_img = np.asarray([r_resize_img, g_resize_img, b_resize_img])

string label -> int label

dirs = ['ants', 'bees']

# 이미지의 픽셀값과 레이블을 저장할 리스트 초기화
data = [] # 설명변수
label = [] # 목적변수

# 각 폴더의 이미지 파일을 하나씩 읽어 들이여 가공하고 리스트에 추가
for i, d in enumerate(dirs):
    # 파일 목록 생성
    files = os.listdir('./hymenoptera_data/' + d)

    for f in files:
        ...
        # 가공된 이미지를 리스트에 추가
        data.append(rgb_resize_img)

        # 이미지 레이블을 리스트에 추가
        label.append(i)

설명변수를 데이터프레임으로 변환해서 화면에 출력

print("Dataframe:\n", pd.DataFrame(data[0][0])) # R채널)

Dataframe:
0 1 2 ... 125 126 127
0 0.317647 0.317647 0.317647 ... 0.313726 0.309804 0.305882
1 0.317647 0.317647 0.321569 ... 0.313726 0.313726 0.301961
2 0.321569 0.317647 0.317647 ... 0.305882 0.301961 0.305882
3 0.317647 0.317647 0.325490 ... 0.301961 0.305882 0.305882
4 0.325490 0.321569 0.325490 ... 0.305882 0.309804 0.305882
.. ... ... ... ... ... ... ...
123 0.341176 0.333333 0.333333 ... 0.545098 0.011765 0.117647
124 0.337255 0.333333 0.337255 ... 0.556863 0.125490 0.105882
125 0.337255 0.337255 0.341176 ... 0.568627 0.129412 0.105882
126 0.337255 0.337255 0.337255 ... 0.180392 0.000000 0.125490
127 0.337255 0.337255 0.337255 ... 0.141176 0.156863 0.227451

print("label: ", label)

label: [0, .... , 1, ....]

이쯤에서 data 형변환

data = np.array(data, dtype='float32')
label = np.array(label, dtype='int64')

sklearn.model_selection.train_test_split

# Split arrays or matrices into random train and test subsets
train_X, test_X, train_Y, test_Y = model_selection.train_test_split(
    data, label, test_size=0.1, random_state=48)

pytorch로 학습시키기 위해 numpy->pytorch 형변환

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

torch.utils.data.TensorDataset(*tensors)

# Dataset wrapping tensors.
# 설명변수와 목적변수 텐서를 합치기
train = TensorDataset(train_X, train_Y)

미니배치로 분할하기

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

Variable로 감싸기

# PyTorch Variable은 PyTorch Tensor와 동일한 API를 제공합니다: Tensor에서 할 수 있는 (거의) 모든 연산은 Variable에서도 할 수 있습니다; 차이점은 연산 그래프를 정의할 때 Variable을 사용하면, 자동으로 변화도를 계산할 수 있다는 것입니다.
# 계산 그래프 구성
train_x, train_y = Variable(train_x), Variable(train_y)

전체코드

import torch
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

# OS 패키지 임포트
import os
# Pillow 라이브러리 임포트
from PIL import Image
# NumPy 라이브러리 임포트
import numpy as np
# pandas 라이브러리 임포트
import pandas as pd
# scikit-learn 라이브러리 임포트
from sklearn import datasets, model_selection

dirs = ['ants', 'bees']

# 이미지의 픽셀값과 레이블을 저장할 리스트 초기화
data = [] # 설명변수
label = [] # 목적변수

# 각 폴더의 이미지 파일을 하나씩 읽어 들이여 가공하고 리스트에 추가
for i, d in enumerate(dirs):
    # 파일 목록 생성
    files = os.listdir('./hymenoptera_data/' + d)

    for f in files:
        # 이미지 읽어 들이기
        img = Image.open('./hymenoptera_data/' + d + '/' + f, 'r')
        # 128 * 128로 리사이징
        resize_img = img.resize((128, 128))
        # 채널별로 분리해서 [0,1] 구간으로 정규화
        r,g,b = resize_img.split()
        r_resize_img = np.asarray(np.float32(r)/255.0)
        g_resize_img = np.asarray(np.float32(g)/255.0)
        b_resize_img = np.asarray(np.float32(b)/255.0)
        rgb_resize_img = np.asarray([r_resize_img, g_resize_img, b_resize_img])
        # 가공된 이미지를 리스트에 추가
        data.append(rgb_resize_img)

        # 이미지 레이블을 리스트에 추가
        label.append(i)

# 설명변수를 데이터프레임으로 변환해서 화면에 출력
print("Dataframe:\n", pd.DataFrame(data[0][0])) # R채널)
print("label: ", label)

data = np.array(data, dtype='float32')
label = np.array(label, dtype='int64')

train_X, test_X, train_Y, test_Y = model_selection.train_test_split(
    data, label, test_size=0.1, random_state=48)

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

train_X = torch.from_numpy(train_X).float()
train_Y = torch.from_numpy(train_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=32, shuffle=True)

# 신경망 구성
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 합성곱층
        self.conv1 = nn.Conv2d(3, 10, 5) # 입력 채널 수, 출력 채널 수, 필터 크기
        self.conv2 = nn.Conv2d(10, 20, 5)

        # 전결합층
        self.fc1 = nn.Linear(20 * 29 * 29, 50) # 29=(((((128-5)+1)/2)-5)+1)/2
        self.fc2 = nn.Linear(50, 2)

    def forward(self, x):
        # 풀링층
        x = F.max_pool2d(F.relu(self.conv1(x)), 2) # 풀링 영역 크기
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, 20 * 29 * 29)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

# 인스턴스 생성
model = Net()

# 오차함수 객체
criterion = nn.CrossEntropyLoss()

# 최적화를 담당할 객체
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 학습 시작
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.item()
    # 50회 반복마다 누적오차 출력
    if (epoch+1) % 50 == 0:
        print(epoch+1, total_loss)

# NumPy 배열로 변환
test_X = np.array(test_X, dtype='float32')
test_Y = np.array(test_Y, dtype='int64')

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

# 텐서 크기 확인
print(test_X.shape)
print(test_Y.shape)

# 계산 그래프 구성
test_x, test_y = Variable(test_X), Variable(test_Y)
# 출력이 0 혹은 1이 되게 함
print("model(test_x).data: ", model(test_x).data)
result = torch.max(model(test_x).data, 1)[1]
# 모형의 정확도 측정
accuracy = sum(test_y.data.numpy() == result.numpy()) / len(test_y.data.numpy())

# 모형의 정확도 출력
print(accuracy)