10.2.2 データ拡張の戦略

画像分類で最もよく使われ、しかも見落とされやすいテクニックの1つが、データ拡張です。
データ拡張が解決するのは「モデルが学習できない」ということではなく、次の点です。
モデルが訓練データ内の偶然の細部を、つい本物だと思い込んでしまう。
適切に拡張することで、モデルに「合理的に変化した同じ画像」をもっと見せられるため、より安定して学習できます。
学習目標
- データ拡張がなぜ汎化能力を高めるのかを理解する
- 代表的な拡張方法がどんな問題に向いているかを区別する
- 「ラベルは変わらない」という拡張の前提を理解する
- 実行できる例を通して、拡張の流れを直感でつかむ
まずは全体像をつかもう
もしあなたが第6章から来たなら、この節は次のように理解するとよいです。
- ここまでで、畳み込みネットワークが画像から特徴を学ぶことは分かっている
- ここからは、「訓練データの見た目だけを覚えすぎないようにするにはどうするか」を扱う
つまり、データ拡張はただの小技ではなく、次の点を補っています。
- モデルが現実世界の視点、明るさ、切り抜き、遮蔽の変化にどう対応するか
データ拡張を学ぶときに、新人が最初に押さえるべきなのは「変換名をどれだけ覚えるか」ではありません。まず見るべきなのは、次の流れです。
この節で本当に知りたいのは、次の2点です。
- なぜ画像分類では特に拡張が必要なのか
- 拡張が役に立つ場面と、意味を壊してしまう場面はどこか
一、なぜ画像タスクではデータ拡張が特に必要なのか?
現実世界はもともと変化する
同じ猫でも、画像が違えば次のように見えます。
- 角度が変わる
- 光の当たり方が変わる
- 背景が変わる
- 一部が隠れる
訓練データでこの変化を十分にカバーできていないと、モデルは偶然の背景を本当の特徴だと勘違いしやすくなります。
拡張は「データを増やす」ことではなく、「自然な変化を再現する」こと
1枚の画像を適切に変換しても、
多くの場合、意味はまだ変わりません。
たとえば、
- 左右反転した猫は、やはり猫です
- 少し切り抜いた犬も、やはり犬です
だからこそ、拡張はモデルをより安定して学習させる助けになります。
データ拡張を初めて学ぶとき、まず何をつかむべき?
まず大事なのは、API名の一覧ではなく、次の1文です。
拡張とは、「同じ対象が、合理的に違う見た目で現れる」ことを模擬するもの。
この感覚がつかめれば、その後に出てくる
- 反転
- 切り抜き
- 色のゆらぎ
- Mixup / CutMix
についても、「役に立つのか、それとも意味を壊しているのか」を判断しやすくなります。
たとえ話
データ拡張は、試験前に変化問題を練習するようなものです。
知識を増やすのではなく、1問の見た目だけに頼って覚えないようにするのです。
二、よく使う拡張の種類
幾何学的な拡張
たとえば、
- 反転
- 平行移動
- 切り抜き
- 回転
これは主に、次の変化に対応するのを助けます。
- 視点や位置の変化
色に関する拡張
たとえば、
- 明るさ
- コントラスト
- 彩度
これは主に、次の変化に対応するのを助けます。
- 光の条件や撮影条件の変化
組み合わせや混合の拡張
たとえば、
- Cutout
- Mixup
- CutMix
これらはより強めの手法ですが、その分、効果が高いことも多いです。
画像分類を初めてやるとき、まずどこから始めるのがよい?
一般的には、次の順番が安定です。
-
まず幾何学的な拡張から始める
直感的で、「現実の視点変化」と結びつけやすいからです。 -
次に軽めの色拡張を加える
光や撮影条件の変化に対応するためです。 -
最後に、より強い混合拡張を試す
ここまで来ると baseline があるので、本当に効果があるかを見分けやすくなります。
三、まずは最小の拡張パイプラインを動かしてみよう
以下の例は画像ライブラリに依存せず、
2次元リストでグレースケール画像を表して、拡張の核心をつかみやすくしています。
image = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
def horizontal_flip(img):
return [list(reversed(row)) for row in img]
def center_crop(img, size=2):
return [row[:size] for row in img[:size]]
def brightness_shift(img, delta=1):
return [[pixel + delta for pixel in row] for row in img]
print("original:")
for row in image:
print(row)
print("\nflip:")
for row in horizontal_flip(image):
print(row)
print("\ncrop:")
for row in center_crop(image):
print(row)
print("\nbrightness:")
for row in brightness_shift(image):
print(row)
実行結果の例:
original:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
flip:
[3, 2, 1]
[6, 5, 4]
[9, 8, 7]
crop:
[1, 2]
[4, 5]
brightness:
[2, 3, 4]
[5, 6, 7]
[8, 9, 10]
この例でまず押さえるべきこと
拡張の本質は画像ライブラリの API ではなく、
次の2点です。
- 入力に対して合理的な変換を行う
- そのとき、できるだけラベルの意味を変えない
なぜ「合理的」であることが重要なのか?
もし「6」や「9」のような数字画像をむやみに回転させると、
ラベルそのものが変わってしまうことがあります。
つまり、拡張は何でも強くすればよいわけではなく、
タスクの意味に合わせる必要があります。
これが画像タスクで特に大事な理由
画像分類のラベルは、幾何や向きに依存することがあるからです。
たとえば、
- 一般的な自然画像では左右反転しても問題ないことが多い
- 数字認識では、安易な回転でクラスの意味が変わることがある
- 検出やセグメンテーションでは、bbox や mask も一緒に変換する必要がある
つまり、拡張は「たくさん入れれば先進的」というものではなく、
- タスク本来の意味の境界を壊していないか
が大切です。

この図で押さえるべきことは1つです。拡張は、モデルに「合理的な変化」を無視させるためのものですが、ラベルの意味まで壊してはいけません。分類・検出・セグメンテーションでは、label、box、mask をそれぞれ連動して扱う必要があります。
四、Mixup はなぜ特に覚える価値があるのか?
単に画像を混ぜるだけでなく、ラベルも一緒に混ぜる
Mixup の核心は次の通りです。
- 2枚の画像を比率に応じて混ぜる
- ラベルも同じ比率で混ぜる
数字だけでつかむ直感例
img_a = [1.0, 2.0, 3.0]
img_b = [7.0, 8.0, 9.0]
label_a = [1.0, 0.0]
label_b = [0.0, 1.0]
alpha = 0.7
mixed_img = [round(alpha * a + (1 - alpha) * b, 2) for a, b in zip(img_a, img_b)]
mixed_label = [round(alpha * a + (1 - alpha) * b, 2) for a, b in zip(label_a, label_b)]
print("mixed_img:", mixed_img)
print("mixed_label:", mixed_label)
実行結果の例:
mixed_img: [2.8, 3.8, 4.8]
mixed_label: [0.7, 0.3]
なぜこの方法が効くのか?
モデルが極端な境界を覚えにくくなり、
より滑らかな決定境界を作りやすくなるからです。
五、拡張でつまずきやすいポイント
誤解1:拡張は強ければ強いほどよい
強すぎる拡張は、有効な特徴まで壊してしまうことがあります。
誤解2:どのタスクも同じ拡張でよい
分類、検出、セグメンテーションでは、拡張に対する敏感さが同じではありません。
誤解3:拡張を増やすだけで、検証しない
拡張は手段であって目的ではありません。
最終的には、検証データで本当に良くなっているかを見る必要があります。
初心者が画像分類を始めるときの、いちばん安定した拡張順序
画像分類を始めたばかりなら、次の順番がおすすめです。
- まず水平反転を使う
- 次に軽い切り抜きを加える
- 次に軽い色のゆらぎを加える
- baseline が安定したら、Mixup / CutMix を試す
こうすると、どの拡張が効いているのかを見分けやすくなります。
拡張が本当に有効かどうか、まず何を見るべき?
訓練データの loss だけを見ないでください。
より安定した判断基準は、次の通りです。
- 検証データの指標が上がっているか
- 間違い方がより自然になっているか
- モデルが背景や撮影姿勢に強く依存しなくなっているか
つまり、拡張の本当の価値は「スコアが少し上がること」だけではありません。
より安定した視覚特徴を学べるようにすることです。
まとめ
この節で最も重要なのは、次の判断を持つことです。
データ拡張の核心は、合理的な変化を模擬して、モデルにより安定した視覚特徴を学ばせることであり、訓練データ内の偶然の細部を丸暗記させないこと。
この直感があれば、後でより複雑な拡張戦略を見ても迷いにくくなります。
この節で持ち帰るべきこと
- 拡張は強ければよいのではなく、タスクの意味に合っていることが大事
- 初めてのプロジェクトでは、まず安定した拡張から始める
- 検証データが本当に良くなるかどうかが、拡張を残す価値があるかの本当の基準
ひと言でまとめるなら、こうです。
データ拡張の本質は、「画像を派手に変える」ことではなく、意味を変えない範囲でモデルにもっと多くの合理的変化を見せること。
練習
- サンプルに
vertical_flip関数を追加してみましょう。 - 考えてみましょう。なぜ、あるタスクでは回転拡張が有害になりうるのでしょうか?
- 自分の言葉で説明してみましょう。Mixup と普通の拡張のいちばん大きな違いは何でしょうか?
- 検証データの結果が下がったら、まず拡張が弱すぎると疑いますか、それとも強すぎると疑いますか?