PyTorchでデータ拡張(Data Augmentation)後の画像を表示する


pytorchを使用していて、画像のオーグメンテーションによく使用されるものをまとめました:cherry_blossom:
「画像の一部を消したいけど、それするやつの名前を忘れた・・・。」みたいな時に、参考にして下さい。

また、ここに出しているのは一部です。より詳細に知りたい方は、本家の[PyTorchのtransformsのドキュメント](https://pytorch.org/docs/stable/torchvision/transforms.html)を見て下さい。


# 準備
最初に、必要なライブラリのインポートと、今回扱うCIFAR10のデータセットのダウンロードをします。
また、画像を可視化する関数を準備しました。


```py
# モジュールのimport
import torch
from torchvision import transforms, datasets
import matplotlib.pyplot as plt
```

```py
# CIFAR10データセットのダウンロードする関数
def load_cifar10(transform):
    cifar10_dataset = datasets.CIFAR10(
                        root='./',
                        transform=transform,
                        download=True)
    return cifar10_dataset
```

```py
# CIFAR10の画像を可視化する関数
def show_img(dataset):
    plt.figure(figsize=(15, 3))
    for i in range(5):
        image, label = dataset[i]
        image = image.permute(1, 2, 0)
        plt.subplot(1, 5, i+1)
        plt.tick_params(labelbottom=False, labelleft=False, labelright=False, labeltop=False)
        plt.tick_params(bottom=False, left=False, right=False, top=False)
        plt.imshow(image)
    plt.savefig('a.png')
```

# CIFAR10データセット
CIFAR10のデータセットを実際に見てみる。CIFAR10は、(32, 32)サイズで、5万枚のtrain画像・1万枚のtest画像からなります。
labelの種類は10クラスです。airplane (飛行機), automobile (自動車), bird (鳥), cat (猫), deer (鹿), dog (犬), frog (カエル), horse (馬), ship (船), truck (トラック)です。

```py
# 画像の加工、pytorchではテンソル型にする。
transform = transforms.Compose([
    transforms.ToTensor()
])
```

```py
# CIFAR10のダウンロードと画像の可視化
cifar10_dataset = load_cifar10(transform)
show_img(cifar10_dataset)
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/88bd7a6b-cf52-ecd8-3d20-20d7e9fc6b45.png)


# Risize
画像の解像度を変更します。
CIFAR10のオリジナルのサイズは、(32, 32)です。今回は、画像のサイズを(16, 16)に解像度を落としています。

```py
transform = transforms.Compose([
    transforms.Resize(16),
    transforms.ToTensor()
])
```

```py
cifar10_dataset = load_cifar10(transform)
show_img(cifar10_dataset)
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/a28fe6e3-a28b-1e70-18b9-f990a6b7ab6e.png)


# CenterCrop
中心部分を切り出します。
CIFAR10のオリジナルのサイズは、(32, 32)です。今回は、(24, 24)サイズで、中心部分を切り出しています。testデータに適用されることが多いです。
（また、冗長になるため、今回から可視化のコードは省略します。コード自体は上のものと同じです。）


```py
transform = transforms.Compose([
    transforms.CenterCrop(24),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/f30c1fa3-bbf0-0bdd-1947-941f11bdddbd.png)


# RandomCrop
こちらは、ランダムに(24, 24)サイズで、切り出しています。
CenterCropでは、必ず中心部分を取り出していたのに対して、RandomCropでは、中心部分かもしれないし、左上に寄った部分かもしれないし、右下に寄った部分かもしれません。訓練画像に適用されることが多いです。

```py
transform = transforms.Compose([
    transforms.RandomCrop(24),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/1bdadfde-a743-86d0-f606-7dfce4981d84.png)


# RandomHorizontalFlip
与えられた確率(p)でランダムに水平反転させます。
pのデフォルト値は0.5なので、pの値を設定しなければ、半分の確率で水平反転させます。
今回は、1枚目・2枚目・3枚目が水平反転されています。

```py
transform = transforms.Compose([
    transforms.RandomHorizontalFlip(p=0.5),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/f51f7796-e7d0-8d3f-86dd-dc60d440e229.png)

# RandomVerticalFlip
与えられた確率(p)でランダムに垂直反転させます。
pのデフォルト値は0.5なので、pの値を設定しなければ、半分の確率で垂直反転させます。
今回は、1枚目・4枚目・5枚目が垂直反転されています。

```py
transform = transforms.Compose([
    transforms.RandomVerticalFlip(p=0.5),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/5aa47d1d-8ecf-05fd-a758-8fc1ce253cef.png)

# RandomRotation
与えられた角度(degrees)の範囲で、ランダムに回転します。
今回はdegrees=30としたので、-30度から+30度までの範囲をランダムに取ります。
回転軸のcenterの値(デフォルトは中心)や、回転することで現れる部分の値(デフォルトは真っ黒)を変更することも出来ます。

```py
transform = transforms.Compose([
    transforms.RandomRotation(degrees=30),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/c2335d73-a503-a048-79e6-b07d02880fc9.png)


# RandomErasing
p: Erasingされる確率。
scale: Erasingされる面積を全体の面積で割った数。デフォルト値では、全体の1/50から、1/3までErasingされる可能性があります。
ratio: Erasingされる長方形の縦横のアスペクト比。横長の長方形から、縦長の長方形まであります。
value: Erasingした範囲に適応する値です。デフォルト値では1が設定され、真っ黒になります。

```py
transform = transforms.Compose([
    transforms.RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0),
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/93efd95e-f714-1436-716f-05c0ea05dce4.png)

# Normalize
テンソル画像を平均と標準偏差で正規化します。n 個のチャンネルについて mean. (M1,...,Mn) と標準偏差: (S1,...,Sn) が n 個のチャンネルに対して与えらます。
一般的なRGBのカラー画像だと、3チャンネルあるので、mean, stdそれぞれ3つずつ指定しています。
今回用いた値は、CIFAR10データセットで有効的な値を引っ張ってきています。
(注) Normalizeは、これまでのものと異なり、Tendor型に変更してから、適応します。

```py
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/a2fe07b6-46ae-0f83-bfea-de0b01235af5.png)


# Grayscale
グレー画像に変換します。num_output_channelsで、出力画像を1チャンネルか3チャンネルかを選べます。
3チャンネルにした場合、それぞれのピクセルの3チャンネルには同じ値が入ります。

```py
transform = transforms.Compose([
    transforms.Grayscale(num_output_channels=3)
    transforms.ToTensor()
])
```

![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/b7d0f2a3-edf5-964e-6bda-d9909c897cea.png)

# RandomApply
transformを適用する確率を設定します。
例として、上記のGrayscaleを、0.5の確率で適応します。
今回は、1枚目・2枚目・5枚目がグレイスケールに変換されています。

```py
transform = transforms.Compose([
    transforms.RandomApply([transforms.Grayscale(num_output_channels=3)], p=0.5),
    transforms.ToTensor()
])
```
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566497/947fb319-9d89-812f-67d3-135efcd81564.png)

#終わりに
pytorchを触り始めて経験が浅いですので、間違いがあれば教えて下さい。
自分は良く、transformsの名前を忘れるので、日本語でまとめた一覧があれば良いなと思い、記事にまとめました。
一人でも役立つ方が居れば、嬉しいです！！:relaxed:
気になったことがあれば、コメント下さい！