データ拡張(Data Augmentation)は、機械学習やコンピュータビジョンにおいて使用される手法であり、既存の画像データに対して様々な変換や修正を行うことで、トレーニングデータセットのサイズと多様性を人工的に増やす手法です。データが限られている場合や、モデルがより堅牢で未知のデータに対してより良い汎化性能を持つ必要がある場合によく使用されます。
データ拡張の主な目的は、トレーニングデータに自然なバリエーションを導入することで、モデルの汎化能力を向上させ、新しい未知のデータに対して正確な予測を行えるようにすることです。
データ拡張の手法には、以下のようなさまざまな変換が含まれます。
- 幾何学的変換。画像や画像内のオブジェクトの回転、平行移動、スケーリング、反転などの操作が含まれます。
- 色調やコントラストの調整。画像の色空間、明るさ、コントラスト、彩度などの色に関連する特性を変更します。
- ノイズの追加。ランダムなノイズをデータに追加することで、モデルがノイズや不完全な入力に対してより堅牢になることがあります。
- クロッピングやリサイズ。画像を異なるサイズやアスペクト比にクロップしたり、リサイズしたりする操作です。
- 隠蔽やマスキング。データの一部に隠蔽やマスクを適用することで、モデルが難しい環境や一部が遮られた状況でオブジェクトを認識する能力を学習することができます。
これらの変換を適用することにより、データ拡張は元のデータとは異なるが、モデルが推論時に遭遇する可能性のある現実的な変動を表現した新しいサンプルを生成することができます。これによりモデルの性能を向上させ、過学習を減らし、多様な入力シナリオに対応する能力を高めることができます。
データ拡張で注意すべき事としては、あまりにも強すぎる変換を行わないことだと個人的には思います。
実際に私の場合はモデルの精度は下がってしまいましたし、誤検知も増えた様に思えます。(データセットによるかも)
あくまで現実的にあり得そうな変換に留めることが大切だと考えます。
imgaugについて
今回データ拡張用のライブラリとしてimgaugを使ってみようと思います。
imgaugは様々なフィルタを簡単に適用でき、組み合わせてランダムな順序で実行したり、複数のCPUコアで実行したりすることができます。
imgaug is a library for image augmentation in machine learning experiments. It supports a wide range of augmentation techniques, allows to easily combine these and to execute them in random order or on multiple CPU core
引用: https://imgaug.readthedocs.io/en/latest/index.html
imgaugでフィルタを適用後どのような見た目になるのかは、imgaugのgithubのexample-imagesセクションにまとめられているので分かりやすいです。
自分の手持ちのデータセットに必要なフィルタを想像しながら1つ1つ適用していくといいかと思います。
それではimgaugを試してみたいと思います。
imgaugでの画像変換をサンプル画像に適用してみる
まずは比較できる様にオリジナル画像とimgaugを適用した画像を表示する関数を作成しておきます。
import imgaug
"""
オリジナル画像とimgaugを適用した画像を表示する関数
"""
def display_aug(augment,num):
augment = augment
image = cv2.imread("/Users/hinomaruc/Desktop/blog/dataset/aidetection_cars/alexander-schimmeck-W3MXYIfyxno-unsplash.jpg")
for i in range(num):
image_aug = augment.augment_image(image)
fig,axs = plt.subplots(1,2,figsize=(20,10))
axs[0].imshow(cv2.cvtColor(image,cv2.COLOR_BGR2RGB))
axs[0].axis('off')
axs[0].set_title('Original image')
axs[1].imshow(cv2.cvtColor(image_aug,cv2.COLOR_BGR2RGB))
axs[1].axis('off')
axs[1].set_title('Augmented image')
plt.show()
次にimgaugのフィルタを設定した順番やルール通りに適用させるaugmenter変数を作成します。Sequential、SomeOf、OneOfなどを組み合わせることによって自由度高くフィルタを適用することが可能になります。
今回は左右フリップ → 画角の変更・色の変更・雨・ぼやけさせる・拡大/縮小のうち1つ以上のフィルタを順番にランダムで適用させるようなaugmenter変数を作成しました。なるべく元の画像の壊しすぎず、現実的なフィルタを選んだつもりです 笑
Sequential
List augmenter that may contain other augmenters to apply in sequence or random order.
引用: https://imgaug.readthedocs.io/en/latest/source/overview/meta.html#sequentialSomeOf
List augmenter that applies only some of its children to images.
引用: https://imgaug.readthedocs.io/en/latest/source/overview/meta.html#someofOneOf
Augmenter that always executes exactly one of its children.
引用: https://imgaug.readthedocs.io/en/latest/source/overview/meta.html#oneof
import cv2
from imgaug import augmenters as iaa
from imgaug import parameters as iap
import matplotlib.pyplot as plt
# Sequentialで上から順に画像にフィルタをかけていく
augment = iaa.Sequential([
# 50%の確率で左右にフリップさせる
iaa.Fliplr(0.5),
# 最低1つ以上適用
iaa.SomeOf((1, None), [
# 画角の調整フィルタのうち1つを選択
iaa.OneOf([
iaa.Affine(rotate=(-30, 30)),
iaa.Affine(rotate=(-30, 30), cval=(0, 255)),
iaa.Affine(translate_percent={"x": (-0.5, 0.5), "y": (-0.5, 0.5)}),
iaa.Affine(translate_percent={"x": (-0.5, 0.5), "y": (-0.5, 0.5)}, cval=(0, 255))
]),
# 色の調整フィルタのうち1つを選択
iaa.OneOf([
# 昼間
iaa.Sequential([
iaa.Multiply((1.5, 3.0)),
iaa.ChangeColorTemperature((5000, 7000))
]),
# 夕方
iaa.ChangeColorTemperature((15000, 30000)),
# 夜
iaa.Sequential([
iaa.Multiply((0.3, 0.8)),
iaa.contrast.LinearContrast((0.5, 1.0)),
iaa.ChangeColorTemperature((2000, 5000))
])
]),
# 10%の確率で雨のフィルタを付与
iaa.Sometimes(0.1, iaa.Rain(drop_size=(1, 2))),
# 10%の確率でぼやけさせるフィルタを付与
iaa.Sometimes(0.1, iaa.GaussianBlur(sigma=(5, 10))),
# 10%の確率で拡大と縮小を適応
iaa.Sometimes(0.1, iaa.Affine(scale={"x": (0.5, 1.5), "y": (0.5, 1.5)}))
])
])
# augmentを適用し5枚結果を出力する
display_aug(augment,5)
どうでしょうか?ちょっとぼやけ具合が強すぎるのでもう少し弱めてもいいかも知れません。
次に各フィルタがどう画像を変換させるのか見てみたいと思います。
各フィルタの適用結果を確認
1つ前のセクションだと確率的にフィルタを適用するので中々出現しないフィルタも出てくると思います。
想像しにくいので、実際に個々のフィルタの適用結果を見てみます。
Fliplr
左右を入れ替えた画像を生成します。
augment = iaa.Fliplr(1.0)
display_aug(augment,1)
Affine (rotate)
画像を傾けます。
augment = iaa.Affine(rotate=(-30, 30))
display_aug(augment,1)
Affine (rotate & cval)
画像を傾け、余白の色をRGB(0~255)で指定し塗りつぶします。
augment = iaa.Affine(rotate=(-30, 30), cval=(0, 255))
display_aug(augment,1)
Affine (translate_percent)
画像を縦横にシフトします。
augment = iaa.Affine(translate_percent={"x": (-0.5, 0.5), "y": (-0.5, 0.5)})
display_aug(augment,1)
Affine (translate_percent & cval)
画像を縦横にシフトし、余白の色をRGB(0~255)で指定し塗りつぶします。
augment = iaa.Affine(translate_percent={"x": (-0.5, 0.5), "y": (-0.5, 0.5)}, cval=(0, 255))
display_aug(augment,1)
Multiply & ChangeColorTemperature
画像を明るくし、昼間のようなエフェクトを追加します。
augment = iaa.Sequential([
iaa.Multiply((1.5, 3.0)),
iaa.ChangeColorTemperature((5000, 7000))
])
display_aug(augment, 1)
ChangeColorTemperature
画像にオレンジかかったエフェクトを追加し、夕方のような画像に変換します。
augment = iaa.ChangeColorTemperature((15000, 30000))
display_aug(augment, 1)
Multiply & contrast.LinearContrast & ChangeColorTemperature
画像を暗くし、青っぽいエフェクトを追加することによって夜中のような画像に変換します。
augment = iaa.Sequential([
iaa.Multiply((0.3, 0.8)),
iaa.contrast.LinearContrast((0.5, 1.0)),
iaa.ChangeColorTemperature((2000, 5000))
])
display_aug(augment, 1)
Rain
画像に雨のエフェクトを追加します。
augment = iaa.Rain(drop_size=(1, 2))
display_aug(augment, 1)
GaussianBlur
画像をぼやけさせるエフェクトを追加します。
augment = iaa.GaussianBlur(sigma=(5, 10))
display_aug(augment, 1)
Affine (scale)
画像をズームインしたりズームアウトしたりします。
augment = iaa.Affine(scale={"x": (0.5, 1.5), "y": (0.5, 1.5)})
display_aug(augment, 1)
まとめ
いかがでしょうか?imgaugでデータの拡張が簡単に出来たかと思います。
他にも黒いボックスを一面に描画し物体の一部を隠すエフェクトなどがありますので、データセットに合わせてimgaugのエフェクトを追加するといいのではないでしょうか。