カテゴリ:中級者向け / 過学習対策 / 画像分類

1. Mixupとは?

Mixup(ミックスアップ)は、2枚の画像とそのラベルを線形に合成して新たな学習データを作るシンプルなデータ拡張手法です。2018年に発表されて以来、ImageNetやCIFARなど様々なデータセットで有効性が報告されています。

目的

  • 過学習を防ぐ
  • モデルのロバスト性(ノイズ耐性)を向上させる
  • クラス間の境界をなめらかに学習する

2. Mixupの原理

2枚の画像 $x_i$, $x_j$ と、それぞれのラベル $y_i$, $y_j$ を以下の式で混合します:

  x' = λ * x_i + (1 - λ) * x_j
  y' = λ * y_i + (1 - λ) * y_j

ここで、$λ$(ラムダ)は [0,1] の範囲の実数で、通常は Beta分布(α, α) に従ってランダムにサンプリングされます。

このようにして「曖昧な画像と曖昧なラベル」のセットを大量に作り、モデルに柔軟な学習をさせます。

GoogleColabにてすぐ実行可能なコード例

# Mixup 実装例(Google Colab で ImageNet‑1k サイズの画像を使って可視化)
# ---------------------------------------------------------
# ▼ 使い方
# 1. Colab にこのセルを貼り付けて Shift+Enter で実行。
# 2. Mixup 後の合成画像を Matplotlib で表示します。
#
# ※ ネットワークの都合で画像が取得できない場合は、URL を手元の画像に差し替えてください。

# --- 必要ライブラリのインストール ---
!pip -q install torchvision requests pillow

# --- インポート ---
import torch, requests, io, numpy as np
import torchvision.transforms as T
import matplotlib.pyplot as plt
from PIL import Image

# --- Mixup 関数定義 ---

def mixup_data(x, y, cnt, alpha=0.4):
    #lam = np.random.beta(alpha, alpha)
    lam = 0.2 * cnt
    batch_size = x.size(0)
    index = torch.randperm(batch_size)
    mixed_x = lam * x + (1 - lam) * x[index]
    y_a, y_b = y, y[index]
    return mixed_x, y_a, y_b, lam

# --- one‑hot 生成ヘルパー ---

def to_onehot(idx, num_classes=1000):
    y = torch.zeros(num_classes)
    y[idx] = 1.0
    return y

# --- 224×224 サイズで取得可能な画像 URL ---
urls = [
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_2924_3-scaled.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2024/10/IMG_1974_2-2.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_2536.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_2537.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_2924_3-1-scaled.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_2535_2.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/IMG_1762.jpg",
    "https://chatterboxvr.com/wordpress/wp-content/uploads/2025/07/image_123650291-1.jpg",

]

# 変換パイプライン
transform = T.Compose([
    T.Resize((224, 224)),
    T.ToTensor()
])

images, labels = [], []
for i, url in enumerate(urls):
    try:
        r = requests.get(url, timeout=10)
        r.raise_for_status()
        img = Image.open(io.BytesIO(r.content)).convert("RGB")
        images.append(transform(img))
        labels.append(to_onehot(i % 1000))  # ダミー one‑hot
    except Exception as e:
        print(f"[Warning] 画像取得失敗: {url} → {e}")

# バッチテンソル化
images = torch.stack(images)  # (B,3,224,224)
labels = torch.stack(labels)  # (B,1000)
print(f"Downloaded {images.size(0)} images for mixup demo.")

# --- Mixup 実行 ---
mixed_images, y_a, y_b, lam = mixup_data(images, labels, alpha=0.4)

# --- 可視化 ---
fig, axs = plt.subplots(1, 4, figsize=(12, 3))
for i in range(4):
    img_np = mixed_images[i].permute(1, 2, 0).numpy()
    axs[i].imshow(img_np)
    axs[i].set_title(f"λ={lam:.2f}")
    axs[i].axis("off")

plt.suptitle("Mixup sample(ImageNet 224×224)")
plt.show()

【出力結果】2枚の画像が重なって見える。これがMixup

4. 使用時の注意点

  • Loss関数は通常、ラベルがone-hotであることを想定しています。Mixupではラベルが連続値になるため、CrossEntropyLoss の代わりに KLDivLossBCEWithLogitsLoss を使う必要があります。
  • テスト時はMixupしない(純粋な画像で予測)

5. 他のデータ拡張との比較・併用

手法特徴
Cutout一部をランダムに隠す
CutMix一部を他の画像と貼り替える
Mixup画像全体を線形合成(なめらか)

Mixupはシンプルで実装しやすく、特に少量データのタスクやラベルノイズの多いタスクで真価を発揮します。


まとめ

Mixupは、わずか数行のコード追加で過学習を防ぎ、モデルの汎化性能を高める便利なテクニックです。実務のプロジェクトでも、まずは alpha=0.2〜0.4 あたりから試してみると良いでしょう。

投稿者 kojiro777

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です