일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- numpy
- SQLD
- 엔터티
- 1x1 Convolution
- dfs
- CROSS JOIN
- 백준
- 인접리스트
- resnet
- get_dummies()
- bottleneck
- 그래프
- 연산량 감소
- 인접행렬
- Depthwise Separable Convolution
- 데이터모델링
- BFS
- depthwise convolution
- Two Pointer
- Inductive Bias
- SQLD 후기
- 정규화
- skip connection
- feature map
- mobilenet
- 식별자
- SQL
- outer join
- dp
- pytorch
- Today
- Total
SJ_Koding
02. [Dacon 교육] Fashion MNIST : 의류 클래스 예측 (csv파일)아주 쉽게 따라하기. (Pytorch 이용) 본문
02. [Dacon 교육] Fashion MNIST : 의류 클래스 예측 (csv파일)아주 쉽게 따라하기. (Pytorch 이용)
성지코딩 2022. 1. 14. 15:12csv파일로 이루어진 fasion mnist 셋을 Pytorch를 이용하여 분류하는 방법을 알아보겠습니다.
https://dacon.io/competitions/open/235594/overview/description
데이터 셋은 이 dacon 대회 사이트를 통해 다운로드 가능합니다.
먼저 필요한 모듈을 import합니다.
import pandas as pd
import numpy as np
from torch.utils.data import Dataset, DataLoader
from torch import nn
from torchvision import transforms
import matplotlib.pyplot as plt
import torch
그 후 다운로드 받은 데이터 셋을 적절한 위치에 저장한 후 pd.read_csv() 을 통해 그 파일들을 가져옵니다.
저는 Google Colab환경에서 구글드라이브를 마운트해 파일을 불러왔습니다.
이 때, lndex_col = 'index' 는 'index'의 컬럼을 인덱스 번호로 지정한다는 의미입니다.
train데이터는 train, test데이터는 test라는 변수명을 사용합니다.
train = pd.read_csv('/content/drive/MyDrive/dacon/fasion_mnist_classifier/train.csv', index_col='index')
test = pd.read_csv('/content/drive/MyDrive/dacon/fasion_mnist_classifier/test.csv', index_col='index')
train셋의 상위 5개를 출력해봅니다.
train.shape
(60000, 785)
60000개의 데이터를 가지고 있는 것을 확인할 수 있습니다.
train셋의 상위 5개를 출력해봅니다.
train.head()
출력 결과를 보면, label데이터와 pixel1 부터 pixel 784 까지 존재하는 것을 확인할 수 있고. 5 row x 785 columns의 형태를 띕니다. 여기서 추측이 하나 가능한데, 784는 28의 제곱수입니다. 즉 이 이미지는 28 * 28의 사이즈를 가질 수 있다라고 추측이 가능합니다. 각 픽셀의 숫자들은 0~255의 값을 가지고있으며, 이는 한 픽셀당 밝기값을 의미합니다.
흑백 이미지이므로 RGB값은 존재하지 않습니다.
plt.imshow(np.array(train.iloc[2, 1:]).reshape(28, 28), cmap = 'gray')
Pytorch의 Dataset을 상속받아 나만의 데이터셋 인스턴스를 생성해주는 클래스를 구현합니다.
__len__() 에서는 학습 데이터의 개수를 리턴해주고, __getitem__()은 앞서 만든 리스트의 인덱스 값을 참조해 데이터에 관한 여러 일처리를 진행한 후에 그 결과를 반환합니다. 아래의 코드에서는 __init__()에서 인자로 가져온 transform을 적용시킨 데이터를 반환하게됩니다.
class train_Dataset(Dataset):
def __init__(self, data, transform = None):
self.fashion_mnist = list(data.values)
self.transform = transform
label, img = [], []
for one_line in self.fashion_mnist:
label.append(one_line[0])
img.append(one_line[1:])
self.label = np.array(label)
self.img = np.array(img).reshape(-1, IMAGE_SIZE, IMAGE_SIZE, CHANNEL).astype('float32')
def __len__(self):
return len(self.label)
def __getitem__(self, idx):
label, img = self.label[idx], self.img[idx]
if self.transform:
img = self.transform(img)
return label, img
사용자 정의의 test_dataset클래스를 만들어줍니다. 여기서는 train_dataset과 차이가 있는데, 먼저 test셋에는 label이 존재하지 않기 때문에 append시 슬라이싱 범위를 바꿔주어야 하며 반환값이 기존 label, img에서 img하나만 반환하게 됩니다.
class test_Dataset(Dataset):
def __init__(self, data, transform = None):
self.fashion_mnist = list(data.values)
self.transform = transform
img = []
for one_line in self.fashion_mnist:
img.append(one_line[:])
self.img = np.array(img).reshape(-1, IMAGE_SIZE, IMAGE_SIZE, CHANNEL).astype('float32')
def __len__(self):
return len(self.fashion_mnist)
def __getitem__(self, idx):
img = self.img[idx]
if self.transform:
img = self.transform(img)
return img
하이퍼 파라메타를 설정합니다.
BATCH_SIZE = 25
LR = 5e-3
NUM_CLASS = 10
IMAGE_SIZE = 28
CHANNEL = 1
Train_epoch = 30
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu'
사용자 transform을 구현합니다. 여기서는 ToTensor() 하나만 적용시켜줄겁니다. ToTensor()는 값을 Tensor형으로 변환해주며 값을 0.0에서 1.0으로 스케일링 해줍니다.
그 후 위에서 구현한 train_Dataset, test_Dataset을 통해 값을 가져오고, 이를 Pytorch의 DataLoader함수에 넣어줍니다.
DataLoader함수는 데이터를 미니배치로 처리해주고, GPU를 통한 병렬처리, 학습효율의 향상효과를 가질 수 있습니다.
My_transform = transforms.Compose([
transforms.ToTensor(), # default : range [0, 255] -> [0.0, 1.0]
])
Train_data = train_Dataset(train, transform=My_transform)
Test_data = test_Dataset(test, transform=My_transform)
Train_dataloader = DataLoader(dataset=Train_data,
batch_size = BATCH_SIZE,
shuffle=False)
Test_dataloader = DataLoader(dataset=Test_data,
batch_size = 1,
shuffle=False)
class My_model(nn.Module):
def __init__(self, num_of_class):
super(My_model, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1), # 28 * 28 * 16
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)) # 14 * 14 * 16
self.layer2 = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1), # 14 * 14 * 32
nn.BatchNorm2d(32),
nn.ReLU()
# nn.MaxPool2d(kernel_size=2, stride=2)) 7 * 7 * 32
)
self.layer3 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
) # 7 * 7 * 64
self.fc = nn.Linear(7 * 7 * 64, num_of_class)
def forward(self, x):
out = self.layer1(x)
out = self.layer2(out)
out = self.layer3(out)
out = out.reshape(out.size(0), -1)
out = self.fc(out)
return out
이제 짜여진 모델을 통해 모델 학습을 진행하면 됩니다.
Adam optimizer를 사용하고 CELoss를 통해 학습을 진행합니다.
모델의 학습 순서
1. 모델에 데이터 넣기 output = model(image)
2. 로스 구하기 loss= criterion(output, label).
3. 옵티마이저 기울기 초기화하기
이상적으로 학습이 이루어지기 위해선 한번의 학습이 완료되어지면(즉, Iteration이 한번 끝나면) gradients를 항상 0으로 만들어 주어야 합니다. 만약 gradients를 0으로 초기화해주지 않으면 gradient가 의도한 방향이랑 다른 방향을 가르켜 학습이 원하는 방향으로 이루어 지지 않습니다.
출처:
https://algopoolja.tistory.com/55
4. 역전파 진행해주기
5. 최적화 과정 진행하기
여기서 최적의 모델을 얻기위해서 로스가 가장 낮은값이 나오는 경우 torch.save()를 통해 모델을 저장하고
추후 저장된 모델을 사용하여 예측을 진행하였습니다.
def train():
model = My_model(NUM_CLASS).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr = LR)
criterion = nn.CrossEntropyLoss()
min_Loss = 100000
for epoch in range(1, Train_epoch + 1):
for batch_id, (label, image) in enumerate(Train_dataloader):
label, image = label.to(device), image.to(device)
output = model(image)
loss = criterion(output, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch_id % 1000 == 0:
print('Loss :{:.4f} Epoch[{}/{}]'.format(loss.item(), epoch, Train_epoch))
if loss.item() < min_Loss:
torch.save(model, '/content/drive/MyDrive/dacon/fasion_mnist_classifier/best_model.pt')
min_Loss = loss.item()
print('Model save!! found minimum loss')
return model
아래는 학습된 모델을 통해 예측값을 반환하는 함수입니다. flatten을 해준 이유는 submission파일에 값을 대입하기 위함입니다. flatten은 다차원 데이터를 1차원으로 펴주는 역할을 수행합니다.
def test(model):
model = torch.load('/content/drive/MyDrive/dacon/fasion_mnist_classifier/best_model.pt') # 모델 불러오기
print('success load best_model')
pred = []
with torch.no_grad():
correct = 0
total = 0
for image in Test_dataloader:
image = image.to(device)
outputs = model(image)
predicted = np.array(torch.argmax(outputs, dim=1).cpu())
pred.append(predicted)
print(np.array(pred).flatten().shape)
return np.array(pred).flatten()
그리고 실행합니다.
if __name__ == '__main__':
model = train()
pred = test(model)
최소로스 0.0006일때의 모델을 저장하였습니다.
학습이 정상적으로 완료되었습니다. 이제 submission파일에 값을 넣고 제출하면 됩니다.
submission = pd.read_csv('/content/drive/MyDrive/dacon/fasion_mnist_classifier/sample_submission.csv')
submission['label'] = pred
submission
submission.to_csv('/content/drive/MyDrive/dacon/fasion_mnist_classifier/submission.csv', index=False)
정확도는 0.9119가 나왔고 97위를 기록했습니다. 성능향상보다는 기본적으로 제출하기 위한 연습이었습니다.
감사합니다.
-sjkoding-
'AI Competition' 카테고리의 다른 글
05. [Dacon Basic] 항공사 고객 만족도 예측 경진대회 (최종 2등!!) (1) | 2022.02.08 |
---|---|
04. [Dacon Basic] 집값 예측 경진대회 (0) | 2022.02.08 |
03.[Dacon Basic] 영화 리뷰 감정분석 경진대회 (최종39위 / 605명) (1) | 2022.01.20 |
01. [Dacon basic], 펭귄 몸무게 예측 경진대회 참가 코드[최종 26위 / 725명, private score : 308.10401(RMSE)] (2) | 2022.01.06 |