Pytorch – torchvision で使える Transform まとめ

Pytorch – torchvision で使える Transform まとめ

概要

torchvision で提供されている Transform について紹介します。 Transform についてはまず以下の記事を参照してください。

Pytorch – Transforms、Dataset、DataLoader について解説 – pystyle

Advertisement

Transform

Transform はデータに対して行う前処理を定義します。torchvision では、画像のリサイズや切り抜きといった処理を行うための Transform が用意されています。

以下はグレースケール変換を行う Transform である Grayscale を使った例になります。

  1. Image.open() で画像を読み込む
  2. Grayscale オブジェクトを作成する
  3. 関数呼び出しで変換を行う
In [1]:
from PIL import Image
from torch.utils import data as data
from torchvision import transforms as transforms

img = Image.open("sample.jpg")
display(img)

# グレースケール変換を行う Transforms
transform = transforms.Grayscale()

# 関数呼び出しで変換を行う
img = transform(img)
img

Compose を使用すると、複数の Transform を連続して行う Transform を作成できます。画像を読み込む際にリサイズや標準化など一連の処理を行いたい場合に便利です。

  1. (256, 256) にリサイズする
  2. 画像の中心を (224, 224) で切り抜く
  3. PIL Image をテンソルに変換する
In [2]:
img = Image.open("sample.jpg")

transform = transforms.Compose(
    [transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor()]
)

# 関数呼び出しで変換を行う
img = transform(img)
print(type(img), img.shape)
<class 'torch.Tensor'> torch.Size([3, 224, 224])

torchvision の Transform

torchvision では、以下の Transform が提供されています。

Name 概要 入力 出力
Compose 複数の Transform を連続して行う PIL Image PIL Image
RandomApply 複数の Transform を指定した確率で行う PIL Image PIL Image
RandomChoice 複数の Transform から1つを選択して行う PIL Image PIL Image
RandomOrder 複数の Transform をランダムに順番を入れ替えて行う PIL Image PIL Image
Pad パディングを行う PIL Image PIL Image
CenterCrop 画像の中心を切り抜く PIL Image PIL Image
FiveCrop 4隅及び中心の計5箇所を切り抜く PIL Image PIL Image のタプル
TenCrop 元の画像及び左右反転した画像の4隅及び中心の計10箇所を切り抜く PIL Image PIL Image のタプル
Resize リサイズを行う PIL Image PIL Image
Grayscale グレースケール変換を行う PIL Image PIL Image
RandomCrop ランダムに画像を切り抜く PIL Image PIL Image
RandomResizedCrop ランダムにリサイズ及び切り抜きを行う PIL Image PIL Image
ColorJitter ランダムに明るさ、コントラスト、彩度、色相を変化させる PIL Image PIL Image
RandomGrayscale ランダムにグレースケール変換を行う PIL Image PIL Image
RandomHorizontalFlip ランダムに左右反転を行う PIL Image PIL Image
RandomVerticalFlip ランダムに上下反転を行う PIL Image PIL Image
RandomAffine ランダムにアフィン変換を行う PIL Image PIL Image
RandomPerspective ランダムに射影変換を行う PIL Image PIL Image
RandomRotation ランダムに回転を行う PIL Image PIL Image
LinearTransformation 線形変換を行う テンソル テンソル
Normalize 標準化を行う テンソル テンソル
RandomErasing ランダムに選択した領域を除去する テンソル テンソル
ToPILImage テンソルをPIL Image オブジェクトに変換する テンソル PIL Image
ToTensor PIL Image オブジェクトをテンソルに変換する PIL Image テンソル
Lambda ユーザー定義の Transform を作成する場合に利用する 任意のオブジェクト 任意のオブジェクト

サンプルコードで使用するモジュールを import します。

In [3]:
import random

import numpy as np
import torchvision.transforms as transforms
from IPython.display import display
from PIL import Image

複数の Transform を渡して作成する Transform

Compose

複数の Transform を連続して行う Transform を作成します。

Compose(transforms)
  • 引数
    • transforms (iterable of Transform) – Transform のリスト
In [4]:
transform = transforms.Compose(
    [
        transforms.Resize(256),  # 1
        transforms.CenterCrop(224),  # 2
        transforms.ToTensor(),  # 3
    ]
)
Advertisement

RandomApply

複数の Transform を指定した確率で行う Transform を作成します。

  • 引数
    • transforms (iterable of Transform) – Transform のリスト
    • p (float) – 確率
In [5]:
transform = transforms.RandomApply(
    [transforms.Resize(256), transforms.ToTensor()], p=0.5
)

RandomChoice

複数の Transform から1つを選択して行う Transform を作成します。

  • 引数
    • transforms (sequence of Transform) – Transform のリスト
In [6]:
transform = transforms.RandomChoice(
    [transforms.RandomHorizontalFlip(), transforms.RandomVerticalFlip()]
)

RandomOrder

複数の Transform をランダムに順番を入れ替えて行う Transform を作成します。

  • 引数
    • transforms (sequence of Transform) – Transform のリスト
In [7]:
transform = transforms.RandomChoice(
    [transforms.RandomHorizontalFlip(), transforms.RandomRotation(10)]
)

画像に対して行う Transform

画像の入力は PIL Image オブジェクトです。 サンプル画像として、以下を使用します。

sample.jpg

変換結果を確認するために、同じ大きさの複数枚の画像をタイル上に並べる関数を用意しました。

In [8]:
def tile_imgs(imgs, n_cols=3):
    """同じ大きさの複数枚の画像をタイル上に並べる。
    """
    n_rows = int(np.ceil(len(imgs) / n_cols))
    w, h = imgs[0].size

    # 結合後の画像
    concat_img = Image.new("RGB", (w * n_cols, h * n_rows))

    for i, img in enumerate(imgs):
        row, col = i % n_cols, i // n_cols
        concat_img.paste(img, (w * row, h * col))

    return concat_img
Advertisement

Pad

パディングを行う Transform です。

Pad(padding, fill=0, padding_mode='constant')
  • 引数
    • padding – パディング幅
      • int – 上下左右に padding だけパディングする
      • 2-ints tuple – 左右にそれぞれ padding[0]、上下にそれぞれ padding[1] だけパディングする
      • 4-ints tuple – 左に padding[0]、上に padding[1]、右に padding[2]、下に padding[3] だけパディングする
    • fill (int or 3-ints tuple) – padding_mode="constant" を指定した場合に使用する色。int の場合は各チャンネル同じ値を使用する。
    • padding_mode (str) – パディング方法
      • “constant” – 引数 fill に指定した色で埋める
      • “edge” – 一番近い画像の端の色で埋める
      • “reflect” – 画像の端で折り返す (端の色は繰り返さない)
      • “symmetric” – 画像の端で折り返す (端の色を繰り返す)

padding_mode の例を以下に示します。

padding の指定方法

In [9]:
data = np.arange(1, 26, dtype=np.uint8).reshape(5, 5)
img = Image.fromarray(data)

print("int")
transform = transforms.Pad(padding=1)
print(np.array(transform(img)))

print("2-ints tuple")
transform = transforms.Pad(padding=(2, 1))
print(np.array(transform(img)))

print("4-ints tuple")
transform = transforms.Pad(padding=(2, 1, 1, 2))
print(np.array(transform(img)))
int
[[ 0  0  0  0  0  0  0]
 [ 0  1  2  3  4  5  0]
 [ 0  6  7  8  9 10  0]
 [ 0 11 12 13 14 15  0]
 [ 0 16 17 18 19 20  0]
 [ 0 21 22 23 24 25  0]
 [ 0  0  0  0  0  0  0]]
2-ints tuple
[[ 0  0  0  0  0  0  0  0  0]
 [ 0  0  1  2  3  4  5  0  0]
 [ 0  0  6  7  8  9 10  0  0]
 [ 0  0 11 12 13 14 15  0  0]
 [ 0  0 16 17 18 19 20  0  0]
 [ 0  0 21 22 23 24 25  0  0]
 [ 0  0  0  0  0  0  0  0  0]]
4-ints tuple
[[ 0  0  0  0  0  0  0  0]
 [ 0  0  1  2  3  4  5  0]
 [ 0  0  6  7  8  9 10  0]
 [ 0  0 11 12 13 14 15  0]
 [ 0  0 16 17 18 19 20  0]
 [ 0  0 21 22 23 24 25  0]
 [ 0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0]]

padding_mode の指定方法

In [10]:
data = np.arange(1, 26, dtype=np.uint8).reshape(5, 5)
img = Image.fromarray(data)

transform = transforms.Pad(padding=2, padding_mode="constant", fill=0)
print("constant (fill=0)")
print(np.array(transform(img)))

transform = transforms.Pad(padding=2, padding_mode="edge", fill=0)
print("edge")
print(np.array(transform(img)))

transform = transforms.Pad(padding=2, padding_mode="reflect", fill=0)
print("reflect")
print(np.array(transform(img)))

transform = transforms.Pad(padding=2, padding_mode="symmetric", fill=0)
print("symmetric")
print(np.array(transform(img)))
constant (fill=0)
[[ 0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0]
 [ 0  0  1  2  3  4  5  0  0]
 [ 0  0  6  7  8  9 10  0  0]
 [ 0  0 11 12 13 14 15  0  0]
 [ 0  0 16 17 18 19 20  0  0]
 [ 0  0 21 22 23 24 25  0  0]
 [ 0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0]]
edge
[[ 1  1  1  2  3  4  5  5  5]
 [ 1  1  1  2  3  4  5  5  5]
 [ 1  1  1  2  3  4  5  5  5]
 [ 6  6  6  7  8  9 10 10 10]
 [11 11 11 12 13 14 15 15 15]
 [16 16 16 17 18 19 20 20 20]
 [21 21 21 22 23 24 25 25 25]
 [21 21 21 22 23 24 25 25 25]
 [21 21 21 22 23 24 25 25 25]]
reflect
[[13 12 11 12 13 14 15 14 13]
 [ 8  7  6  7  8  9 10  9  8]
 [ 3  2  1  2  3  4  5  4  3]
 [ 8  7  6  7  8  9 10  9  8]
 [13 12 11 12 13 14 15 14 13]
 [18 17 16 17 18 19 20 19 18]
 [23 22 21 22 23 24 25 24 23]
 [18 17 16 17 18 19 20 19 18]
 [13 12 11 12 13 14 15 14 13]]
symmetric
[[ 7  6  6  7  8  9 10 10  9]
 [ 2  1  1  2  3  4  5  5  4]
 [ 2  1  1  2  3  4  5  5  4]
 [ 7  6  6  7  8  9 10 10  9]
 [12 11 11 12 13 14 15 15 14]
 [17 16 16 17 18 19 20 20 19]
 [22 21 21 22 23 24 25 25 24]
 [22 21 21 22 23 24 25 25 24]
 [17 16 16 17 18 19 20 20 19]]

CenterCrop

画像の中心を切り抜く Transform です。

CenterCrop(size)
  • 引数
    • size – 切り抜く大きさ
      • int – 幅 size、高さ size となるように切り抜く
      • 2-ints sequence – 幅 size[0]、高さ size[1] となるように切り抜く
In [11]:
img = Image.open("sample.jpg")
transform = transforms.CenterCrop(150)

img = transform(img)
img

FiveCrop

4隅及び中心の計5箇所を切り抜く Transform です。

FiveCrop(size)
  • 引数
    • size – 切り抜く大きさ
      • int – 幅 size、高さ size となるように切り抜く
      • 2-ints sequence – 幅 size[0]、高さ size[1] となるように切り抜く
In [12]:
img = Image.open("sample.jpg")
transform = transforms.FiveCrop(150)

imgs = transform(img)
tile_imgs(imgs)

TenCrop

元の画像及び左右反転した画像に対して、それぞれ4隅及び中心の計10箇所を切り抜く Transform です。

TenCrop(size)
  • 引数
    • size – 切り抜く大きさ
      • int – 幅 size、高さ size となるように切り抜く
      • 2-ints sequence – 幅 size[0]、高さ size[1] となるように切り抜く
In [13]:
img = Image.open("sample.jpg")
transform = transforms.TenCrop(150)

imgs = transform(img)
tile_imgs(imgs)
Advertisement

Resize

リサイズを行う Transform です。

Resize(size, interpolation=2)
  • 引数
    • size – リサイズする大きさ
      • int – 短辺の長さが size となるようにアスペクト比を固定してリサイズする
      • 2-ints sequence – 幅が size[0]、高さが size[1] となるようにリサイズする
    • interpolation (int) – 補間方法
      • PIL.Image.NEAREST: 最近傍補間
      • PIL.Image.BILINEAR: バイリニア補間
      • PIL.Image.BICUBIC: バイキュービック補間
      • PIL.Image.LANCZOS: Lanczos 補間
In [14]:
img = Image.open("sample.jpg")

transform = transforms.Resize(150)
display(transform(img))

transform = transforms.Resize((150, 150))
display(transform(img))

Grayscale

グレースケール変換を行う Transform です。

Grayscale(num_output_channels=1)
  • 引数
    • num_output_channels (int) – 出力のチャンネル数。カラー画像のままにしたい場合は3を指定する。
In [15]:
img = Image.open("sample.jpg")

transform = transforms.Grayscale()
display(transform(img))

Augmentation に利用する Transform

RandomCrop

ランダムに画像を切り抜く Transform です。

RandomCrop(size, padding=None, pad_if_needed=False, fill=0, padding_mode='constant')
  • 引数
    • size – 切り抜く大きさ
      • int – 幅 size、高さ size となるように切り抜く
      • 2-ints sequence – 幅 size[0]、高さ size[1] となるように切り抜く
    • padding – パディング幅
      • int – 上下左右に padding だけパディングする
      • 2-ints tuple – 左右にそれぞれ padding[0]、上下にそれぞれ padding[1] だけパディングする
      • 4-ints tuple – 左に padding[0]、上に padding[1]、右に padding[2]、下に padding[3] だけパディングするする
    • pad_if_needed (bool) – size に指定した大きさが画像より大きい場合にパディングするかどうか
    • fill (int or 3-ints tuple) – padding_mode="constant" を指定した場合に使用する色。int の場合は各チャンネル同じ値を使用する。
    • padding_mode (str) – パディング方法
      • “constant” – 引数 fill に指定した色で埋める
      • “edge” – 一番近い画像の端の色で埋める
      • “reflect” – 画像の端で折り返す (端の色は繰り返さない)
      • “symmetric” – 画像の端で折り返す (端の色を繰り返す)
In [16]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomCrop(150)
display(transform(img))

transform = transforms.RandomCrop((100, 200))
display(transform(img))

transform = transforms.RandomCrop(250, pad_if_needed=True)
display(transform(img))
Advertisement

RandomResizedCrop

ランダムにリサイズ及び切り抜きを行う Transform です。

RandomResizedCrop(size, scale=(0.08, 1.0), ratio=(3 / 4, 4 / 3), interpolation=2)
  • 引数
    • size – リサイズする大きさ
      • int – 短辺の長さが size となるようにアスペクト比を固定してリサイズする
      • 2-ints sequence – 幅が size[0]、高さが size[1] となるようにリサイズする
    • scale (2-ints sequence) – スケールの変動幅
      • スケールは uniform(scale[0], scale[1]) で決める
    • aspect (2-ints sequence) – アスペクト比の変動幅
      • アスペクト比は uniform(aspect[0], aspect[1]) で決める
    • interpolation (int) – 補間方法
      • PIL.Image.NEAREST: 最近傍補間
      • PIL.Image.BILINEAR: バイリニア補間
      • PIL.Image.BICUBIC: バイキュービック補間
      • PIL.Image.LANCZOS: Lanczos 補間

切り抜く画像サイズは次のように決める。 元の画像の大きさを (w, h)、スケールを scale、アスペクト比を ratio としたとき、切り抜く画像の大きさ (nw, nh) を次の方程式を満たすように決定する。

$$ \begin{aligned} nw \times nh &= (w \times h) * scale \\ \frac{nw}{nh} &= ratio \end{aligned} $$
In [17]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomResizedCrop(150, scale=(0.08, 1.0), ratio=(3 / 4, 4 / 3))

imgs = [transform(img) for _ in range(6)]
tile_imgs(imgs)

ColorJitter

ランダムに明るさ、コントラスト、彩度、色相を変化させる Transform です。

ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)
  • 引数
    • brightness (float or 2-floats list/tuple, 0以上) – 明るさの変動幅
      • float – 変動幅は value ✕ uniform(max(0, 1 - brightness), 1 + brightness) で決める
      • 2-floats list/tuple – 変動幅は value ✕ uniform(brightness[0], brightness[1]) で決める
    • contrast (float or 2-floats list/tuple, 0以上) – コントラストの変動幅
      • 0以上の float
      • float – 変動幅は value ✕ uniform(max(0, 1 - contrast), 1 + contrast) で決める
      • 2-floats list/tuple – 変動幅は value ✕ uniform(contrast[0], contrast[1]) で決める
    • saturation (float or 2-floats list/tuple, 0以上) – 彩度の変動幅
      • float – 変動幅は value ✕ uniform(max(0, 1 - saturation), 1 + saturation) で決める
      • 2-floats list/tuple – 変動幅は value ✕ uniform(saturation[0], saturation[1]) で決める
    • hue (float or 2-floats list/tuple) – 色相の変動幅
      • float, $[0, 0.5]$ の範囲 – 変動幅は value ✕ uniform(max(0, 1 - hue), 1 + hue) で決める
      • 2-floats list/tuple, $[-0.5, 0.5]$ の範囲 – 変動幅は value ✕ uniform(hue[0], hue[1]) で決める
In [18]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5)

imgs = [transform(img) for _ in range(4)]
tile_imgs(imgs, n_cols=2)

RandomGrayscale

ランダムにグレースケール変換を行う Transform です。

RandomGrayscale(p=0.3)
  • 引数
    • p (float) – 確率
In [19]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomGrayscale(0.9)
display(transform(img))

RandomHorizontalFlip

ランダムに左右反転を行う Transform です。

RandomHorizontalFlip(p=0.3)
  • 引数
    • p (float) – 確率
In [20]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomHorizontalFlip(0.9)
display(transform(img))
Advertisement

RandomVerticalFlip

ランダムに上下反転を行う Transform です。

RandomVerticalFlip(p=0.3)
  • 引数
    • p (float) – 確率
In [21]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomVerticalFlip(0.9)
display(transform(img))

RandomAffine

ランダムにアフィン変換を行う Transform です。

RandomAffine(degrees, translate=None, scale=None, shear=None, resample=False, fillcolor=0)
  • 引数
    • degrees
      • float, 0以上 – 回転角度は uniform(-degrees, degrees) で決める
      • 2-floats list/tuple – 回転角度は uniform(degrees[0], degrees[1]) で決める
    • translate (2-floats list/tuple, $[0, 1]$ の範囲)
      • x 方向の移動量は uniform(-w * translate[0], w * translate[1]) で決める
      • y 方向の移動量は uniform(-h * translate[1], h * translate[1]) で決める
    • scale (2-floats list/tuple, 0以上) – スケールは uniform(scale[0], scale[1]) で決める
    • shear – せん断
      • float, 0以上 – x 軸に対するせん断の角度を uniform(-shear, shear) で決める
      • 2-floats list/tuple – x 軸に対するせん断の角度を uniform(shear[0], shear[1]) で決める
      • 4-floats list/tuple – x 軸に対するせん断の角度を uniform(shear[0], shear[1])、y 軸に対するせん断の角度を uniform(shear[2], shear[3]) で決める
    • resample (int) – 内挿方法
      • PIL.Image.NEAREST: 最近傍補間
      • PIL.Image.BOX:
      • PIL.Image.BILINEAR: バイリニア補間
      • PIL.Image.HAMMING:
      • PIL.Image.BICUBIC: バイキュービック補間
      • PIL.Image.LANCZOS: Lanczos 補完
    • fillcolor (int or 3-ints tuple) – 外挿する際に使用する色。int の場合は各チャンネル同じ値を使用する。
In [22]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomAffine(
    degrees=[-10, 10], translate=(0.1, 0.1), scale=(0.5, 1.5)
)

imgs = [transform(img) for _ in range(6)]
tile_imgs(imgs)

RandomPerspective

ランダムに射影変換を行う Transform です。

RandomPerspective(distortion_scale=0.5, p=0.5, interpolation=3, fill=0)
  • 引数
    • distortion_scale (float) – 歪ませる幅
    • p (float) – 射影変換を行う確率
    • interpolation (int) – 補間方法
      • PIL.Image.NEAREST: 最近傍補間
      • PIL.Image.BILINEAR: バイリニア補間
      • PIL.Image.BICUBIC: バイキュービック補間
      • PIL.Image.LANCZOS: Lanczos 補間
    • fill (int or 3-ints tuple) – 外挿する際に使用する色。int の場合は各チャンネル同じ値を使用する。
In [23]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomPerspective(distortion_scale=0.2, p=0.9)

imgs = [transform(img) for _ in range(6)]
tile_imgs(imgs)

RandomRotation

ランダムに回転を行う Transform です。

RandomRotation(degrees, resample=False, expand=False, center=None, fill=None)
  • 引数
    • degrees (float or 2-floats tuple)
      • float, 0以上 – 角度は uniform(-degrees, degrees) で決める
      • 2-floats tuple – 角度は uniform(degrees[0], degrees[1]) で決める
    • resample (int) – 内挿方法
      • PIL.Image.NEAREST: 最近傍補間
      • PIL.Image.BOX:
      • PIL.Image.BILINEAR: バイリニア補間
      • PIL.Image.HAMMING:
      • PIL.Image.BICUBIC: バイキュービック補間
      • PIL.Image.LANCZOS: Lanczos 補完
    • expand (bool) – 回転した際にすべての画素が収まるように出力画像の大きさを調整するかどうか
    • center (2-ints tuple) – 回転する中心
    • fill (int or 3-ints tuple) – 外挿する際に使用する色。int の場合は各チャンネル同じ値を使用する。
In [24]:
img = Image.open("sample.jpg")
random.seed(0)

transform = transforms.RandomRotation(degrees=10)

imgs = [transform(img) for _ in range(6)]
tile_imgs(imgs)
Advertisement

テンソルに対して行う Transform

LinearTransformation

線形変換を行う Transform です。

Normalize

正規化を行う Transform です。 $n$ 個のチャンネルごとの平均 $(m_1, m_2, \cdots, m_n)$ 及び標準偏差 $(s_1, s_2, \cdots, s_n)$ が与えられたとき、チャンネルごとに次のように標準化を行います。

$$ \text{output}_c = \frac{\text{input}_c – m_c}{s_c} $$
Normalize(mean, std, inplace=False)
  • 引数
    • mean (sequence of floats) – 平均
    • std (sequence of floats) – 標準偏差
    • inplace (bool) – inplace で処理を行うかどうか
In [25]:
# ImageNet の標準化
transform = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

RandomErasing

ランダムに選択した領域を除去する Transform です。

Advertisement

ToPILImage

テンソルを PIL Image に変換する Transform です。

ToPILImage(mode=None)
  • 引数
    • mode (PIL.Image mode) – 変換後の形式。None の場合は、テンソルの形状から推定する。s

ToTensor

PIL Image をテンソルに変換する Transform です。

ToTensor()

自作の Transform を作成する

Lambda に変換処理を行う関数を渡すことで、ユーザー定義の Transform が簡単に作れます。

Lambda(lambd)
  • 引数
    • lambd – ユーザー定義の関数
In [26]:
from PIL import ImageFilter

img = Image.open("sample.jpg")


def blur(img):
    """ガウシアンフィルタを適用する。
    """
    return img.filter(ImageFilter.BLUR)


transform = transforms.Lambda(blur)

img = transform(img)
img