📋 このステップで学ぶこと
ViTの課題とSwin Transformerの解決策
Window-based Self-Attentionによる効率化
Shifted Window Attentionの仕組み
Patch Mergingによるダウンサンプリング
DETR(DEtection TRansformer)の全体構造
Object Queriesの概念
Bipartite Matching(二部マッチング)
なぜNMSが不要になるのか
実装:SwinとDETRの利用方法
🪟 1. Swin Transformer
Swin Transformer (Shifted Window Transformer)は、ViTの課題を解決した効率的なTransformerモデルです。Microsoftが2021年に発表し、画像分類だけでなく物体検出やセグメンテーションにも適用可能な汎用的なモデルとなっています。
1-1. ViTの課題
まず、STEP 16で学んだViT(Vision Transformer)の課題を整理しましょう。
【ViTの3つの課題】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
課題1: グローバルAttentionの計算コスト
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ViTのSelf-Attention:
すべてのパッチ間でAttentionを計算
計算量: O(N²) ← Nはパッチ数
具体例:
224×224画像(パッチサイズ16):
パッチ数 = 14×14 = 196
計算量 = 196² = 38,416 ← 許容範囲
1024×1024画像(パッチサイズ16):
パッチ数 = 64×64 = 4,096
計算量 = 4,096² = 16,777,216 ← 約440倍!
→ 高解像度画像では計算量が爆発的に増加
→ 実用的でない
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
課題2: 単一スケールの特徴マップ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ViTの構造:
入力 → パッチ分割 → Transformer → 出力
特徴マップのサイズは一定(14×14など)
問題:
物体検出やセグメンテーションには
複数スケールの特徴が必要
例: Faster R-CNNのFPN(Feature Pyramid Network)
・1/4スケール: 小さい物体用
・1/8スケール: 中くらいの物体用
・1/16スケール: 大きい物体用
・1/32スケール: 非常に大きい物体用
→ ViTには複数スケールの特徴がない
→ 物体検出への直接適用が難しい
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
課題3: 固定解像度への依存
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ViTの制約:
224×224で訓練 → 224×224でしか使えない
(位置埋め込みが固定サイズ)
問題:
異なる解像度の画像に対応できない
位置埋め込みの補間が必要
1-2. Swin Transformerの解決策
💡 Swin Transformerの3つの革新
1. Window-based Attention
グローバルAttentionの代わりに、局所的なWindow内でのみAttention
→ 計算量をO(N²)からO(N)に削減
2. Shifted Window
Window間の情報交換のため、Windowの位置をずらす
→ 局所性を維持しながらグローバルな情報も学習
3. 階層的構造
Patch Mergingでダウンサンプリング
→ CNNのような複数スケールの特徴マップを生成
→ 物体検出、セグメンテーションに対応
1-3. Swin Transformerの全体構造
【Swin Transformerのアーキテクチャ】
入力画像(例: 224×224×3)
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Patch Partition(パッチ分割)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像を4×4のパッチに分割
224×224 → 56×56パッチ
各パッチ: 4×4×3 = 48次元
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Linear Embedding(線形埋め込み)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各パッチを埋め込み次元に変換
48次元 → C次元(Swin-Tの場合 C=96)
出力: 56×56×96
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Swin Transformer Block × 2
・Window-based Self-Attention
・Shifted Window-based Self-Attention
出力: 56×56×96(解像度維持)
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Patch Merging
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2×2パッチを1つに統合
56×56×96 → 28×28×192
解像度1/2、チャンネル2倍
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 2
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Swin Transformer Block × 2
出力: 28×28×192
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Patch Merging
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
28×28×192 → 14×14×384
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Swin Transformer Block × 6
出力: 14×14×384
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Patch Merging
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14×14×384 → 7×7×768
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 4
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Swin Transformer Block × 2
出力: 7×7×768
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Classification Head(分類の場合)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Global Average Pooling → Linear → クラス数
【CNNとの類似性】
Swin Transformer CNN(ResNet)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 1: 56×56 conv2: 56×56
Stage 2: 28×28 conv3: 28×28
Stage 3: 14×14 conv4: 14×14
Stage 4: 7×7 conv5: 7×7
→ 同じような階層構造
→ 物体検出のFPNにそのまま使える!
1-4. Window-based Self-Attention
Swin Transformerの核心技術であるWindow-based Self-Attention について詳しく見ていきましょう。
【Window-based Self-Attentionの仕組み】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
基本アイデア
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ViT: 全パッチ間でAttention(グローバル)
Swin: Window内のパッチ間のみAttention(ローカル)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
視覚的な説明
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
56×56の特徴マップをWindowに分割(Windowサイズ: 7×7):
┌───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
│ Win1 │ Win2 │ Win3 │ Win4 │ Win5 │ Win6 │ Win7 │ Win8 │
│ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │
├───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ Win9 │ Win10 │ Win11 │ Win12 │ Win13 │ Win14 │ Win15 │ Win16 │
│ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │ 7×7 │
├───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ … │ … │ … │ … │ … │ … │ … │ … │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘
Window数: 8×8 = 64個
各Windowのパッチ数: 7×7 = 49個
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Attention計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Window内のパッチ間のみでAttention:
Window 1内:
パッチ1 ↔ パッチ2, パッチ3, … パッチ49
パッチ2 ↔ パッチ1, パッチ3, … パッチ49
…
→ 49×49のAttention行列
同じ計算を64個のWindowで独立に実行
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
計算量の比較
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
グローバルAttention(ViT):
全パッチ数: 56×56 = 3,136
計算量: 3,136² = 9,830,496
Window-based Attention(Swin):
1 Windowの計算量: 49² = 2,401
全Windowの計算量: 2,401 × 64 = 153,664
削減率: 153,664 / 9,830,496 ≈ 1.56%
→ 約64倍の効率化!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
計算量のオーダー
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ViT: O(N²) ← Nはパッチ数
Swin: O(N × M²) ← MはWindow内パッチ数(固定)
= O(N) ← Mは定数なので
→ 画像サイズに対して線形!
→ 高解像度画像にも対応可能
1-5. Shifted Window Attention
Window-based Attentionには1つ問題があります。Window間の情報交換ができない ことです。Shifted Window Attentionはこの問題を解決します。
【Window-based Attentionの問題】
物体がWindowの境界をまたぐ場合:
┌───────┬───────┐
│ 🐱 │ │ ← 猫の左半分はWindow 1
│ 左半分 │ │
├───────┼───────┤
│ │ 🐱 │ ← 猫の右半分はWindow 4
│ │ 右半分 │
└───────┴───────┘
問題:
・猫の左半分と右半分が別々のWindowで処理
・Window間でAttentionがないので情報交換できない
・猫全体として認識できない!
【Shifted Window Attentionの解決策】
アイデア:
奇数層(Layer 1, 3, 5, …): 通常のWindow分割
偶数層(Layer 2, 4, 6, …): Windowをシフト(ずらす)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Layer L(通常のWindow分割)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─────────┬─────────┬─────────┬─────────┐
│ Window1 │ Window2 │ Window3 │ Window4 │
│ 7×7 │ 7×7 │ 7×7 │ 7×7 │
├─────────┼─────────┼─────────┼─────────┤
│ Window5 │ Window6 │ Window7 │ Window8 │
│ 7×7 │ 7×7 │ 7×7 │ 7×7 │
├─────────┼─────────┼─────────┼─────────┤
│ : │ : │ : │ : │
└─────────┴─────────┴─────────┴─────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Layer L+1(Shifted Window分割)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Windowを右と下に floor(M/2) = 3 パッチずらす:
┌──┬────────┬────────┬────────┬──┐
│ │ │ │ │ │
├──┼────────┼────────┼────────┼──┤
│ │ Win1′ │ Win2′ │ Win3′ │ │
│ │ 7×7 │ 7×7 │ 7×7 │ │
├──┼────────┼────────┼────────┼──┤
│ │ Win4′ │ Win5′ │ Win6′ │ │
│ │ 7×7 │ 7×7 │ 7×7 │ │
├──┼────────┼────────┼────────┼──┤
│ │ : │ : │ : │ │
└──┴────────┴────────┴────────┴──┘
→ 境界の位置が変わる!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
効果: Window間の情報交換
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
猫がWindow境界をまたぐ場合:
Layer L:
┌─────┬─────┐
│🐱左 │ │ 猫の左半分: Window 1
├─────┼─────┤
│ │🐱右 │ 猫の右半分: Window 4
└─────┴─────┘
→ 左右が分離、情報交換なし
Layer L+1(シフト後):
┌───┬─────┬───┐
│ │🐱全体│ │ 猫全体: Window 1′
├───┼─────┼───┤
│ │ │ │
└───┴─────┴───┘
→ 猫全体が同じWindowに!
→ 左右の情報を統合できる
2層を交互に繰り返すことで:
すべての領域でWindow間の情報交換が実現
【シフトの実装: Cyclic Shift】
シフト後、端にできる小さなWindowの扱い:
問題:
シフトすると端に半端なWindowができる
サイズが異なるとバッチ処理できない
解決策: Cyclic Shift(循環シフト)
特徴マップを「輪っか」のように扱う
┌──────────────────┐ ┌──────────────────┐
│ A │ B │ C │ │ B │ C │ A │
│────┼─────┼─────│ → │────┼─────┼─────│
│ D │ E │ F │ │ E │ F │ D │
└──────────────────┘ └──────────────────┘
Aの部分が右端に移動(循環)
→ すべてのWindowが同じサイズ
→ バッチ処理可能!
マスクによる制御:
循環でつながった不正なAttentionを
マスクで無効化
1-6. Patch Merging
Patch Merging は、特徴マップのダウンサンプリングを行う層です。CNNのPooling層に相当します。
【Patch Mergingの仕組み】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
目的
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 解像度を下げる(1/2倍)
2. チャンネル数を増やす(2倍)
3. 階層的な特徴を構築
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
処理手順
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: 56×56×96 の特徴マップ
ステップ1: 2×2パッチをグループ化
━━━━━━━━━━━━━━━━━━━━━━━━━━
元の特徴マップ(4×4の例で説明):
┌───┬───┬───┬───┐
│ 1 │ 2 │ 5 │ 6 │ ← 各セルは96次元ベクトル
├───┼───┼───┼───┤
│ 3 │ 4 │ 7 │ 8 │
├───┼───┼───┼───┤
│ 9 │10 │13 │14 │
├───┼───┼───┼───┤
│11 │12 │15 │16 │
└───┴───┴───┴───┘
2×2ずつグループ化:
┌───────┬───────┐
│[1,2, │[5,6, │
│ 3,4] │ 7,8] │
├───────┼───────┤
│[9,10,│[13,14│
│11,12]│15,16]│
└───────┴───────┘
ステップ2: 各グループを結合(Concatenate)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
グループ[1,2,3,4]の結合:
パッチ1: 96次元
パッチ2: 96次元
パッチ3: 96次元
パッチ4: 96次元
結合: 96×4 = 384次元
ステップ3: 線形変換で次元削減
━━━━━━━━━━━━━━━━━━━━━━━━━━
384次元 → 192次元(Linear層)
これにより:
・情報量を保持しながら
・適切な次元数に調整
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
結果
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力: 56×56×96
出力: 28×28×192
・解像度: 1/2に
・チャンネル数: 2倍に
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各Stageでの特徴マップサイズ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Stage 1: 56×56×96 (1/4解像度)
↓ Patch Merging
Stage 2: 28×28×192 (1/8解像度)
↓ Patch Merging
Stage 3: 14×14×384 (1/16解像度)
↓ Patch Merging
Stage 4: 7×7×768 (1/32解像度)
→ FPN(Feature Pyramid Network)の入力として使用可能!
1-7. Swin Transformerのバリエーション
モデル
埋め込み次元
層数(各Stage)
パラメータ数
ImageNet精度
特徴
Swin-T
96
2, 2, 6, 2
29M
81.3%
軽量
Swin-S
96
2, 2, 18, 2
50M
83.0%
バランス
Swin-B
128
2, 2, 18, 2
88M
83.5%
標準
Swin-L
192
2, 2, 18, 2
197M
86.3%
高精度
🎯 Swin Transformerの利点まとめ
1. 効率性
・Window-based Attentionで計算量O(N)に削減
・高解像度画像にも対応可能
2. 階層性
・Patch Mergingで複数スケールの特徴マップ
・CNNの階層構造と互換性あり
3. 汎用性
・画像分類、物体検出、セグメンテーションすべてに対応
・既存のCNNベースフレームワーク(Detectron2など)と連携可能
4. 性能
・ViTより効率的で同等以上の精度
・ResNetを置き換えるバックボーンとして最適
🎯 2. DETR(DEtection TRansformer)
DETR (DEtection TRansformer)は、Transformerを使ったEnd-to-End の物体検出モデルです。Facebook AI(現Meta)が2020年に発表し、物体検出のパラダイムを大きく変えました。
2-1. 従来の物体検出の問題点
【従来の物体検出パイプライン】
例: Faster R-CNN
入力画像
↓
━━━━━━━━━━━━━━━━━━━━
1. CNNバックボーン
━━━━━━━━━━━━━━━━━━━━
ResNet-50などで特徴抽出
↓
━━━━━━━━━━━━━━━━━━━━
2. RPN(Region Proposal Network)
━━━━━━━━━━━━━━━━━━━━
Anchor Boxを使って候補領域を生成
※ Anchor Box:
事前に定義されたサイズ・アスペクト比の矩形
例: [(32×32), (64×64), (128×128)] × [1:1, 1:2, 2:1]
問題:
・データセットに合わせて手動で設計が必要
・不適切なAnchorでは精度が低下
↓
━━━━━━━━━━━━━━━━━━━━
3. RoI Pooling
━━━━━━━━━━━━━━━━━━━━
候補領域を固定サイズに切り出し
↓
━━━━━━━━━━━━━━━━━━━━
4. 分類 + Box回帰
━━━━━━━━━━━━━━━━━━━━
各候補領域のクラスとBoxを予測
→ 同じ物体に複数の検出が発生
↓
━━━━━━━━━━━━━━━━━━━━
5. NMS(Non-Maximum Suppression)
━━━━━━━━━━━━━━━━━━━━
重複した検出を削除
処理:
1. 信頼度でソート
2. 最高信頼度の検出を採用
3. IoU > 閾値の検出を削除
4. 繰り返し
問題:
・IoU閾値の調整が必要
・微分不可能(End-to-End学習の妨げ)
・ヒューリスティックな後処理
↓
最終的な検出結果
【従来手法の問題点まとめ】
1. 複雑なパイプライン
・多段階の処理
・各段階で別々の設計・チューニング
2. 手作業の設計
・Anchor Boxの設計
・NMSの閾値調整
3. End-to-Endでない
・NMSが微分不可能
・全体最適化ができない
2-2. DETRのアプローチ
💡 DETRの革新的なアイデア
物体検出を「集合予測問題」として定式化
従来: 「画像のどこに何がいるか?を繰り返し予測」
DETR: 「画像に含まれる物体の集合を一度に予測」
利点:
・NMS不要(一意な予測)
・Anchor不要(Object Queriesから直接予測)
・シンプルなEnd-to-Endパイプライン
2-3. DETRの全体構造
【DETRのアーキテクチャ】
入力画像(例: 800×1333×3)
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. CNNバックボーン(ResNet-50)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
畳み込みによる特徴抽出
800×1333 → 25×42の特徴マップ
チャンネル数: 2048
出力: 25×42×2048
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2. 1×1畳み込み(次元削減)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
チャンネル数を削減
2048 → 256(hidden dimension)
出力: 25×42×256
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. Flatten + Positional Encoding
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2D特徴マップを1Dシーケンスに変換
25×42 = 1050個のトークン
各トークンに位置情報を追加(2D positional encoding)
出力: 1050×256
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. Transformer Encoder(6層)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像特徴のSelf-Attention
各トークンが画像全体の文脈を理解
出力: 1050×256(Memory)
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
5. Transformer Decoder(6層)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
入力:
・Object Queries: 100×256(学習可能なパラメータ)
・Memory: 1050×256(Encoderの出力)
処理:
・Self-Attention: Object Queries間
・Cross-Attention: Queries → Memory
出力: 100×256
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
6. Prediction Heads(並列)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各Object Query(100個)に対して:
分類ヘッド(FFN):
256 → 91+1クラス
(COCOの91クラス + “no object”クラス)
Box回帰ヘッド(FFN):
256 → 4(cx, cy, w, h)
(中心座標と幅高さ、0-1に正規化)
↓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7. 出力
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
100個の予測:
Query 1: (クラス1, [0.25, 0.30, 0.10, 0.15])
Query 2: (クラス2, [0.60, 0.70, 0.20, 0.25])
Query 3: (no_object, _)
Query 4: (no_object, _)
…
Query 100: (no_object, _)
“no_object”以外を最終結果として出力
2-4. Object Queries
Object Queries は、DETRの最も重要な概念の一つです。「画像に何がいるか?」を質問するベクトルと考えることができます。
【Object Queriesとは】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
基本概念
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Object Queries:
・100個の学習可能なベクトル(パラメータ)
・各Queryが1つの物体を担当
・形状: (100, 256)
イメージ:
「この画像に物体はいますか?」と
100人の専門家が同時に質問
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
訓練による役割分担
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
訓練前(ランダム初期化):
Query 1: [0.23, -0.45, 0.12, …, 0.89]
Query 2: [0.67, 0.34, -0.21, …, -0.12]
Query 3: [-0.56, 0.11, 0.78, …, 0.33]
…
→ 特に意味はない
訓練後:
各Queryが特定の役割を学習
例(COCOデータセットで訓練後):
Query 1: 「画像中央の大きな物体」を担当
Query 2: 「左上の小さな物体」を担当
Query 3: 「右下の中くらいの物体」を担当
…
→ データから自動的に役割分担を学習!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Decoderでの処理
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Decoder Layer 1:
Self-Attention:
Object Queries間でAttention
→ 「Query 1が大きな物体を見ているなら、
私(Query 2)は別の物体を見よう」
Cross-Attention:
Object Queries ← Encoder出力(画像特徴)
→ 各Queryが画像特徴を「見て」
担当する物体を探す
例:
Query 1: 「中央に猫がいる!」
Query 2: 「左上に車がある!」
Query 3: 「物体は見つからない…」
Decoder Layer 2-6:
さらに精緻化
Query 1: 「猫の位置をもっと正確に…」
Query 2: 「車の大きさを調整…」
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
最終出力
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各Queryから1つの予測:
Query 1: (猫, 0.95, [0.45, 0.50, 0.30, 0.40])
Query 2: (車, 0.88, [0.15, 0.20, 0.20, 0.25])
Query 3: (no_obj, 0.92, _)
Query 4: (no_obj, 0.85, _)
…
→ 100個の独立した予測
→ 重複がほとんどない(学習で抑制)
→ NMS不要!
2-5. Bipartite Matching(二部マッチング)
DETRの学習では、Bipartite Matching (二部マッチング)という手法を使って、予測と正解を一意に対応付けます。これがNMSを不要にする鍵です。
【Bipartite Matchingとは】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
問題設定
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
正解物体: N個(例: 3個)
予測: M個(例: 100個、M >> N)
課題: どの予測がどの正解に対応するかを決める
従来手法の問題:
1つの正解に複数の予測が対応してしまう
→ NMSで重複を削除
DETRの解決策:
Bipartite Matching で一意に対応付け
→ 各正解に対して最大1つの予測のみ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
具体例
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
画像に3個の物体(猫、車、犬)がある場合:
正解:
物体1: 猫, Box [100, 50, 200, 150]
物体2: 車, Box [300, 200, 450, 350]
物体3: 犬, Box [500, 100, 600, 200]
予測(100個のObject Queries):
Query 1: 猫, 0.75, [102, 51, 202, 151] ← 猫に近い
Query 2: 犬, 0.82, [502, 102, 602, 202] ← 犬に近い
Query 3: 車, 0.88, [305, 202, 455, 352] ← 車に近い
Query 4: no_object, 0.91, _
Query 5: 猫, 0.45, [150, 80, 250, 180] ← 猫っぽいが位置がずれてる
…
Query 100: no_object, 0.85, _
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ1: コスト行列の計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各(正解、予測)ペアのコストを計算:
コスト = λ_cls × L_cls + λ_box × L_box + λ_giou × L_giou
L_cls: 分類損失(クロスエントロピー)
L_box: Box損失(L1距離)
L_giou: GIoU損失(位置の一致度)
λ_cls = 1, λ_box = 5, λ_giou = 2(論文の設定)
コスト行列(一部):
Query1 Query2 Query3 Query4 Query5 … Query100
正解1(猫) 0.25 0.85 0.90 0.95 0.55 0.92
正解2(車) 0.88 0.82 0.30 0.91 0.87 0.89
正解3(犬) 0.91 0.22 0.87 0.93 0.89 0.91
解説:
・正解1(猫)とQuery1のコストが0.25(低い = 似ている)
・正解2(車)とQuery3のコストが0.30(低い = 似ている)
・正解3(犬)とQuery2のコストが0.22(低い = 似ている)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ2: Hungarian Algorithm(ハンガリアン法)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
総コストを最小化する一意な割り当てを見つける
制約:
・各正解は最大1つの予測にマッチ
・各予測は最大1つの正解にマッチ
結果:
正解1(猫) → Query1(コスト0.25)
正解2(車) → Query3(コスト0.30)
正解3(犬) → Query2(コスト0.22)
総コスト: 0.25 + 0.30 + 0.22 = 0.77(最小)
重要:
Query5も猫を予測しているが、
Query1の方がコストが低いのでQuery1がマッチ
→ Query5は「no_object」として学習される
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ステップ3: 損失の計算
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
マッチしたQuery:
L1 = L_cls(Query1, 猫) + L_box(Query1, 猫Box)
L2 = L_cls(Query3, 車) + L_box(Query3, 車Box)
L3 = L_cls(Query2, 犬) + L_box(Query2, 犬Box)
マッチしなかったQuery:
L4 = L_cls(Query4, no_object)
L5 = L_cls(Query5, no_object) ← 猫を予測したが不採用
…
L100 = L_cls(Query100, no_object)
総損失:
L_total = L1 + L2 + L3 + L4 + … + L100
【なぜNMSが不要になるのか】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由1: 一意な対応付け
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
訓練時:
Bipartite Matchingにより
各正解物体に1つのQueryのみがマッチ
→ 同じ物体を検出するQueryは1つだけ
→ 重複予測にペナルティ(no_objectとして学習)
学習結果:
各Queryが異なる物体を担当するように学習
Query 1: 「私は大きな物体を担当」
Query 2: 「私は小さな物体を担当」
Query 3: 「私は左側の物体を担当」
…
→ 自然に役割分担
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由2: Set Predictionとしての定式化
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
従来手法:
予測 = リスト(順序あり、重複あり)
[検出1, 検出2, 検出3, …]
→ 同じ物体が複数回出現可能
DETR:
予測 = 集合(順序なし、重複なし)
{検出1, 検出2, 検出3, …}
→ 各要素は一意
Bipartite Matchingにより:
予測集合と正解集合を一意に対応付け
→ 重複が本質的に存在しない
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
理由3: 損失関数による学習
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
もし複数のQueryが同じ物体を予測すると:
例: Query1とQuery5が両方とも猫を予測
Bipartite Matching:
コストが低い方(Query1)のみがマッチ
学習:
Query1: 「猫」として正しく学習
Query5: 「no_object」として学習(ペナルティ)
結果:
Query5は猫を予測すると損失が増加
→ 学習により、Query5は猫を避けるようになる
→ 重複予測が減少
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
推論時の動作
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
推論:
100個のQueryから予測を取得
Query1: 猫, 0.95
Query2: 犬, 0.88
Query3: 車, 0.92
Query4: no_object, 0.96
…
Query100: no_object, 0.89
フィルタリング:
信頼度閾値(例: 0.7)でフィルタ
no_object以外を採用
最終結果:
猫, 犬, 車の3つの検出
→ 重複がない(学習で抑制済み)
→ NMSは不要!
2-6. DETRの特徴と課題
項目
利点
課題
アーキテクチャ
シンプル、End-to-End
学習が遅い(500 epochs必要)
NMS
不要(一意な予測)
–
Anchor
不要(Object Queries)
–
大きい物体
高精度
–
小さい物体
–
精度がやや低い
推論速度
中程度(約28FPS)
YOLOより遅い
【DETRの改良版】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Deformable DETR(2020年)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
改良点:
・Deformable Attentionの導入
→ 全ピクセルではなく、
学習された少数の点のみAttention
・Multi-Scale特徴の利用
効果:
・学習が10倍高速(50 epochs)
・小さい物体の精度向上
・メモリ使用量削減
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DINO(2022年)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
改良点:
・Contrastive DeNoising
・Mixed Query Selection
・Look Forward Twice
効果:
・COCO mAP 63.3%(最高精度)
・収束が安定
→ 現在の最先端DETR系モデル
💻 3. 実装:SwinとDETRの利用
3-1. Swin Transformerで画像分類
※ コードが横に長い場合は横スクロールできます
# ===================================================
# Swin Transformerで画像分類
# ===================================================
# 必要なライブラリをインポート
from transformers import AutoImageProcessor, SwinForImageClassification
import torch
from PIL import Image
import requests
from io import BytesIO
# ===================================================
# 1. モデルとプロセッサのロード
# ===================================================
# モデル名を指定
# microsoft/swin-tiny-patch4-window7-224:
# – swin-tiny: Swin-Tサイズ(29Mパラメータ)
# – patch4: パッチサイズ4×4
# – window7: Windowサイズ7×7
# – 224: 入力画像サイズ224×224
model_name = “microsoft/swin-tiny-patch4-window7-224″
# AutoImageProcessor: 画像の前処理を自動的に行う
# – リサイズ
# – 正規化
# – テンソル変換
processor = AutoImageProcessor.from_pretrained(model_name)
# SwinForImageClassification: 分類用Swinモデル
# – ImageNetの1000クラス分類用に事前学習済み
model = SwinForImageClassification.from_pretrained(model_name)
# 評価モードに設定
# – Dropoutを無効化
# – BatchNormを固定
model.eval()
# モデル情報を表示
print(f”モデル: {model_name}”)
print(f”パラメータ数: {sum(p.numel() for p in model.parameters()):,}”)
実行結果:
モデル: microsoft/swin-tiny-patch4-window7-224
パラメータ数: 28,288,354
# ===================================================
# 2. 画像の読み込みと前処理
# ===================================================
# サンプル画像をダウンロード(テスト用)
url = “https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg”
response = requests.get(url)
image = Image.open(BytesIO(response.content)).convert(‘RGB’)
# 前処理を実行
# processor()が自動的に以下を行う:
# – リサイズ(224×224)
# – 正規化(ImageNetの平均・標準偏差)
# – テンソル変換
inputs = processor(images=image, return_tensors=”pt”)
print(f”入力テンソルのshape: {inputs[‘pixel_values’].shape}”)
実行結果:
入力テンソルのshape: torch.Size([1, 3, 224, 224])
# ===================================================
# 3. 推論の実行
# ===================================================
# 勾配計算を無効化(推論時は不要)
with torch.no_grad():
# モデルに入力を渡して出力を取得
outputs = model(**inputs)
# outputs.logits: 分類のロジット(softmax前の値)
# shape: (1, 1000)
logits = outputs.logits
# softmaxで確率に変換
probs = torch.softmax(logits, dim=-1)
# Top-5の確率とインデックスを取得
top5_prob, top5_idx = torch.topk(probs, 5, dim=-1)
# 結果を表示
print(“\nTop 5 Predictions (Swin Transformer):”)
print(“-” * 50)
for i in range(5):
class_id = top5_idx[0][i].item()
class_name = model.config.id2label[class_id]
prob = top5_prob[0][i].item()
print(f”{i+1}. {class_name}: {prob*100:.2f}%”)
実行結果:
Top 5 Predictions (Swin Transformer):
————————————————–
1. tabby, tabby cat: 48.23%
2. tiger cat: 25.67%
3. Egyptian cat: 15.34%
4. Persian cat: 5.82%
5. Siamese cat, Siamese: 2.43%
3-2. Swinの階層的特徴の抽出
# ===================================================
# Swinの階層的特徴の抽出
# ===================================================
from transformers import SwinModel
# SwinModel: 分類ヘッドなしのベースモデル
# 特徴抽出に使用
feature_extractor = SwinModel.from_pretrained(model_name)
feature_extractor.eval()
# 特徴抽出(各Stageの出力を取得)
# output_hidden_states=True: 各層の出力を保存
with torch.no_grad():
outputs = feature_extractor(**inputs, output_hidden_states=True)
# hidden_states: 各Stageの特徴マップ
# タプル形式で取得
hidden_states = outputs.hidden_states
print(“各Stageの特徴マップサイズ:”)
print(“-” * 50)
for i, hidden_state in enumerate(hidden_states):
# hidden_stateのshape: (batch, num_patches, channels)
print(f”Stage {i}: {hidden_state.shape}”)
# パッチ数から解像度を計算
num_patches = hidden_state.shape[1]
resolution = int(num_patches ** 0.5)
channels = hidden_state.shape[2]
print(f” → 解像度: {resolution}×{resolution}, チャンネル: {channels}”)
実行結果:
各Stageの特徴マップサイズ:
————————————————–
Stage 0: torch.Size([1, 3136, 96])
→ 解像度: 56×56, チャンネル: 96
Stage 1: torch.Size([1, 784, 192])
→ 解像度: 28×28, チャンネル: 192
Stage 2: torch.Size([1, 196, 384])
→ 解像度: 14×14, チャンネル: 384
Stage 3: torch.Size([1, 49, 768])
→ 解像度: 7×7, チャンネル: 768
【Swinの階層的特徴の活用】
物体検出やセグメンテーションでは、
各Stageの特徴をFPN(Feature Pyramid Network)に入力:
features = {
‘p2’: stage1_features, # 28×28×192(小さい物体用)
‘p3’: stage2_features, # 14×14×384(中くらいの物体用)
‘p4’: stage3_features, # 7×7×768 (大きい物体用)
}
# FPNで処理
fpn_features = fpn(features)
# 物体検出ヘッド
detections = detection_head(fpn_features)
→ Detectron2などのフレームワークで使用可能
3-3. DETRで物体検出
# ===================================================
# DETRで物体検出
# ===================================================
from transformers import DetrImageProcessor, DetrForObjectDetection
import torch
from PIL import Image, ImageDraw
import matplotlib.pyplot as plt
# ===================================================
# 1. モデルとプロセッサのロード
# ===================================================
# DetrImageProcessor: DETR用の画像前処理
# – リサイズ(最大800px)
# – 正規化
processor = DetrImageProcessor.from_pretrained(“facebook/detr-resnet-50”)
# DetrForObjectDetection: DETR物体検出モデル
# – ResNet-50バックボーン
# – COCOデータセットで事前学習済み(91クラス)
model = DetrForObjectDetection.from_pretrained(“facebook/detr-resnet-50″)
model.eval()
print(f”Object Queries数: {model.config.num_queries}”)
print(f”クラス数: {model.config.num_labels}”)
実行結果:
Object Queries数: 100
クラス数: 91
# ===================================================
# 2. 画像の読み込みと前処理
# ===================================================
# サンプル画像をダウンロード(人や車が写っている画像)
url = “http://images.cocodataset.org/val2017/000000039769.jpg”
response = requests.get(url)
image = Image.open(BytesIO(response.content)).convert(‘RGB’)
# 前処理
inputs = processor(images=image, return_tensors=”pt”)
print(f”入力shape: {inputs[‘pixel_values’].shape}”)
print(f”元画像サイズ: {image.size}”)
実行結果:
入力shape: torch.Size([1, 3, 800, 1066])
元画像サイズ: (640, 480)
# ===================================================
# 3. 推論の実行
# ===================================================
with torch.no_grad():
outputs = model(**inputs)
# 出力の構造
# outputs.logits: 各Queryのクラス予測
# shape: (1, 100, 92) → 91クラス + “no_object”
# outputs.pred_boxes: 各QueryのBox予測
# shape: (1, 100, 4) → (cx, cy, w, h)、0-1に正規化
print(f”Logits shape: {outputs.logits.shape}”)
print(f”Boxes shape: {outputs.pred_boxes.shape}”)
実行結果:
Logits shape: torch.Size([1, 100, 92])
Boxes shape: torch.Size([1, 100, 4])
# ===================================================
# 4. 後処理(信頼度でフィルタリング)
# ===================================================
# クラス確率を計算
# [:, :-1]: 最後の”no_object”クラスを除外
probs = outputs.logits.softmax(-1)[0, :, :-1]
# 信頼度閾値
threshold = 0.7
# 各Queryの最大確率を取得
max_probs = probs.max(-1).values
# 閾値以上の検出を保持
keep = max_probs > threshold
# フィルタリング
probs_keep = probs[keep]
boxes_keep = outputs.pred_boxes[0, keep]
# 予測クラスと信頼度
pred_classes = probs_keep.argmax(-1)
pred_scores = probs_keep.max(-1).values
print(f”\n検出された物体数: {len(pred_classes)}”)
実行結果:
検出された物体数: 2
# ===================================================
# 5. 結果の表示
# ===================================================
# COCOクラス名(一部)
COCO_CLASSES = [
‘N/A’, ‘person’, ‘bicycle’, ‘car’, ‘motorcycle’, ‘airplane’, ‘bus’,
‘train’, ‘truck’, ‘boat’, ‘traffic light’, ‘fire hydrant’, ‘N/A’,
‘stop sign’, ‘parking meter’, ‘bench’, ‘bird’, ‘cat’, ‘dog’, ‘horse’,
‘sheep’, ‘cow’, ‘elephant’, ‘bear’, ‘zebra’, ‘giraffe’, ‘N/A’, ‘backpack’,
‘umbrella’, ‘N/A’, ‘N/A’, ‘handbag’, ‘tie’, ‘suitcase’, ‘frisbee’, ‘skis’,
‘snowboard’, ‘sports ball’, ‘kite’, ‘baseball bat’, ‘baseball glove’,
‘skateboard’, ‘surfboard’, ‘tennis racket’, ‘bottle’, ‘N/A’, ‘wine glass’,
‘cup’, ‘fork’, ‘knife’, ‘spoon’, ‘bowl’, ‘banana’, ‘apple’, ‘sandwich’,
‘orange’, ‘broccoli’, ‘carrot’, ‘hot dog’, ‘pizza’, ‘donut’, ‘cake’,
‘chair’, ‘couch’, ‘potted plant’, ‘bed’, ‘N/A’, ‘dining table’, ‘N/A’,
‘N/A’, ‘toilet’, ‘N/A’, ‘tv’, ‘laptop’, ‘mouse’, ‘remote’, ‘keyboard’,
‘cell phone’, ‘microwave’, ‘oven’, ‘toaster’, ‘sink’, ‘refrigerator’,
‘N/A’, ‘book’, ‘clock’, ‘vase’, ‘scissors’, ‘teddy bear’, ‘hair drier’,
‘toothbrush’
]
print(“\n検出結果:”)
print(“-” * 50)
for i, (class_id, score, box) in enumerate(zip(pred_classes, pred_scores, boxes_keep)):
class_name = COCO_CLASSES[class_id.item()]
print(f”{i+1}. {class_name}”)
print(f” 信頼度: {score.item():.3f}”)
print(f” Box (cx, cy, w, h): {[f'{x:.3f}’ for x in box.tolist()]}”)
実行結果:
検出結果:
————————————————–
1. cat
信頼度: 0.998
Box (cx, cy, w, h): [‘0.502’, ‘0.480’, ‘0.680’, ‘0.850’]
2. remote
信頼度: 0.856
Box (cx, cy, w, h): [‘0.120’, ‘0.520’, ‘0.080’, ‘0.120’]
# ===================================================
# 6. 可視化
# ===================================================
def visualize_detr_detections(image, boxes, classes, scores, class_names):
“””
DETRの検出結果を可視化
Args:
image: PILイメージ
boxes: Box座標(cx, cy, w, h)、0-1正規化
classes: クラスID
scores: 信頼度スコア
class_names: クラス名のリスト
“””
# 画像をコピー
img_draw = image.copy()
draw = ImageDraw.Draw(img_draw)
width, height = img_draw.size
# 色の定義
colors = [‘red’, ‘blue’, ‘green’, ‘yellow’, ‘purple’, ‘orange’]
for i, (box, class_id, score) in enumerate(zip(boxes, classes, scores)):
# Box座標を変換
# (cx, cy, w, h) → (x1, y1, x2, y2)
# 0-1正規化 → ピクセル座標
cx, cy, w, h = box.tolist()
x1 = (cx – w/2) * width
y1 = (cy – h/2) * height
x2 = (cx + w/2) * width
y2 = (cy + h/2) * height
# 色を選択
color = colors[i % len(colors)]
# 矩形を描画
draw.rectangle([x1, y1, x2, y2], outline=color, width=3)
# ラベルを描画
class_name = class_names[class_id.item()]
label = f”{class_name}: {score.item():.2f}”
draw.text((x1, y1 – 15), label, fill=color)
return img_draw
# 可視化を実行
result_image = visualize_detr_detections(
image,
boxes_keep,
pred_classes,
pred_scores,
COCO_CLASSES
)
# 表示
plt.figure(figsize=(12, 8))
plt.imshow(result_image)
plt.axis(‘off’)
plt.title(“DETR Object Detection”, fontsize=16)
plt.tight_layout()
plt.savefig(‘detr_detection.png’, dpi=150, bbox_inches=’tight’)
plt.show()
print(“\ndetr_detection.png を保存しました”)
📝 練習問題
問題1:Window-based Attentionの計算量(基礎)
56×56の特徴マップに対して、Windowサイズ7×7のWindow-based Attentionを適用した場合の計算量を求めてください。また、グローバルAttention(ViT)と比較してください。
解答を見る
解答:
与えられた情報:
特徴マップサイズ: 56×56
Windowサイズ: 7×7
1. 1つのWindow内の計算量
Window内のトークン数:
N_window = 7 × 7 = 49
Self-Attentionの計算量:
O(N²) = 49² = 2,401
2. Window数の計算
特徴マップ全体のパッチ数:
56 × 56 = 3,136
Window数:
縦方向: 56 ÷ 7 = 8個
横方向: 56 ÷ 7 = 8個
合計: 8 × 8 = 64個
3. 全体の計算量
全Window合計:
2,401 × 64 = 153,664
4. グローバルAttentionとの比較
グローバルAttention(ViT):
3,136² = 9,830,496
削減率:
153,664 / 9,830,496 = 0.0156 ≈ 1.56%
→ 約64倍の効率化!
結論:
Window-based Attentionにより、計算量が約1/64に削減されます。これは画像サイズに対して線形 O(N) のオーダーになります。
問題2:Patch Mergingの出力サイズ(中級)
Swin TransformerのPatch Mergingについて、入力が56×56×96の特徴マップの場合、出力のサイズと処理の詳細を説明してください。
解答を見る
解答:
入力: 56×56×96
ステップ1: 2×2パッチのグループ化
56×56の特徴マップを2×2ずつグループ化
グループ数:
縦方向: 56 ÷ 2 = 28
横方向: 56 ÷ 2 = 28
合計: 28 × 28 = 784グループ
ステップ2: 各グループの結合
各グループには4つのパッチ:
パッチ1: 96次元
パッチ2: 96次元
パッチ3: 96次元
パッチ4: 96次元
結合(Concatenate):
96 × 4 = 384次元
ステップ3: 線形変換で次元削減
Linear層:
入力: 384次元
出力: 192次元
重み行列: W ∈ R^(384×192)
出力: 28×28×192
変化:
・解像度: 56×56 → 28×28(1/2倍)
・チャンネル: 96 → 192(2倍)
効果:
・情報量を保持しながらダウンサンプリング
・CNNのPooling + チャンネル増加に相当
・階層的な特徴表現の構築
問題3:Bipartite Matchingの仕組み(上級)
DETRにおけるBipartite Matching(二部マッチング)の仕組みと、なぜこれによりNMSが不要になるのか説明してください。
解答を見る
解答:
1. Bipartite Matchingの仕組み
問題設定:
正解物体: N個(例: 3個)
予測: M個(例: 100個のObject Queries)
→ どの予測がどの正解に対応するかを決める
ステップ1: コスト行列の計算
各(正解、予測)ペアのコストを計算
コスト = λ_cls × L_cls + λ_box × L_box + λ_giou × L_giou
L_cls: 分類損失
L_box: Box損失(L1距離)
L_giou: GIoU損失
ステップ2: Hungarian Algorithm
総コストを最小化する一意な割り当てを見つける
制約:
・各正解は最大1つの予測にマッチ
・各予測は最大1つの正解にマッチ
ステップ3: 損失の計算
マッチしたQuery: 正解との損失
マッチしなかったQuery: “no_object”との損失
2. なぜNMSが不要になるのか
理由1: 一意な対応付け
各正解物体に1つのQueryのみがマッチ
→ 同じ物体を検出するQueryは1つだけ
→ 重複予測にペナルティ(no_objectとして学習)
理由2: Set Predictionとしての定式化
予測 = 集合(Set)として扱う
→ 各要素は一意
→ 重複が本質的に存在しない
理由3: 損失関数による学習
複数のQueryが同じ物体を予測すると:
・コストが低い方のみがマッチ
・他は”no_object”として学習
→ 学習により重複予測を避けるようになる
結果:
推論時に重複がほとんど発生しない
→ NMSは不要!
問題4:SwinとViTの比較(上級)
Swin TransformerとViTの違いを、計算量、階層性、適用タスクの観点から比較してください。
解答を見る
解答:
【計算量の比較】
ViT:
・グローバルAttention
・計算量: O(N²)(Nはパッチ数)
・例: 56×56 = 3,136パッチ → 9,830,496計算
Swin:
・Window-based Attention
・計算量: O(N × M²)(MはWindow内パッチ数、固定)
・例: 56×56、Window7×7 → 153,664計算
→ Swinは約64倍効率的
→ 高解像度画像に対応可能
【階層性の比較】
ViT:
・単一スケールの特徴マップ
・最終出力のみ(14×14など)
・位置埋め込みが固定サイズ
Swin:
・階層的な特徴マップ
・Stage 1: 56×56
・Stage 2: 28×28
・Stage 3: 14×14
・Stage 4: 7×7
→ Swinは複数スケールの特徴を提供
→ FPNと連携可能
【適用タスクの比較】
ViT:
・主に画像分類
・物体検出、セグメンテーションには
追加の工夫が必要
Swin:
・画像分類
・物体検出(Faster R-CNN、DETRのバックボーン)
・セマンティックセグメンテーション
・インスタンスセグメンテーション
→ Swinは汎用的なバックボーン
【使い分けの指針】
ViTを選ぶ場合:
・画像分類のみのタスク
・固定サイズの入力画像
・大規模事前学習済みモデルを使いたい
Swinを選ぶ場合:
・物体検出、セグメンテーション
・高解像度画像を扱う
・既存のCNNベースフレームワークと連携
・計算効率が重要
📝 STEP 18 のまとめ
✅ このステップで学んだこと
1. Swin Transformer
・Window-based Attentionで計算量O(N)に削減
・Shifted Windowでwindow間の情報交換
・Patch Mergingで階層的な特徴マップ
2. DETR
・Transformerベースの物体検出
・Object Queriesによる並列予測
・Bipartite Matchingで一意な対応付け
・NMS不要のEnd-to-Endアーキテクチャ
💡 重要ポイント
Swin Transformer:
・ViTの効率性と階層性の問題を解決
・CNNを置き換える汎用バックボーン
DETR:
・物体検出のパラダイムを変えた
・シンプルで理論的に美しい
次のSTEP 19では、「CLIPとマルチモーダルAI」 を学びます。
画像とテキストの統合、ゼロショット分類を習得します!