Transformerはもともと自然言語処理(NLP)向けに設計されたアーキテクチャで、単語の並びを系列データとして処理します。では、画像にTransformerを適用するには? そこで登場するのが パッチ分割(Patch Embedding) の考え方です。
パッチとは何か?
ViT(Vision Transformer)では、画像を固定サイズのパッチ(例:16×16ピクセル)に細かく分割し、それぞれを「単語」のように扱います。たとえば224×224の画像なら、16×16パッチで 14×14 = 196個のパッチトークン に変換されます。
パッチサイズの意味
- 小さいパッチ(8×8):より細かい情報が得られるが、トークン数が増えて計算量が跳ね上がる
- 大きいパッチ(32×32):粗い特徴だが、処理は高速でメモリ消費も少ない
目的に応じてバランスを取る必要があります。
たとえ話:地図の縮尺
- パッチサイズ = 地図の縮尺
- 小さい縮尺(=大きいパッチ)だと街全体の様子はわかるが、細かい路地は見えない
- 大きい縮尺(=小さいパッチ)なら細部まで把握できるが、ページ数が増えて重くなる
実務Tips
- 異常検知などの繊細なタスクでは 14×14 や 8×8 パッチが向いています
- 分類など大まかなラベル判定なら 16×16 以上でも十分なことが多い
- PyTorch の
torchvision.models.vit_b_16
などでは、デフォルトで 16×16 パッチが使われています
パッチ数と計算量の関係
パッチ数Nが2倍になると、Self-Attentionの計算量は N² に比例して増えます。
- 例えば:196パッチ → 392パッチ にすると、Attentionは約 4倍 のコスト
- 要注意:解像度を上げる=パッチ数が増える=重くなる!
Self-Attention(自己注意)とは?
イメージ:各パッチ(トークン)が、自分を含む全パッチを見渡して「どれをどれだけ重視するか」を学び、その重みで情報を混ぜ合わせる仕組みです。
技術的説明:各パッチから Query(Q)・Key(K)・Value(V) を作り、全パッチ対全パッチの関連度を計算して重み付き合計を作るしくみです。
- 式:
softmax(Q K^T / sqrt(d_k)) V
(似ているほど大きい重み) - なぜ重い?
QK^T
が N×N 行列になるため計算/メモリは O(N^2)。Nを2倍にすると約4倍に。 - マルチヘッド:複数の視点(ヘッド)で同時に注意を計算し、結合して表現力を上げる。
- たとえ:会議で「全員が全員の発言」をチェックするイメージ。人数(パッチ数)が増えるほど比較の組合せが爆増。
attn = (Q @ K.transpose(-1, -2)) / (dk ** 0.5)
weights = attn.softmax(dim=-1)
out = weights @ V
コード中の -1
, -2
, dk ** 0.5
, dim=-1
の意味
- 前提の形状:
Q, K, V
はふつう(B, H, N, d_k)
※注(V
は最後がd_v
のことも)。B
: バッチ数,H
: ヘッド数,N
: パッチ(トークン)数,d_k
: キー/クエリの次元。※注- B … Batch size(同時に処理するサンプル数)
- H … ヘッド数(Multi-Head Attention の“視点”の数)
- N … トークン数(ViTならパッチ数+[CLS]など)
- d_k … 1ヘッドあたりの Key/Query の次元(しばしば
d_model / H
)
K.transpose(-1, -2)
:負の次元は「後ろから数える」。-1
=最後,-2
=最後から2番目。K
を(B,H,N,d_k)
→(B,H,d_k,N)
に転置し、Q @ K^T
(内積)ができる形にする。/ (dk ** 0.5)
:√d_k
で割るスケーリング。QK^T
の値が次元に比例して大きくなり過ぎ、softmax が極端に尖るのを防いで勾配を安定させる(温度を下げるイメージ)。.softmax(dim=-1)
:attn
は(B,H,N,N)
。最後の軸(-1
)=「各クエリに対する全キーの軸」。ここで正規化すると行ごとに合計1の重み(確率分布)になる。※dim=1
(ヘッド軸)で正規化すると意味が変わるのでNG。out = weights @ V
:形(B,H,N,N)
と(B,H,N,d_v)
の積 →(B,H,N,d_v)
。各クエリが全キーのV
を重み付き合計した結果。