1. 導入:何が問題で、なぜ重要か
敵対的サンプル(Adversarial Examples) とは、機械学習モデル(特に深層学習)に誤予測を引き起こす目的で、入力に人間には知覚しづらい 微小な摂動 を付与したデータです。画像・音声・自然言語など多様な入力で成立し、分類・検出・認識・生成など幅広いタスクに影響します。実運用の AI は誤認識により安全性・信頼性・説明責任を損なうため、攻撃の仕組み と 堅牢化(防御) を理解し、設計・評価に反映することが重要です。
- 定義と脅威モデル(ホワイトボックス/ブラックボックス、回避攻撃など)
- 代表的な攻撃(FGSM、PGD、CW、パッチ、転移性)と評価指標($L_p$ ノルムなど)
- 最低限の数式と PyTorch による実装例
- 実運用に向けた防御(敵対的学習、前処理、検知)と限界
- 再現可能な手順・ベンチマークに基づく検証計画
参考として、TensorFlow の日本語チュートリアルでは FGSM を定式化し、実装手順を示しています(URL は参考サイト参照)。HACARUS の翻訳『Interpretable ML』も日本語で要点を整理しています。
2. 基本概念と脅威モデル
2.1 定義
- 敵対的サンプル:モデルの損失 $J(\theta, x, y)$ を増やす方向に、入力 $x$ を微小に摂動して得る $x_{\mathrm{adv}}$ です。
- 摂動の制約:しばしば $\lVert x_{\mathrm{adv}} - x\rVert_p \le \epsilon$ を満たすように設計します。$p \in {0, 2, \infty}$ が実務でよく使われます。
- 目的の違い:非標的攻撃は予測を正解ラベルから外せば成功です。標的攻撃は攻撃者が指定したラベルへ誘導できたときに成功です。
2.2 攻撃の分類(脅威モデル)
| 観点 | 区分 | 定義 | 例 |
|---|---|---|---|
| 知識 | ホワイトボックス | モデル構造・パラメータ・勾配にアクセス | FGSM, PGD, CW |
| ブラックボックス | 入出力インターフェースのみ | 転移攻撃、スコア探索、ベイズ最適化 | |
| 目的 | 非標的(untargeted) | 正解ラベル以外なら成功 | ただの誤分類誘発 |
| 標的(targeted) | 指定ラベルへの誘導が成功条件 | 猫→犬に固定 | |
| 位相 | デジタル | 画素値や音声波形を直接改変 | ピクセル摂動 |
| 物理 | 印刷・貼付・撮影を経由 | 交通標識へのステッカー、敵対的パッチ |
非標的攻撃では「正解ラベルから外れたか」を、標的攻撃では「指定ラベルに到達したか」を分けて評価すると、攻撃成功率の解釈がぶれにくくなります。
2.3 評価指標
- ノルム:$L_0$(変更画素の個数)、$L_2$(ユークリッド距離)、$L_\infty$(最大摂動)です。
- 攻撃成功率(Attack Success Rate)、信頼度低下、クリーン精度/ロバスト精度を確認します。
- 可視性:PSNR/SSIM などの画質尺度も補助的に使います。
3. 代表的な攻撃アルゴリズム
3.1 FGSM(Fast Gradient Sign Method)
定義:
$$
x_{\mathrm{adv}} = x + \epsilon \cdot \mathrm{sign}\bigl(\nabla_x J(\theta, x, y)\bigr)
$$
性質:単段の符号勾配で高速です。$L_\infty$ 制約に整合し、ホワイトボックス前提で使います。
3.2 PGD(Projected Gradient Descent)
反復版 FGSM です。反復で摂動を更新し、毎回 $\epsilon$-球へ射影します:
$$
x^{t+1} = \Pi_{B_\epsilon(x)}\left(x^t + \alpha \cdot \mathrm{sign}\bigl(\nabla_x J(\theta, x^t, y)\bigr)\right)
$$
初期化にランダムノイズ(ランダムスタート)を入れることが多く、ロバスト最適化の基準攻撃としてよく使われます。
3.3 CW 攻撃(Carlini & Wagner)
ノルム最小化と誤分類目的を同時に最適化します:
$$
\min_\delta \ \lVert \delta \rVert_p + c \cdot f(x+\delta) \quad \text{s.t. } x+\delta \in [0,1]^n
$$
$f$ はロジット余裕(logit margin)に基づく目的です。$L_2$ が有名で、強力ですが計算コストは高めです。
3.4 敵対的パッチ(Adversarial Patch)
印刷・貼付で 物理世界 でも有効な模様を最適化する手法です。検出回避 や 誤認識誘導 に利用されます。
3.5 転移攻撃(Black-box)
サロゲート(代替)モデルで生成した摂動が、未知の本命モデルでも通用する 転移性 を利用します。
4. 数式から実装へ:最小 PyTorch 実装
以下は、入力テンソルが 0〜1 範囲に収まる単一ラベル画像分類を前提にした教育用の単純化コードです。mean/std で正規化済みのモデルにはそのまま適用せず、摂動の定義域と clamp の位置を前処理に合わせて調整してください。評価用の攻撃生成やベンチマークでは、Dropout や BatchNorm の揺らぎを避けるため
model.eval()を前提にします。
4.1 前提ユーティリティ
# 必要パッケージ: torch
# モデルの用意は読者の環境に合わせてください(例: torchvision.models.resnet18 等)
import torch
from torch import nn
def clamp01(x):
return x.clamp(0.0, 1.0)
def cross_entropy_logits(logits, y):
return nn.CrossEntropyLoss()(logits, y)
4.2 FGSM(非標的)
def fgsm(model, x, y, eps=8/255):
x_in = x.detach().clone().requires_grad_(True)
logits = model(x_in)
loss = cross_entropy_logits(logits, y)
loss.backward()
x_adv = x_in + eps * x_in.grad.sign()
return clamp01(x_adv.detach())
4.3 PGD(L∞ 制約)
def pgd_linf(model, x, y, eps=8/255, step=2/255, iters=10):
x0 = x.detach()
# ランダムスタート
x_adv = (x0 + torch.empty_like(x0).uniform_(-eps, eps)).clamp(0,1).detach()
for _ in range(iters):
x_adv.requires_grad_(True)
loss = cross_entropy_logits(model(x_adv), y)
loss.backward()
with torch.no_grad():
x_adv = x_adv + step * x_adv.grad.sign()
# 射影 (L∞ 球)
x_adv = torch.max(torch.min(x_adv, x0 + eps), x0 - eps)
x_adv = clamp01(x_adv)
x_adv = x_adv.detach()
return x_adv
4.4 CW(概念的スケルトン)
次のコードは CW 攻撃の考え方を示す簡略版です。本番評価にそのまま使う完成実装ではなく、tanh 再パラメータ化、定数 $c$ の二分探索、confidence margin などは省略しています。また、L2 ペナルティは生の
deltaに対して計算しており、clamp 後の実効摂動量とは一致しない点に注意してください。
def cw_l2(model, x, y_target, c=1.0, lr=1e-2, iters=200):
# 実運用では tanh 再パラメータ化や confidence margin などを実装します
delta = torch.zeros_like(x, requires_grad=True)
opt = torch.optim.Adam([delta], lr=lr)
num_classes = model(x[:1]).size(1) # クラス数を取得する簡易手段
for _ in range(iters):
x_adv = clamp01(x + delta)
logits = model(x_adv)
# target 以外のクラスで最も高いロジットを取得
one_hot = torch.nn.functional.one_hot(y_target, num_classes=num_classes).bool()
logits_non_target = logits.masked_fill(one_hot, float('-inf'))
max_non_target = logits_non_target.max(dim=1).values
target_logit = logits.gather(1, y_target.view(-1, 1)).squeeze(1)
# margin > 0 なら target がまだ最大クラスでない → 最小化で target を強くする
margin = (max_non_target - target_logit).mean()
loss = delta.pow(2).mean() + c * margin
opt.zero_grad()
loss.backward()
opt.step()
return clamp01(x + delta.detach())
5. 評価・ベンチマーク・実験計画
5.1 データセットとモデル
- CIFAR-10/100、ImageNet、小型 ResNet/Wide-ResNet、ViT などを候補にします。
- 事前学習重みの正規化・前処理(mean/std)は評価条件として統一します。
5.2 攻撃構成の透過性
- 乱数シード、$\epsilon$・ステップ幅・反復回数、初期化方法(ランダムスタート)、早期停止 の有無を明記します。
- 多様な攻撃 で評価(FGSM/PGD/CW/AutoAttack など)。単一攻撃のみは過大評価の原因。
5.3 指標
- クリーン精度 と ロバスト精度 を併記します。
- 平均攻撃成功率 と 最悪ケース(union of attacks)も補助指標として確認します。非標的攻撃では正解ラベルから外した割合、標的攻撃では指定ラベルに到達した割合として定義すると整理しやすいです。
5.4 再現性のための擬似コード(評価ループ)
def eval_under_attack(model, loader, attack):
model.eval()
clean_correct, robust_correct, n = 0, 0, 0
for x, y in loader:
with torch.no_grad():
clean_correct += (model(x).argmax(1) == y).sum().item()
x_adv = attack(model, x, y)
with torch.no_grad():
robust_correct += (model(x_adv).argmax(1) == y).sum().item()
n += x.size(0)
if n == 0:
return 0.0, 0.0
return clean_correct / n, robust_correct / n
6. 実例とリスク:物理世界・業務システム
- 交通標識:ステッカーやパッチで停止標識を別標識に誤認させる例です(物理貼付→撮影→誤分類)。日本語の入門記事や実験紹介が複数あり、工学的妥当性が広く議論されています(URL は参考サイト参照)。
- 監視カメラの回避:人物検出を逃れる 敵対的パッチ です。屋内外・距離・角度でロバスト化した最適化が報告されています。
- 音声コマンド:人間には無害なノイズに聞こえても、音声認識(Automatic Speech Recognition)を誤作動させる摂動が研究されています。
- マルウェア分類:機能を保持したまま特徴量を改変し、静的・動的検知を回避する手法が報告されています。
物理世界では印刷品の色域・照明・距離・モーションブラーなどが入り、期待攻撃成功率が低下しやすいです。したがって屋外ロバスト化では、視点・スケール・射影変換を取り入れた学習や評価が必要です。
7. 防御(堅牢化)の実務パターンと限界
7.1 敵対的学習(Adversarial Training)
最も実務で効果的な基盤手法の一つです。ミニバッチ内で FGSM/PGD で生成した $x_{\mathrm{adv}}$ を混在させて学習し、ロバスト精度を引き上げます。アルゴリズム上は min-max 最適化として次のように表せます。
$$
\min_\theta \ \mathbb{E}_{(x,y)} \left[ \max_{\lVert \delta \rVert_p \le \epsilon} J(\theta, x+\delta, y) \right]
$$
7.2 前処理・変換
ビット深度削減、JPEG 圧縮、平滑化、ランダムリサイズ・パディングなどが使われます。ただし 勾配遮蔽(gradient masking) に陥ると、ロバスト性の過大評価を招きます。
7.3 検知と拒否
入力統計の外れ値検知、ロジット一貫性検査、確率的テスト時拡張(TTA)などです。完全な検知は困難です。
7.4 認証ロバスト性(Certified Robustness)
ランダム化平滑化(Randomized Smoothing)により、$L_2$ 半径内の予測不変性を確率的に保証するアプローチがあります。
7.5 運用設計
- モデル外部の安全策:多層検知、意思決定の人間確認、フェイルセーフ。
- モニタリング:スコア分布・入力統計のドリフト監視、攻撃兆候の検知。
- レッドチーミング:新攻撃の横展開と継続評価。
8. 実装ガイド:最小限の敵対的学習ループ(PGD)
以下は clean loss と adversarial loss を mix_ratio で重み付けする最小例です。
def adversarial_training_epoch(model, loader, optimizer, eps=8/255, step=2/255, iters=4, mix_ratio=0.5):
if not 0.0 <= mix_ratio <= 1.0:
raise ValueError("mix_ratio must be in [0, 1].")
model.train()
for x, y in loader:
# 1) 敵対的ミニバッチの生成
model.eval()
x_adv = pgd_linf(model, x, y, eps=eps, step=step, iters=iters)
model.train()
# 2) クリーン損失と敵対的損失を重み付きで合成
logits_clean = model(x)
logits_adv = model(x_adv)
loss_clean = cross_entropy_logits(logits_clean, y)
loss_adv = cross_entropy_logits(logits_adv, y)
loss = (1.0 - mix_ratio) * loss_clean + mix_ratio * loss_adv
optimizer.zero_grad()
loss.backward()
optimizer.step()
実務 Tips
- 計算コストと精度のトレードオフを明示します。PGD 反復は妥協点(例:4〜10)から始めると整理しやすいです。
- 正規化・データ拡張・混同行列・学習曲線は、クリーン/ロバストで分けて集計します。
- 評価では 攻撃多様性 と ハイパラ開示 を徹底します。
9. よくある誤りと落とし穴
- 単一攻撃・軽負荷設定のみ でロバスト性を主張すると、過大評価になりやすいです。
- 前処理で精度維持 をそのままロバスト化と解釈すると、勾配遮蔽の典型に陥りやすいです。
- $\epsilon$・ノルム未開示 の報告は、比較や再現を難しくします。
- 物理世界の条件 を設計に反映しないと、印刷・照明・視点の違いで再現性が落ちやすいです。
- 実運用の安全設計(多層防御・監査・ログ)をモデル単体で代替しようとすると、運用上の抜け漏れが残ります。
10. まとめ:運用可能なロバスト性へ
- 敵対的サンプルは 現実の AI システム に実害を与えうるため、デジタル・物理の両位相を念頭に脅威モデルを明示して設計・評価することが重要です。
- FGSM/PGD/CW は基礎です。特に PGD は評価・学習の基準攻撃として位置付けやすいです。
- 敵対的学習 は現実的で強力な第一選択肢です。前処理・検知は補助的に扱うと整理しやすいです。
- ロバスト性は プロセス(データ、学習、評価、運用)として継続的に作り込む必要があります。
本記事の作成には、生成AI(ChatGPT / GitHub Copilot)を補助的に使用しています。
A. 参考サイト
- TensorFlow 公式(日本語):FGSM の定式化と実装
https://www.tensorflow.org/tutorials/generative/adversarial_fgsm?hl=ja - HACARUS『Interpretable ML(日本語訳)』:敵対的サンプルの概念と実例
https://hacarus.github.io/interpretable-ml-book-ja/adversarial.html - MBSD AIセキュリティ・マトリックス:FGSM の解説(日本語)
https://www.mbsd.jp/aisec_portal/attack_fgsm.html - NRIセキュア:敵対的サンプルの生成と攻撃分類の概説(日本語)
https://www.nri-secure.co.jp/blog/hostile-sample-mechanics-and-attack-classification - AIディフェンス研究所:敵対的パッチ等の入門解説(日本語)
https://jpsec.ai/attacks-that-deceive-ai/ - AutoAttack 日本語要約(ブログ)
https://kamakuraviel.hatenablog.com/entry/2022/05/29/221410
B. 関連書籍
C. 用語集
- 敵対的サンプル:微小摂動で誤分類を誘発する入力です。$\lVert \delta \rVert_p \le \epsilon$ 制約が一般的です。
- FGSM:単段の符号勾配です。$x_{\mathrm{adv}} = x + \epsilon \cdot \mathrm{sign}(\nabla_x J)$ で表します。
- PGD:反復 FGSM と射影を組み合わせた、最悪ケースに近い強攻撃です。
- CW:ノルム最小化と誤分類目的を組み合わせる連続最適化です。
- 勾配遮蔽:防御で勾配を壊し、見かけのロバスト性を得ても実際は弱い現象です。
- ロバスト精度:攻撃下での正解率です。クリーン精度 と併記します。
- 攻撃成功率:非標的攻撃では正解ラベルから外した割合、標的攻撃では指定ラベルに到達した割合です。
- 転移攻撃:代替モデルで作った摂動が本命モデルでも効く性質を利用する攻撃です。
D. 動作確認ログの読み方
未学習の小規模モデルとランダム入力を使い、記事中のコード断片が実行可能かを確かめるスモークテストを行いました。精度の良し悪しではなく、コードが最後まで正常に動くことの確認が目的です。乱数シードにより具体的な数値は変動します。
- model forward: OK (32, 10):32 件の入力に対して 10 クラスの出力が得られ、分類モデルとして必要な出力形状を確認できました。
- FGSM / PGD: max |delta| = 0.031373:$\epsilon = 8/255 \approx 0.031373$ と一致しており、$L_\infty$ 制約が正しく機能しています。
- CW: max |delta| = 0.207832:CW は $L_2$ ベースの簡略版のため、$L_\infty$ 制約はありません。FGSM/PGD とは別系統の攻撃として解釈します。
- eval_under_attack: clean=0.086, robust=0.016:未学習モデルのため精度自体は低いですが、攻撃後に性能がさらに低下する挙動を確認できました。
- adversarial_training_epoch: avg_loss=2.314084:10 クラスのランダム予測でのクロスエントロピーは $\log 10 \approx 2.3026$ 付近になるため、未学習モデルとして自然な範囲です。損失が NaN や inf にならず、学習ループが数値的に破綻しないことを確認できました。
- ALL CHECKS PASSED:出力形状、攻撃後テンソルの値域、摂動上限、評価関数の戻り値範囲、損失の有限性がすべて正常でした。

コメント