PyTorch Dataset Class, transform 설명
PyTorch는 데이터를 불러오는 과정을 쉽게해주고, 또 잘 사용한다면 코드의 가독성도 보다 높여줄 수 있는 도구들을 제공합니다.
- scikit-image : 이미지 Input / Output 와 변형을 위해 필요합니다.
- pandas : CSV 파일 피싱을 보다 쉽게 해줍니다.
Dataset Class
torch.utils.data.Dataset 은 데이터셋을 나타내는 추상클래스입니다. 데이터넷은 Dataset에 상속하고 아래와 같이 오버라이드해야합니다.
- len(dataset) 에서 호출되는 __len__ 은 데이터셋의 크기를 리턴해야합니다.
- dataset[i] 에서 호출되는 __getitem__ 은 i 번째 샘플을 찾는데 사용됩니다.
데이터셋 클래스를 만들어보도록 하겠습니다. __init__을 사용해서 CSV 파일 안에 있는 데이터를 읽지만, __getitem__을 이용해서 이미지를 판독합니다. 이 방법은 모든 이미지를 메모리에 저장하지 않고 필요할때마다 읽기 때문에 메모리를 효율적으로 사용합니다.
데이터셋의 샘플은 { 'image' : image, 'label' : label } 의 사전 형태를 갖습니다. 선택적 인자인 transform 을 통해 필요한 전처리 과정을 샘플에 적용할 수 있습니다.
''' mnistDataset의 예제를 통한 Dataset 클래스 구현방법'''
import torch
from torch.utils.data import Dataset, DataLoader
import pandas as pd
class mnistDataset(Dataset):
"""mnist dataset."""
def __init__(self, file_path, transform=None):
"""
csv파일 데이터 및 라벨일 경우
file_path = 경로 + 파일
transform (callable, optional): 샘플에 적용될 Optional transform (전처리)
이미지일 경우 추가
csv_file (string): csv 파일의 경로
root_dir (string): 모든 이미지가 존재하는 디렉토리 경로
"""
self.data = [] # 데이터를 정제해 담을 행렬 생성
df_mnist = pd.read_csv(file_path) # pandas를 이용한 csv 파일 읽기
for idx in df_mnist.index:
temp_target = df_mnist.values[idx][0] # 타겟 행 받아오기
temp_input = df_mnist.values[idx][1:] # 행렬 행 받아오기
self.data.append((temp_input, temp_target)) # 타겟 / 행렬 구분된 데이터를 data에 첨부
self.transform = transform # 데이터 받아오기 이후 데이터 전처리
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
x, y = self.data[idx]
sample = {"x" : x, "y" : int(y)}
'''
이미지일 경우 이미지 파일 읽어오기 추가
if torch.is_tensor(idx):
idx = idx.tolist()
img_name = os.path.join(self.root_dir,
self.landmarks_frame.iloc[idx, 0])
image = io.imread(img_name)
landmarks = self.landmarks_frame.iloc[idx, 1:]
landmarks = np.array([landmarks])
landmarks = landmarks.astype('float').reshape(-1, 2)
sample = {'image': image, 'landmarks': landmarks}
'''
if self.transform:
sample = self.transform(sample)
return sample
# 사용 방법
train_dataset = mnistDataset("파일경로/파일.csv")
test_dataset = mnistDataset("파일경로/파일.csv")
Transform
샘플들이 다 같은 사이즈가 아닐 때 혹은 다른 상황에 사용할 수 있습니다. 대부분의 신경망(neural networks)은 고정된 크기의 이미지라고 가정합니다. 그러므로 우리는 신경망에 주기 전에 처리할 과정을 작성해야합니다. ( Preprocessing )
- Rescale : 이미지의 크기를 조절합니다.
- RandomCrop : 이미지를 무작위로 자릅니다.
- ToTensor : numpy 이미지에서 torch 이미지로 변경합니다. (축변환 필요합니다.)
간단한 함수대신에 호출 할 수 있는 클래스로 작성합니다. 이렇게 한다면, 클래스가 호출 될 때마다 Transform의 매개변수가 전달 되지 않아도 됩니다. 이와 같이, __call__ 함수를 구현해야 합니다. 필요하다면, __init__ 함수도 구현해야 합니다. 다음과 같이 transform을 사용할 수 있습니다.
ex)))) 이미지
class Rescale(object):
"""
주어진 사이즈로 샘플크기를 조정합니다.
output_size(tuple or int) : 원하는 사이즈 값
tuple인 경우 해당 tuple(output_size)이 결과물(output)의 크기가 되고,
int라면 비율을 유지하면서, 길이가 작은 쪽이 output_size가 됩니다.
"""
def __init__(self, output_size):
assert isinstance(output_size, (int, tuple))
self.output_size = output_size
def __call__(self, sample):
image, landmarks = sample['image'], sample['landmarks']
h, w = image.shape[:2]
if isinstance(self.output_size, int):
if h > w:
new_h, new_w = self.output_size * h / w, self.output_size
else:
new_h, new_w = self.output_size, self.output_size * w / h
else:
new_h, new_w = self.output_size
new_h, new_w = int(new_h), int(new_w)
img = transform.resize(image, (new_h, new_w))
landmarks = landmarks * [new_w / w, new_h / h]
return {'image': img, 'landmarks': landmarks}
class ToTensor(object):
"""numpy array를 tensor(torch)로 변환 시켜줍니다."""
def __call__(self, sample):
image, landmarks = sample['image'], sample['landmarks']
# swap color axis because
# numpy image: H x W x C
# torch image: C X H X W
image = image.transpose((2, 0, 1))
return {'image': torch.from_numpy(image),
'landmarks': torch.from_numpy(landmarks)}
저번에 올렸던 Fashion MNIST 의 행렬 사이즈를 변경할 수 있습니다.
data = []
df_mnist = pd.read_csv('파일경로/파일.csv')
for idx in df_mnist.index:
temp_input = df_mnist.values[idx][1:]
#>>> '''전처리 과정''' temp_input_reshape = temp_input.reshape([28, 28])
temp_target = df_mnist.values[idx][0]
data.append((temp_input_reshape, temp_target))
~ing
참고자료:https://tutorials.pytorch.kr/beginner/data_loading_tutorial.html