torchvision.Transforms にによるオーグメンテーションについてまとめています。
結果がわかりやすいように極端な値を入れているものが多いです。
torchvision.Transorms の使い方
そのまま学習データに使う
一般的なデータ拡張の方法です。
データを保存せずにそのままデータセットを作り、深層学習へ入っていきます。
データが増えないためすぐに学習を開始できますが、
実際にどういったデータで学習したかを後から検証できません。
from torchvision import transforms from torchvision import datasets # 画像データのルートディレクトリを指定 data_path = 'images/train' # オーグメンテーション transform = transforms.Compose([ # ここに処理を追加していく transforms.ToTensor() ]) # データセットの作成 dataset = datasets.ImageFolder(data_path, transform)
変換後のデータを保存した上で使用する
別の Python ファイルで別のフォルダに物理的に画像データを増やしていきます。
その後増やしたデータを読み込んで学習に利用します。
こちらの場合はどういった画像データを使用して学習したかを後から検証できます。
検証用データとコード
from PIL import Image from torchvision import transforms # オーグメンテーション transform = transforms.Compose([ # ここに処理を記載していく ]) # 画像の読み込み img = Image.open('images/test.png') # オーグメンテーションの実行 img = transform(img) # 編集した画像を保存 img.save('images/transformed_test.png')
下記の画像に対して前処理を行っていきます。

Compose | 連続で複数の処理を行う
最もよく使用される Transform の実行コマンドです。
Compose の中で書いた処理を順番に行っていきます。
from PIL import Image from torchvision import transforms # 前処理 transform = transforms.Compose([ # ここで画像を変換していく ]) # 画像の読み込み img = Image.open('images/test.png') # 前処理の実行 img = transform(img) # 編集した画像を保存 img.save('images/transformed_test.png')


コマンドとして使用する
コマンドとして利用するには
上記のtorchvision.transforms.functional
を利用します。
例えば Tensor型への変換であれば
from PIL import Image, ImageFilter from torchvision import transforms import torchvision.transforms.functional as TF img = Image.open('images/test.png') # Tensor型へ変換 img = TF.to_tensor(img) print(img.shape)
となります。
Tensor 型へ変換
ToTenor | 0-1 でテンソル型へ変換
from PIL import Image from torch.utils import data from torchvision import transforms # 前処理 transform = transforms.Compose([ transforms.ToTensor() ]) # 画像の読み込み img = Image.open('images/test.png') print(type(img)) print('画像サイズ', img.size) print('チャンネル数', len(img.getbands())) print(img.getextrema()) # 前処理の実行 img = transform(img) print('\n--- 変換後 ---\n') print(type(img)) print(img.shape) print('最小値', img.min()) print('最大値', img.max())
<class 'PIL.PngImagePlugin.PngImageFile'> 画像サイズ (1500, 600) チャンネル数 4 ((0, 255), (0, 255), (0, 255), (188, 255)) --- 変換後 --- <class 'torch.Tensor'> torch.Size([4, 600, 1500]) 最小値 tensor(0.) 最大値 tensor(1.)
最小値と最大値が 0 - 1 で変換されます。
PILToTensor | 0-255 でテンソル変換
from PIL import Image from torch.utils import data from torchvision import transforms # 前処理 transform = transforms.Compose([ transforms.PILToTensor() ]) # 画像の読み込み img = Image.open('images/test.png') print(type(img)) print('画像サイズ', img.size) print('チャンネル数', len(img.getbands())) print(img.getextrema()) # 前処理の実行 img = transform(img) print('\n--- 変換後 ---\n') print(type(img)) print(img.shape) print('最小値', img.min()) print('最大値', img.max())
<class 'PIL.PngImagePlugin.PngImageFile'> 画像サイズ (1500, 600) チャンネル数 4 ((0, 255), (0, 255), (0, 255), (188, 255)) --- 変換後 --- <class 'torch.Tensor'> torch.Size([4, 600, 1500]) 最小値 tensor(0, dtype=torch.uint8) 最大値 tensor(255, dtype=torch.uint8)
最小値と最大値が 0 - 255 のまま変換されます。
リサイズとトリミング
Resize | リサイズ
画像サイズを変更します。
transforms.Resize((縦, 横))
transforms.Resize(サイズ)
ひとつだけ渡した場合はアスペクト比を固定し、最大の長さが指定した値のピクセルになるようにリサイズします。

CenterCrop | 中央を基準にトリミング
中心部から指定したサイズ分だけ切り取ります。
transforms.CenterCrop(サイズ)


FiveCrop | 5カ所をトリミング
4隅と中央の5カ所を切り取ります。
transforms.FiveCrop(サイズ)

TenCrop | 10カ所をトリミング
元画像と反転させた画像に対して4隅と中央の計10カ所を切り取ります。
transforms.TenCrop(サイズ, vertical_flip=上下反転可なら True)

Pad | パディング
pad でパディングを追加します。
transforms.Pad(パディング数, fill=0, padding_mode='constant')
パディングの指定方法
from PIL import Image import numpy as np from torchvision import transforms # 検証用データ end = 256 arr = np.arange(int(end / 9), end, int(end / 9)) data = arr.reshape((3,3)) # 行列を PIL.Image 型に変換 img = Image.fromarray(data) print(np.array(img))
[[ 28 56 84] [112 140 168] [196 224 252]]
3px × 3px のグレースケール画像のデータだと仮定してください。
上記のコードでパディングの指定方法を見ていきます。
パディング数の指定
from PIL import Image import numpy as np from torchvision import transforms # 検証用データ end = 256 arr = np.arange(int(end / 9), end, int(end / 9)) data = arr.reshape((3,3)) img = Image.fromarray(data) print('\n---- 整数をひとつ渡す ----\n') transform = transforms.Pad(padding=1) print(np.array(transform(img))) print('\n---- タプルで2つ渡す (横, 縦) ----\n') transform = transforms.Pad(padding=(3, 1)) print(np.array(transform(img))) print('\n---- タプルで4つ渡す (左, 上, 右, 下) ----\n') transform = transforms.Pad(padding=(1, 2, 3, 4)) print(np.array(transform(img)))
---- 整数をひとつ渡す ---- [[ 0 0 0 0 0] [ 0 28 56 84 0] [ 0 112 140 168 0] [ 0 196 224 252 0] [ 0 0 0 0 0]] ---- タプルで2つ渡す (横, 縦) ---- [[ 0 0 0 0 0 0 0 0 0] [ 0 0 0 28 56 84 0 0 0] [ 0 0 0 112 140 168 0 0 0] [ 0 0 0 196 224 252 0 0 0] [ 0 0 0 0 0 0 0 0 0]] ---- タプルで4つ渡す (左, 上, 右, 下) ---- [[ 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0] [ 0 28 56 84 0 0 0] [ 0 112 140 168 0 0 0] [ 0 196 224 252 0 0 0] [ 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0]]
パディングモード
from PIL import Image import numpy as np from torchvision import transforms # 検証用データ end = 256 arr = np.arange(int(end / 9), end, int(end / 9)) data = arr.reshape((3,3)) img = Image.fromarray(data) print('\n---- constant ----\n') transform = transforms.Pad(padding=3, padding_mode='constant', fill=0) print(np.array(transform(img))) print('\n---- edge ----\n') transform = transforms.Pad(padding=3, padding_mode='edge', fill=0) print(np.array(transform(img))) print('\n---- reflect ----\n') transform = transforms.Pad(padding=3, padding_mode='reflect', fill=0) print(np.array(transform(img))) print('\n---- symmetric ----\n') transform = transforms.Pad(padding=3, padding_mode='symmetric', fill=0) print(np.array(transform(img)))
---- constant ---- [[ 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0] [ 0 0 0 28 56 84 0 0 0] [ 0 0 0 112 140 168 0 0 0] [ 0 0 0 196 224 252 0 0 0] [ 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0]] ---- edge ---- [[ 28 28 28 28 56 84 84 84 84] [ 28 28 28 28 56 84 84 84 84] [ 28 28 28 28 56 84 84 84 84] [ 28 28 28 28 56 84 84 84 84] [112 112 112 112 140 168 168 168 168] [196 196 196 196 224 252 252 252 252] [196 196 196 196 224 252 252 252 252] [196 196 196 196 224 252 252 252 252] [196 196 196 196 224 252 252 252 252]] ---- reflect ---- [[140 168 140 112 140 168 140 112 140] [224 252 224 196 224 252 224 196 224] [140 168 140 112 140 168 140 112 140] [ 56 84 56 28 56 84 56 28 56] [140 168 140 112 140 168 140 112 140] [224 252 224 196 224 252 224 196 224] [140 168 140 112 140 168 140 112 140] [ 56 84 56 28 56 84 56 28 56] [140 168 140 112 140 168 140 112 140]] ---- symmetric ---- [[252 224 196 196 224 252 252 224 196] [168 140 112 112 140 168 168 140 112] [ 84 56 28 28 56 84 84 56 28] [ 84 56 28 28 56 84 84 56 28] [168 140 112 112 140 168 168 140 112] [252 224 196 196 224 252 252 224 196] [252 224 196 196 224 252 252 224 196] [168 140 112 112 140 168 168 140 112] [ 84 56 28 28 56 84 84 56 28]]
edge

reflect

symmetric

ランダムなリサイズとトリミング
RandomCrop | ランダムにトリミング
transforms.RandomCrop((縦, 横), padding=None, pad_if_needed=False, fill=0, padding_mode='constant')
フラグ | 値 | 意味 |
---|---|---|
サイズ | 第一引数 | (int、int) / int | (縦, 横) / サイズ(正方形) |
padding | None / int / (int, int) / (int, int, int, int) | None 出ない場合は Pad と同じ指定方法 |
pad_if_needed | bool | サイズで指定した大きさが元画像より大きい場合にパディングするかどうか |
fill | int / (int, int, int) | constant を指定した場合に使用する色 |
padding_mode | str | Pad と同じ指定方法 |

RandomResizedCrop | ランダムなトリミングとスケール
ランダムにトリミングした上でランダムに拡大 / 縮小します。
transforms.RandomResizedCrop(150, scale=(0.08, 1.0), ratio=(3 / 4, 4 / 3))
フラグ | 値 | 意味 |
---|---|---|
サイズ | 第一引数 | (int、int) / int | (縦, 横) / サイズ(正方形) 数値ひとつのみの場合はアスペクト比固定 |
scaale | (float, float) | スケールの幅 |
ratio | (int / int, int / int) | アスペクト比 |

ランダムな反転・移動・回転・スケール
RandomHorizontalFlip | 水平に反転
transforms.RandomHorizontalFlip(p=確率)
一定の確率で画像を水平に反転させます。


RandomVerticalFlip | 垂直に反転
transforms.RandomVerticalFlip(p=確率)
一定の確率で画像を垂直に反転させます。


RandomRotation | 回転
transform.RandomRotation( 角度, expand=すべての画像が収める, center=回転する中心, fill=色)
フラグ | 値 | 意味 |
---|---|---|
角度 | 第一引数 | int / ( int, int ) | int | 最小・最大値 (int, int) / [int, int] | (最小値, 最大値) |
expand | bool | すべての画像を画面内に収めるかどうか。 初期値は False |
center | ( int, int ) | 回転する中心 |
fill | int / ( int, int, int ) | 背景色 |




RandomAffine | 回転・移動・スケール
transforms.RandomAffine( degrees=[角度の最小, 角度の最大], translate=(水平の移動量, 垂直の移動量), scale=(縮小する最小値, 拡大する最大値))
ランダムに回転・移動・拡大・縮小を行います。画像サイズは変わりません。
設定によって見切れたり、余白が大量にでる場合があります。




RandomPerspective | 遠近法変換
transforms.RandomPerspective(distortion_scale=変形量, p=確率)
変形量は 1 を超えると分割されて出てくるようになるため実用性はないように思えます。




色調補正 / フィルター
Grascale | グレースケール変換
transforms.Grayscale()

カラーパレットの赤色の部分を見るとわかりますが、明度差が無くなっています。
失われる特徴量があります。

3チャンネルのグレースケール
transforms.Grayscale(num_output_channels=3)
で変換した場合、
3チャンネルのグレースケール変換になります。
from PIL import Image from torch.utils import data from torchvision import transforms import cv2 # 前処理 transform = transforms.Compose([ transforms.Grayscale(num_output_channels=3) ]) # 画像の読み込み img = Image.open('images/test.png') # 前処理の実行 img = transform(img) img.save('images/transformed_test.png') # 配列状況の取得 before_img = cv2.imread ('images/test.png', -1 ) print(before_img.shape) transformed_img = cv2.imread ('images/transformed_test.png', -1 ) print(transformed_img.shape)
(600, 1500, 4) (600, 1500, 3)
結果は変わりませんが、次元が削減されません。


GaussianBlur | ブラーをかける
transforms.GaussianBlur(奇数のサイズ, sigma=(標準偏差))


ランダムな色調補正
ColorJitter | 明度・彩度・色相・コントラスト
ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)
フラグ | 値 | 意味 |
---|---|---|
brightness | float / (float, float) | 明度の変動値。二つ与えた場合は ( 最小, 最大 ) |
saturation | float / (float, float) | 彩度の変動値 。二つ与えた場合は ( 最小, 最大 ) |
hue | float / (float, float) | 色相の変動値 。二つ与えた場合は ( 最小, 最大 ) | 最小 -0.5, 最大 0.5 |
contrast | float / (float, float) | コントラストの変動値 。二つ与えた場合は ( 最小, 最大 ) |





RandomGrayscale | グレースケール
transforms.RandomGrayscale(確率)
ランダムにグレースケール画像に変換します。


RandomInvert | 色調の反転
transforms.RandomInvert(p=確率)
一定の確率で色調を反転させます。
アルファチャンネルが入っている場合はエラーで止まります。
実行前にアルファチャンネルを消しておく必要があります。
# アルファチャンネルを削る img = img.convert("RGB")


RandomPosterize | 階調の削減
transforms.RandomPosterize(bits=ビット数, p=確率)
一定の確率で色調を反転させます。
アルファチャンネルが入っている場合はエラーで止まります。
実行前にアルファチャンネルを消しておく必要があります。
# アルファチャンネルを削る img = img.convert("RGB")


RandomSolarize | ソラリゼーション
transforms.RandomSolarize(threshold=しきい値, p=確率)
アルファチャンネルが入っている場合はエラーで止まります。
実行前にアルファチャンネルを消しておく必要があります。
# アルファチャンネルを削る img = img.convert("RGB")

値が高すぎて白飛びしている場合に利用したりしています。

RandomAdjustSharpness | シャープ
transforms.RandomSolarize(sharpness_factor=変化量, p=確率)
sharpness_factorの値 | 効果 |
---|---|
0 | ぼかしを入れる |
1 | 元画像 |
1以上 | シャープネス |
2 | シャープネスを2倍 |
10 | 10倍 |


RandomAutocontrast | コントラスト
transforms.RandomAutocontrast(p=確率)
ランダムに自動でコントラストを調整します。
アルファチャンネルが入っている場合はエラーで止まります。
実行前にアルファチャンネルを消しておく必要があります。
# アルファチャンネルを削る img = img.convert("RGB")

調整できるパラメーターは確率のみです。そのため、コントラストに問題がなければ何の変化も起こりません。

RandomEqualize | ヒストグラム平均化
transforms.RandomEqualize(p=確率)
アルファチャンネルが入っている場合はエラーで止まります。
実行前にアルファチャンネルを消しておく必要があります。
# アルファチャンネルを削る img = img.convert("RGB")

カラーパレットの明度に引っ張られて全体の明度が持ち上がってきています。

Tensor 型に対してのみ行える処理
ToPILImage | PIL image 型へ変換
from PIL import Image from torch.utils import data from torchvision import transforms import torch # 前処理 transform = transforms.Compose([ transforms.PILToTensor(), ]) # 画像の読み込み img = Image.open('images/test.png') # 読み込んだ直後 print('読み込んだ直後') print(type(img)) # 前処理の実行 img = transform(img) print('\ntensor へ変換') print(type(img)) # PIL 型に変換 toPIL = transforms.ToPILImage() img = toPIL(img) # PIL 型の時の情報 print('\nPIL.Image へ変換') print(type(img))
読み込んだ直後 <class 'PIL.PngImagePlugin.PngImageFile'> tensor へ変換 <class 'torch.Tensor'> PIL.Image へ変換 <class 'PIL.Image.Image'>
Normalize | 線形変換
from PIL import Image from torch.utils import data from torchvision import transforms # 前処理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 画像の読み込み img = Image.open('images/test.png') print(type(img)) print('画像サイズ', img.size) print('チャンネル数', len(img.getbands())) print(img.getextrema()) # アルファチャンネルを削る img = img.convert("RGB") # 前処理の実行 img = transform(img) print('\n--- 変換後 ---\n') print(type(img)) print(img.shape) print('最小値', img.min()) print('最大値', img.max()) # PIL 型に変換 toPIL = transforms.ToPILImage() img = toPIL(img) img.save('images/transformed_test.png')
<class 'PIL.PngImagePlugin.PngImageFile'> 画像サイズ (1500, 600) チャンネル数 4 ((0, 255), (0, 255), (0, 255), (188, 255)) --- 変換後 --- <class 'torch.Tensor'> torch.Size([3, 600, 1500]) 最小値 tensor(-2.1179) 最大値 tensor(2.6400)


ConvertImageDtype | dtype の変換
from PIL import Image from torch.utils import data from torchvision import transforms import torch # 前処理 transform = transforms.Compose([ transforms.PILToTensor(), transforms.ConvertImageDtype(dtype=torch.float64) ]) # 画像の読み込み img = Image.open('images/test.png') # PIL 型の時の情報 print(type(img)) print('画像サイズ', img.size) print('チャンネル数', len(img.getbands())) print(img.getextrema()) # tenspr 型に変換 toTensor = transforms.PILToTensor () img_tensor = toTensor(img) print('\n--- 変換前の tensor ---\n') print(type(img_tensor)) print(img_tensor.shape) print('最小値', img_tensor.min()) print('最大値', img_tensor.max()) # 前処理の実行 img = transform(img) print('\n--- 変換後 ---\n') print(type(img)) print(img.shape) print('最小値', img.min()) print('最大値', img.max()) # PIL 型に変換 toPIL = transforms.ToPILImage() img = toPIL(img) # PIL 型の時の情報 print('\n--- 変換後の PIL ---\n') print(type(img)) print('画像サイズ', img.size) print('チャンネル数', len(img.getbands())) print(img.getextrema()) img.save('images/transformed_test.png')
<class 'PIL.PngImagePlugin.PngImageFile'> 画像サイズ (1500, 600) チャンネル数 4 ((0, 255), (0, 255), (0, 255), (188, 255)) --- 変換前の tensor --- <class 'torch.Tensor'> torch.Size([4, 600, 1500]) 最小値 tensor(0, dtype=torch.uint8) 最大値 tensor(255, dtype=torch.uint8) --- 変換後 --- <class 'torch.Tensor'> torch.Size([4, 600, 1500]) 最小値 tensor(0., dtype=torch.float64) 最大値 tensor(1., dtype=torch.float64) --- 変換後の PIL --- <class 'PIL.Image.Image'> 画像サイズ (1500, 600) チャンネル数 4 ((0, 255), (0, 255), (0, 255), (188, 255))
型が変わっただけで画像に変化は起こりません。
PIL に戻した段階で元画像の情報に戻ります。
RandomErasing | 一部分を消去
transforms.RandomErasing (scale=(消去領域範囲), ratio=(アスペクト比の範囲), value=どのチャンネルを消すか, inplace=インプレーするか, p=確率)
フラグ | 値 | 意味 |
---|---|---|
scale | (float, float) | 入力画像に対する消去領域の比率の範囲 |
ratio | (float, float) | 消去された領域のアスペクト比の範囲 |
value | int / (int, int, int) | デフォルトは0。単一のintの場合、すべてのピクセルを消去するために使用される。 長さが3のタプルの場合、それぞれR、G、Bチャネルを消去するために使用される。 |
inplace | bool | この変換をインプレースにするブール値。初期値は0。 |
p | float | 処理を行う確率 |
