또르르's 개발 Story

[13-2] Colab에서 DataSet 다루기 (강아지 DataSet) 본문

부스트캠프 AI 테크 U stage/실습

[13-2] Colab에서 DataSet 다루기 (강아지 DataSet)

또르르21 2021. 2. 4. 02:20

1️⃣ 설정

 

아래 모듈들을 import 합니다.

import tarfile

import os

import shutil

import glob

import numpy as np

import matplotlib.pyplot as plt

from torch import nn, optim

from torch.autograd import Variable

colab에서는 모듈과 데이터를 저장할 수 있는 디스크도 제공하기 때문에 os module을 사용하여 현재 위치를 알 수 있습니다.

>>> os.getcwd()   # os 현재 위치

'/content'

강아지 image를 보여주는 imshow 함수를 작성합니다. (나중에 tensor image를 보여줄 때 사용)

def imshow(image, ax=None, title=None, normalize=True):

    """Imshow for Tensor."""
    
    if ax is None:
    
        fig, ax = plt.subplots()
        
    image = image.numpy().transpose((1, 2, 0))
    

    if normalize:
    
        mean = np.array([0.485, 0.456, 0.406])
        
        std = np.array([0.229, 0.224, 0.225])
        
        image = std * image + mean
        
        image = np.clip(image, 0, 1)


    ax.imshow(image)
    
    ax.spines['top'].set_visible(False)
    
    ax.spines['right'].set_visible(False)
    
    ax.spines['left'].set_visible(False)
    
    ax.spines['bottom'].set_visible(False)
    
    ax.tick_params(axis='both', length=0)
    
    ax.set_xticklabels('')
    
    ax.set_yticklabels('')
    

    return ax

 

2️⃣ 데이터 처리

 

1) 다운로드 & 압축 풀기

 

!wget 명령어를 사용해 colab disk에 다운로드합니다.

!wget http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar   

# 현재 directory 기준으로 tar파일을 다운로드(colab이 실행되는 곳에 다운로드)

/Images라는 폴더를 만들어줍니다.

TARGET_PATH = "Images"      # images.tar는 images 폴더에 사진이 들어가기 때문에 

if os.path.exists(TARGET_PATH): # 만약 dir 이름이 있다면 삭제

    shutil.rmtree(TARGET_PATH)

tar file의 압축을 풉니다.

fname = "images.tar"      # tar 파일의 압축을 푸는 것

tar = tarfile.open(fname, "r:tar")

tar.extractall()

tar.close()

tar file을 푼 후, 이미지 개수를 확인할 수 있습니다.

>>> len(os.listdir(TARGET_PATH))

120

Image file에 들어가 있던 파일들은 모두 '-'가 들어가 있어서 이름을 다시 수정합니다.

for dir_name in os.listdir(TARGET_PATH):      # jpg이름에는 '-'가 들어가 있는데 이름을 다시 수정

    breed_name = dir_name.split("-")[-1].lower()
    
    source_dir = os.path.join(TARGET_PATH, dir_name)
    
    target_dir = os.path.join(TARGET_PATH, breed_name)
    
    shutil.move(source_dir, target_dir) 

/로 구분된 강아지 이름을 나눠서 dataset list에 넣습니다.

dataset = []

for filepath in glob.iglob(f'{TARGET_PATH}/**/*.jpg', recursive=True):  #image 폴더에 있는 모든 jpg파일

    breed_name = filepath.split("/")[1]   # 강아지이름만
    
    dataset.append([filepath, breed_name])
    
dataset = np.array(dataset)

>>> print(dataset)


[['Images/sealyham_terrier/n02095889_1445.jpg' 'sealyham_terrier']
 ['Images/sealyham_terrier/n02095889_673.jpg' 'sealyham_terrier']
 ['Images/sealyham_terrier/n02095889_5212.jpg' 'sealyham_terrier']
 ...
 ['Images/rhodesian_ridgeback/n02087394_10014.jpg' 'rhodesian_ridgeback']
 ['Images/rhodesian_ridgeback/n02087394_531.jpg' 'rhodesian_ridgeback']
 ['Images/rhodesian_ridgeback/n02087394_3673.jpg' 'rhodesian_ridgeback']]

 

 

2) Train data와 Test data로 나누기

 

Sklearn module을 사용해서 나눕니다.

from sklearn.model_selection import train_test_split    # 학습 데이터와 test data로 나눔

train_image, test_image, train_target, test_target = train_test_split(dataset[:,0], dataset[:,1], stratify=dataset[:,1])

Train image shape을 확인해보면 아래와 같습니다.

>>> train_image.shape


(15435,)
>>> test_image


array(['Images/beagle/n02088364_17474.jpg',
       'Images/otterhound/n02091635_4175.jpg',
       'Images/schipperke/n02104365_3587.jpg', ...,
       'Images/coated_retriever/n02099429_1465.jpg',
       'Images/norfolk_terrier/n02094114_2394.jpg',
       'Images/coated_wheaten_terrier/n02098105_3609.jpg'], dtype='<U74')

pandas로 강아지 종의 비율들을 확인해볼 수 있습니다.

import pandas as pd

pd.Series(train_target).value_counts() / len(train_target)    # train data의 강아지 비율들


coated_retriever          0.014707
maltese_dog               0.012245
afghan_hound              0.011597
scottish_deerhound        0.011273
irish_wolfhound           0.010625
                            ...   
golden_retriever          0.007256
groenendael               0.007256
welsh_springer_spaniel    0.007256
pekinese                  0.007256
redbone                   0.007191
Length: 119, dtype: float64
import pandas as pd

pd.Series(test_target).value_counts() / len(test_target)


coated_retriever      0.014772
maltese_dog           0.012245
afghan_hound          0.011662
scottish_deerhound    0.011273
samoyed               0.010690
                        ...   
dhole                 0.007191
pekinese              0.007191
eskimo_dog            0.007191
affenpinscher         0.007191
border_collie         0.007191
Length: 119, dtype: float64

Train data와 Test data를 편하게 사용하기 위해서는 Image 폴더에 있는 전체 data를 train data folder와 test data folder로 나눠야 합니다.

DATA_PATH = "dataset"       # train folder와 test folder를 나눠서 사용

if os.path.exists(DATA_PATH):

  shutil.rmtree(DATA_PATH)
  
if not os.path.exists(DATA_PATH):

    os.mkdir(DATA_PATH)
    
    os.makedirs(os.path.join(DATA_PATH, "train"))
    
    os.makedirs(os.path.join(DATA_PATH, "test"))
    
    
    for breed_name in set(test_target):
    
        os.makedirs(os.path.join(DATA_PATH, "train", breed_name))
        
        os.makedirs(os.path.join(DATA_PATH, "test", breed_name))
import shutil

for filepath, taregt_dir in zip(train_image.tolist(), train_target.tolist()):  

    filename = filepath.split("/")[-1]
    
    source_path = filepath
    
    target_dir = os.path.join(DATA_PATH, "train", taregt_dir, filename)
    
    shutil.copy(source_path, target_dir) 
    
    
for filepath, taregt_dir in zip(test_image.tolist(), test_target.tolist()):     

    filename = filepath.split("/")[-1]
    
    source_path = filepath
    
    target_dir = os.path.join(DATA_PATH, "test", taregt_dir, filename)
    
    shutil.copy(source_path, target_dir) 

 

 

3) Image 출력하기

 

target_dir에 있는 image를 열어보면 하나가 출력됩니다.

from PIL import Image
 
 
im = Image.open(target_dir)

im

또는, 랜덤으로 10개를 출력하기 위해 matplotlib.image를 불러와서 사용이 가능합니다.

import matplotlib.pyplot as plt

import matplotlib.image as mpimg


def process(filename: str=None) -> None:

    """
    View multiple images stored in files, stacking vertically

    Arguments:
        filename: str - path to filename containing image
    """
    
    image = mpimg.imread(filename)
    
    # <something gets done here>
    
    plt.figure()
    
    plt.imshow(image)
    

    
idx = np.random.choice(len(dataset), 10)

images = dataset[:, 0][idx]

for file in images:

    process(file)
    
print(dataset[:, 1][idx])

 

 

3️⃣ Data augumentation

 

Data augumentation은 모델의 학습능률을 올리기 위해 데이터를 자르고, 붙이고, 변형하는 방식으로 데이터를 늘리는 방법입니다.

# data 뻥튀기 data augumentation

from torchvision import datasets, transforms, models


# TODO: Define transforms for the training data and testing data

train_transforms = transforms.Compose([transforms.RandomRotation(30),     # image rotation

                                       transforms.RandomResizedCrop(224), # resize
                                       
                                       transforms.RandomHorizontalFlip(), # 수평으로 만듦
                                       
                                       transforms.ToTensor(),
                                       
                                       transforms.Normalize([0.485, 0.456, 0.406],
                                       
                                                            [0.229, 0.224, 0.225])])
                                                            

test_transforms = transforms.Compose([transforms.Resize(255),     # test할 때는 center에서 224*224 모델로 만듦

                                      transforms.CenterCrop(224),
                                      
                                      transforms.ToTensor(),
                                      
                                      transforms.Normalize([0.485, 0.456, 0.406],
                                      
                                                           [0.229, 0.224, 0.225])])
                                                           

DATASET_PATH = "dataset"

# Pass transforms in here, then run the next cell to see how the transforms look

train_data = datasets.ImageFolder(DATASET_PATH + '/train', transform=train_transforms)  

# pytorch에서 datasets.imageFolder을 하면 자동으로 폴더 안에 있는 image와 label을 잡아줌(위의 transforms를 폴더 안 jpg에 적용)

test_data = datasets.ImageFolder(DATASET_PATH + '/test', transform=test_transforms)

따라서 train_data와 test_data를 보면 Transform이 어떻게 되는지를 볼 수 있습니다.

>>> train_data


Dataset ImageFolder
    Number of datapoints: 15435
    Root location: dataset/train
    StandardTransform
Transform: Compose(
               RandomRotation(degrees=[-30.0, 30.0], resample=False, expand=False)
               RandomResizedCrop(size=(224, 224), scale=(0.08, 1.0), ratio=(0.75, 1.3333), interpolation=PIL.Image.BILINEAR)
               RandomHorizontalFlip(p=0.5)
               ToTensor()
               Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
           )
>>> test_data

Dataset ImageFolder
    Number of datapoints: 5145
    Root location: dataset/test
    StandardTransform
Transform: Compose(
               Resize(size=255, interpolation=PIL.Image.BILINEAR)
               CenterCrop(size=(224, 224))
               ToTensor()
               Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
           )

 

 

4️⃣ DataLoader

 

PyTorch에서는 DataLoader를 사용해서 data를 generation 할 수 있습니다.

import torch

train_loader = torch.utils.data.DataLoader(train_data, batch_size=32, shuffle=True)

# dataLoader는 iterator 형태로 불러옴

test_loader = torch.utils.data.DataLoader(train_data, batch_size=32, shuffle=True)

iter()함수를 사용해서 4개의 image를 불러올 수 있습니다.

data_iter = iter(test_loader)


images, labels = next(data_iter)

fig, axes = plt.subplots(figsize=(10,4), ncols=4)

for ii in range(4):

    ax = axes[ii]
    
    imshow(images[ii], ax=ax, normalize=True)   # 여기서 imshow는 위에서 선언한 imshow함수

'부스트캠프 AI 테크 U stage > 실습' 카테고리의 다른 글

[14-2] LSTM using PyTorch  (0) 2021.02.04
[13-3] Google Image Data 다운로드  (0) 2021.02.04
[13-1] CNN using PyTorch  (0) 2021.02.04
[12-2] Optimizers using PyTorch  (0) 2021.02.03
[11-3] MLP using PyTorch  (0) 2021.02.02
Comments