2018년 8월 5일 일요일

PyTorch Data Loading and Processing Tutorial (2/2)



https://pytorch.org/tutorials/beginner/data_loading_tutorial.html

Compose transforms


샘플에다가 앞에서 구현한 transforms을 적용 시켜 봅니다.

이미지의 짧은쪽을 256으로 크기 변환을 원한다고 말합시다(가정 해봅시다.) 그리고 랜덤하게 그것으로 부터 224 크기의 네모를 crop(잘라내기) 합니다. 즉, 우리는 Rescale 과 RandomCrop 변환의 구성을 원합니다. torchvision.transforms.Compose 은 간단하게 호출 할수 있는 class 입니다.

뭔말인가 하면, torchvision.transforms.Compose 요 함수를 이용하는 예를 보여주는 것입니다. composed = transforms.Compose([Rescale(256), RandomCrop(224)]) 이렇게 해놓으면
for i, tsfrm in enumerate([scale, crop, composed]): <= 이것은 아래와 같이 됩니다.
i=0, tsfrm=scale
i=1, tsfrm=crop
i=2, tsfrm=composed

scale = Rescale(256)
crop = RandomCrop(128)
composed = transforms.Compose([Rescale(256),
                               RandomCrop(224)])

# Apply each of the above transforms on sample.
fig = plt.figure()
sample = face_dataset[65]
for i, tsfrm in enumerate([scale, crop, composed]):
    transformed_sample = tsfrm(sample)

    ax = plt.subplot(1, 3, i + 1)
    plt.tight_layout()
    ax.set_title(type(tsfrm).__name__)
    show_landmarks(**transformed_sample)

plt.show()




Iterating through the dataset


지금까지 한 모든 것을 조합하여 composed(구성된) 변환을 사용하여 데이터 세트를 만듭니다. 요약하면,이 데이터 세트가 샘플링 될 때마다 :

- 파일에서 이미지를 즉시 읽습니다.
- 변환은 읽은 이미지에 적용됩니다.
- 변환 중 하나가 무작위이므로 샘플링시 데이터가 증가합니다.

이전처럼 for i in range를 사용하여 생성 된 데이터 집합을 반복 할 수 있습니다.

위 내용은 별것 아닙니다. for 루프로 여러번 돌면서 데이터를 읽는것을 보여줍니다. 다만 아래 부분이 들어간다는게 주의 깊게 볼점입니다.
transform=transforms.Compose([
                                               Rescale(256),
                                               RandomCrop(224),
                                               ToTensor()
                                           ]))

transformed_dataset = FaceLandmarksDataset(csv_file='faces/face_landmarks.csv',
                                           root_dir='faces/',
                                           transform=transforms.Compose([
                                               Rescale(256),
                                               RandomCrop(224),
                                               ToTensor()
                                           ]))

for i in range(len(transformed_dataset)):
    sample = transformed_dataset[i]

    print(i, sample['image'].size(), sample['landmarks'].size())

    if i == 3:
        break
Out:
0 torch.Size([3, 224, 224]) torch.Size([68, 2])
1 torch.Size([3, 224, 224]) torch.Size([68, 2])
2 torch.Size([3, 224, 224]) torch.Size([68, 2])
3 torch.Size([3, 224, 224]) torch.Size([68, 2])
원문에서는 위와 같은 간단한 루프를 사용하면 많은것을 feature들을 놓치고 있다는데, 뭘놓치고 있는지는 모르겠습니다.

3가지를 놓치고 있다고합니다.
-데이터 일괄 처리
-데이터 섞기(셔플)
-다중 처리 작업자를 사용하여 데이터 병렬 로드

오 이러한 처리를 할 수 있는 torch.utils.data.DataLoader 이것이 있다고합니다. 그중 매개 변수 중 하나는 collate_fn입니다. collate_fn을 사용하여 샘플을 일괄 처리해야하는 방법을 지정할 수 있습니다. 그러나 대부분의 사용 사례에서는 기본값으로도 정상적으로 작동합니다. 여기에서도 기본값을 사용했네요. 따로 설정이 없습니다.

아래와 같이 사용합니다.
dataloader = DataLoader(transformed_dataset, batch_size=4,                        shuffle=True, num_workers=4)

for i_batch, sample_batched in enumerate(dataloader):
만약 여기에서 에러가 발생한다면, 아래와 같이 num_workers=0으로 설정하면 됩니다.
dataloader = DataLoader(transformed_dataset, batch_size=4,
                        shuffle=True, num_workers=0)

아래예에서는 0~3번까지 4개의 이미지만 출력하고 중지합니다.

dataloader = DataLoader(transformed_dataset, batch_size=4,
                        shuffle=True, num_workers=4)


# Helper function to show a batch
def show_landmarks_batch(sample_batched):
    """Show image with landmarks for a batch of samples."""
    images_batch, landmarks_batch = \
            sample_batched['image'], sample_batched['landmarks']
    batch_size = len(images_batch)
    im_size = images_batch.size(2)

    grid = utils.make_grid(images_batch)
    plt.imshow(grid.numpy().transpose((1, 2, 0)))

    for i in range(batch_size):
        plt.scatter(landmarks_batch[i, :, 0].numpy() + i * im_size,
                    landmarks_batch[i, :, 1].numpy(),
                    s=10, marker='.', c='r')

        plt.title('Batch from dataloader')

for i_batch, sample_batched in enumerate(dataloader):
    print(i_batch, sample_batched['image'].size(),
          sample_batched['landmarks'].size())

    # observe 4th batch and stop.
    if i_batch == 3:
        plt.figure()
        show_landmarks_batch(sample_batched)
        plt.axis('off')
        plt.ioff()
        plt.show()
        break




Out:
0 torch.Size([4, 3, 224, 224]) torch.Size([4, 68, 2])
1 torch.Size([4, 3, 224, 224]) torch.Size([4, 68, 2])
2 torch.Size([4, 3, 224, 224]) torch.Size([4, 68, 2])
3 torch.Size([4, 3, 224, 224]) torch.Size([4, 68, 2])

Afterword: torchvision


여기에서 datasets, transforms, dataloader 을 사용하고 쓰는지 보았습니다. torchvision 패키지는 약간의 공통적인 datasets , transforms을 제공합니다. 당신이 custom classes를 사용할 필요 조차도 없습니다. torchvision에서 좀 더 일반적인 데이터셋을 이용하는것 중 하나는 ImageFolder입니다. 이것은 이미지들이 아래와 같은 방법으로 구성되어 있다는것을 가정합니다.

root/ants/xxx.png
root/ants/xxy.jpeg
root/ants/xxz.png
.
.
.
root/bees/123.jpg
root/bees/nsdf3.png
root/bees/asd932_.png

‘ants’, ‘bees’ 들은 클래스 label들 입니다. 간단하게 PIL.Image로 동작되는(RandomHorizontalFlip, Scale 같은) 일반적인 변환(transforms)들을 이용할수 있습니다. dataloader 를 아래와 같이 이용할 수 있습니다.

이미지 데이터들은 아래 링크로부터 다운로드 받습니다.
https://download.pytorch.org/tutorial/hymenoptera_data.zip

그리고 아래 예제를 실행하면 됩니다. 아래예제는 데이터를 로드하는 예제이므로 결과는 아무것도 나오지 않습니다.
다만 여기에서 보여주려고 하는것은 위의 형태의 데이터들은 root='hymenoptera_data/train' 형태로 이미지 폴더의 위치를 넘겨주면 된다는 의미입니다. 해당 데이터를 다운받아서 압축을 풀어보면 이해가 쉽게 되리라 생각하면서 마치도록 하겠습니다.

import torch
from torchvision import transforms, datasets

data_transform = transforms.Compose([
        transforms.RandomSizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ])
hymenoptera_dataset = datasets.ImageFolder(root='hymenoptera_data/train',
                                           transform=data_transform)
dataset_loader = torch.utils.data.DataLoader(hymenoptera_dataset,
                                             batch_size=4, shuffle=True,
                                             num_workers=4)



소스링크
https://pytorch.org/tutorials/_downloads/data_loading_tutorial.py




























댓글 없음:

댓글 쓰기