第5回:分類の再統一 II ~マージンの幾何学~
注意事項
- ArcFaceの「角度マージン」は、特徴ベクトルと重みベクトルが
正規化されていることが前提である。 - SVMとの「統一」は幾何学的直感の共有であり、最適化問題として同一ではない。
- 「球面上のSVM」という解釈は比喩として有用だが、厳密な対応ではない点に注意。
導入:二つの伝統の邂逅
機械学習の歴史において、分類問題へのアプローチには二つの大きな伝統があった。
一方には 幾何学的アプローチ がある。Support Vector Machine (SVM) に代表されるこの立場は、決定境界を明示的に扱い、マージンの最大化を目指す。データ点と境界の「距離」という幾何学的概念が中心にある。
他方には 統計的アプローチ がある。ロジスティック回帰やSoftmax分類器に代表されるこの立場は、クラス所属確率を推定し、尤度最大化を目指す。確率分布という統計的概念が中心にある。
長らく、この二つは異なるパラダイムとして扱われてきた。しかし、第3回・第4回で見た「球面への跳躍」——すなわち、表現を単位球面上に制約し、角度で類似度を測る設計——を採用すると、両者が驚くほど自然に融合して見える。
以降、本回では SVM=幾何(マージン)、Softmax=統計(確率) という対応をまず整理し、最後に ArcFaceを「統計の枠組みに幾何のマージンを埋め込んだもの」として位置づけることで、この統一的視点を探る。
SVMの魂:最大マージン原理
マージンとは何か:最も「ゆとり」のある境界線
SVMの核心的アイデアは 最大マージン原理 である。
二値分類問題を考えよう。データ点
禁止区域としてのマージン
超平面
点
サポートベクターが「限界」を決める
「禁止区域(マージン)」を限界まで広げていくプロセスを想像してほしい。幅を広げ、向きを微調整していくと、やがていくつかのデータ点にぶつかって、それ以上広げられなくなる。 このとき、境界線の「広がり」を食い止めるストッパーとなった点を サポートベクター(Support Vector) と呼ぶ。 数式的には、最適解で
なぜ(多くの場合)安定して決まるのか
(スケールの任意性を除くため)最近傍の点が
境界線の角度を少しでも変えれば、別のデータ点にすぐ接触してしまい、マージン(隙間の幅)は今より狭くなってしまう。 つまり、「隙間を最大にする」という条件が境界線を強く制約するため、境界は多くの場合、少し動かすだけでマージンが縮む状態になり、解が安定して定まる。
NOTE
ハードマージンとソフトマージン: 上記の定式化は ハードマージンSVM であり、データが完全に線形分離可能であることを前提とする。 現実のデータでは分離不可能な場合が多いため、ソフトマージンSVM が使われる。 ソフトマージンでは、スラック変数
マージンを決定する「支柱」:サポートベクター
マージンを最大化する際、すべてのデータ点が等しく重要というわけではない。
- 境界を支える存在: サポートベクター以外の点(境界から遠い点)をデータセットから取り除いても、得られる最適超平面は全く変化しない。文字通り、超平面を両側から「支えている」のがこれらの点である。
- スパース性(疎性): 膨大なデータがあっても、モデルの決定にはごく一部のデータ(サポートベクター)しか関与しない。これはSVMが計算効率やメモリ効率に優れ、かつ過学習を抑制できる理由の一つである。
TIP
数学的背景: ラグランジュの未定乗数法を用いて最適化問題を解くと、重みベクトル
ここで、
なぜマージン最大化が有効か
マージン最大化の直感的な意味は、汎化性能の向上 である。
訓練データから少しずれた新しいデータが来ても、マージンが大きければ正しく分類できる可能性が高い。マージンが小さいと、わずかな摂動で分類が反転してしまう。
NOTE
統計的学習理論との接続: マージン最大化は、VC次元理論やPAC学習の枠組みで理論的に正当化される。大まかに言えば、マージンが大きいほど仮説空間の「複雑さ」が抑えられ、汎化誤差の上界が小さくなる。詳細はVapnik (1995) を参照。
SVMの幾何学的世界観
SVMは本質的に ユークリッド幾何学 の世界に住んでいる。
- 空間:
(ユークリッド空間) - 境界:超平面(線形部分空間)
- 距離:ユークリッド距離
- マージン:境界からの垂直距離
この世界観では、「近い」「遠い」はユークリッド距離で測られる。データ点はノルムの制約なく空間内に散らばっている。
球面上のマージン:角度による再定式化
空間を変えると何が変わるか
第3回で見たように、表現を単位球面
- 空間:
(単位球面) - 境界:大円(測地線)
- 距離:測地線距離
- マージン:角度
球面上では、二点間の「距離」は角度で測られる。したがって、マージンも角度で定義するのが自然である。
球面上のSVM的発想
球面上で「最大マージン」を考えるとどうなるか。
二つのクラスを分離する境界は、球面上では 大円(球面と原点を通る超平面の交線)になる。マージンは、境界(大円)から最も近いデータ点までの 角度 である。
NOTE
大円になる条件: 境界が大円になるのは、決定境界が
| ユークリッド空間(SVM) | 球面(角度ベース) |
|---|---|
| 超平面 | 大円(原点を通る超平面との交線) |
| ユークリッド距離 | 測地線距離(角度) |
| 距離マージン | 角度マージン |
この対応は、SVMの発想を球面上に「翻訳」したものと見なせる。
CAUTION
比喩としての限界: この「球面上のSVM」は幾何学的直感を共有しているが、最適化問題として同一ではない。SVMはヒンジ損失を使い、サポートベクターに基づく双対問題を解く。ArcFace(後述)はSoftmax+クロスエントロピーを使い、勾配降下で最適化する。解くべき問題の構造が異なる。
ArcFace:角度マージンの実現
従来のSoftmax分類器の限界
第4回で見たように、Softmax分類器は入力
両者が正規化されている場合、
しかし、標準的なSoftmax損失は「正解クラスの確率を上げる」ことでロジット差を広げる圧力を持つが、角度マージンを幾何学的にコントロールする仕組みがない。その結果、学習された表現は「同じクラスは近く、異なるクラスは遠く」という構造を持つことが多いが、その分離度は明示的に制御されていない。
ArcFaceのアイデア
ArcFace(Deng et al., 2019)は、この問題に対する elegantな解決策を提示した。
核心的アイデアは、正解クラスの角度に固定のマージン
ここで:
:入力と正解クラスの重みのなす角 :角度マージン(典型的には0.5ラジアン ≈ 28.6度) :スケールパラメータ(温度の逆数的役割)
幾何学的解釈
ArcFaceの幾何学的意味を理解しよう。
通常のSoftmaxでは、入力
これは、決定境界を「正解クラス側に押し込む」効果を持つ。結果として:
- 同じクラスの表現は、より狭い角度範囲に集約される
- 異なるクラス間の角度マージンが確保される
通常のSoftmaxでは、境界は角度が等しくなる点(
ArcFace(
マージンの種類:ArcFace、CosFace、SphereFace
角度マージンを導入する方法は複数提案されている。
| 手法 | マージンの入れ方 | 数式 |
|---|---|---|
| SphereFace (2017) | 角度を乗算 | |
| CosFace (2018) | コサインから減算 | |
| ArcFace (2019) | 角度に加算 |
これらは異なる幾何学的効果を持つ:
- SphereFace:角度を拡大する(
)。 が小さいときマージン効果が弱く、大きいとき強い。 - CosFace:コサイン空間で一定のマージンを課す。実装が簡単だが、角度空間では非線形な効果。
- ArcFace:角度空間で一定のマージンを課す。幾何学的に最も直感的。
NOTE
なぜArcFaceが主流になったか: ArcFaceは角度空間で一定のマージンを課すため、(1) 幾何学的解釈が明快、(2) すべての角度で一様なマージン効果、(3) 顔認識ベンチマークで優れた性能、という利点がある。顔認識・顔照合の分野(特にID分類ベースの学習)では、現在も広く使われる標準的手法の一つである。ただし、最適な手法はタスクやデータセットによって変わりうる。
SVMとArcFaceの対話
共通する精神
SVMとArcFaceは、異なる時代に異なる文脈で生まれたが、共通する精神を持っている。
| 観点 | SVM | ArcFace |
|---|---|---|
| 目標 | クラス間の分離を最大化 | クラス間の分離を最大化 |
| 手段 | マージン最大化 | 角度マージンの導入 |
| 空間 | ユークリッド空間 | 単位球面 |
| マージンの単位 | 距離 | 角度 |
| 最適化 | 凸最適化(双対問題) | 勾配降下(SGD等) |
両者とも「クラス間に十分な余裕(マージン)を確保する」という発想を共有している。違いは、その発想を実現する空間と最適化手法である。
異なる点:最適化問題の構造
重要な違いも認識しておく必要がある。
SVMは、ヒンジ損失
ArcFaceは、修正されたSoftmaxクロスエントロピー損失を最小化する。すべてのデータ点が損失に寄与し、深層ネットワークの一部として勾配降下で最適化される。
この違いは、単なる実装の違いではなく、問題設定の違いを反映している:
- SVMは「与えられた特徴表現に対する最適な境界」を見つける
- ArcFaceは「良い特徴表現と境界を同時に学習する」
つまり、以下の結論になる。
- 統一される:「マージンで分離を確保する」幾何学的直感(距離→角度への翻訳)
- 統一されない:最適化問題そのもの(ヒンジ損失の凸最適化 vs CEの勾配降下)
IMPORTANT
「統一」の意味: 本回で言う「統一」は、SVMとArcFaceが同じ最適化問題であるという主張ではない。両者が「マージンによる分離」という幾何学的直感を共有しており、空間(ユークリッド vs 球面)を変えると自然に対応づけられるという視点の提供である。
ArcFaceによる統計(確率)と幾何(マージン)の統合
ArcFaceは確率モデルか幾何モデルか
ArcFaceの興味深い点は、確率的解釈と幾何学的解釈の両方を持つことである。 ArcFaceは、損失関数としては Softmax+クロスエントロピー(統計的アプローチ) に属する一方で、 ロジット設計として 角度マージン(幾何学的アプローチ) を明示的に導入する――つまり 両方の性格を併せ持つ。 言い換えると、ArcFaceは(ロジットを角度マージンで修正した上で)通常のSoftmax+クロスエントロピーを適用する。
確率的解釈: ArcFaceの損失はクロスエントロピーの形をしており、出力はSoftmaxを通じて確率として解釈できる。温度(スケール
幾何学的解釈: 角度マージン
この二面性は、第4回で見た「Softmaxと情報幾何学」の議論と接続する。Softmaxは確率単体への写像であると同時に、(正規化設計下では)角度情報を確率に変換する装置でもあった。ArcFaceは、この角度→確率の変換に幾何学的制約(マージン)を追加したものと見なせる。
歴史的対立の解消
機械学習の歴史において、「幾何 vs 統計」「判別モデル vs 生成モデル」といった対立軸が議論されてきた。
球面上の角度ベース設計は、この対立を異なる視点から照らし出す:
| 従来の対立 | 球面設計での見え方 |
|---|---|
| 幾何(SVM) vs 統計(Softmax) | 角度マージン + 確率出力として統合 |
| 距離ベース vs 確率ベース | コサイン類似度が確率と自然に対応(vMFの視点) |
| 境界の明示 vs 確率の推定 | 両方を同時に行う設計が可能 |
NOTE
vMF分布との接続: 第3回で見たvon Mises-Fisher分布を思い出そう。vMF分布では、確率密度が
まとめ
SVMとArcFaceは、異なる時代・異なる文脈で生まれたが、「マージンによる分離」という幾何学的直感を共有している。空間をユークリッドから球面に変えると、距離マージンは角度マージンに翻訳され、両者の対応が見えてくる。
| 概念 | 定義 | 本回での役割 |
|---|---|---|
| 最大マージン原理 | 決定境界からの最小距離を最大化 | SVMの核心的アイデア |
| 角度マージン | 球面上での分離度を角度で測る | ArcFaceの設計原理 |
| ArcFace | 角度マージンの標準的実装 | |
| CosFace | コサイン空間でのマージン | |
| SphereFace | 角度乗算によるマージン |
ただし、この「統一」は最適化問題としての同一性ではなく、幾何学的直感の共有である。SVMは凸最適化、ArcFaceは勾配降下という異なる最適化手法を使い、問題設定も異なる。
重要なのは、空間の選び方(ユークリッド vs 球面)が、どのような「マージン」が自然かを決定するということである。球面上では角度がマージンの自然な単位となり、これがArcFaceの設計を導いている。
次回予告
第6回「Transformerという測量士」では、Attention機構を幾何学的に再解釈する。
Attentionは、入力に応じて「どこを見るか」を動的に決定する。これを空間の動的な変形、あるいは測地線の選択として捉えるとどう見えるか。正規化(Softmax)の有無が解釈にどう影響するかも検討する。
実装ノート
NOTE
以下のコードは PyTorch >= 1.9 を前提とする。
ArcFaceの素朴な実装
コード例: 05_arcface_naive.py
import torch
import torch.nn as nn
import torch.nn.functional as F
class ArcFaceNaive(nn.Module):
"""ArcFaceの素朴な実装(教育目的)
注意: この実装は数値的に不安定な場合がある。
実用には後述の安定版を使用すること。
"""
def __init__(self, in_features, num_classes, scale=30.0, margin=0.5):
super().__init__()
self.scale = scale
self.margin = margin
self.weight = nn.Parameter(torch.randn(num_classes, in_features))
nn.init.xavier_uniform_(self.weight)
def forward(self, x, labels):
# 特徴と重みを正規化
x_norm = F.normalize(x, dim=1)
w_norm = F.normalize(self.weight, dim=1)
# コサイン類似度
cosine = F.linear(x_norm, w_norm) # [batch, num_classes]
# 正解クラスの角度にマージンを加算
# acos → +m → cos という経路
theta = torch.acos(torch.clamp(cosine, -1 + 1e-7, 1 - 1e-7))
target_logits = torch.cos(theta[range(len(labels)), labels] + self.margin)
# 正解クラスのロジットを置き換え
logits = cosine.clone()
logits[range(len(labels)), labels] = target_logits
# スケーリング
return logits * self.scaleCAUTION
数値不安定性: torch.acos は入力が clamp は応急処置であり、完全な解決ではない。
数値安定なArcFace
コード例: 05_arcface_stable.py
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
class ArcFaceStable(nn.Module):
"""数値安定なArcFace実装
cos(θ + m) = cos(θ)cos(m) - sin(θ)sin(m) を利用し、
acos を避けることで数値安定性を確保する。
"""
def __init__(self, in_features, num_classes, scale=30.0, margin=0.5):
super().__init__()
self.scale = scale
self.margin = margin
self.weight = nn.Parameter(torch.randn(num_classes, in_features))
nn.init.xavier_uniform_(self.weight)
# マージンの三角関数を事前計算
self.cos_m = math.cos(margin)
self.sin_m = math.sin(margin)
# cos(π - m) を使った閾値(θ + m > π を防ぐ)
self.th = math.cos(math.pi - margin)
self.mm = math.sin(math.pi - margin) * margin
def forward(self, x, labels):
# 特徴と重みを正規化
x_norm = F.normalize(x, dim=1)
w_norm = F.normalize(self.weight, dim=1)
# コサイン類似度
cosine = F.linear(x_norm, w_norm)
# sin(θ) = sqrt(1 - cos²(θ))
sine = torch.sqrt(torch.clamp(1.0 - cosine**2, min=1e-9))
# cos(θ + m) = cos(θ)cos(m) - sin(θ)sin(m)
phi = cosine * self.cos_m - sine * self.sin_m
# θ + m > π の場合の処理(角度が大きすぎる場合)
phi = torch.where(cosine > self.th, phi, cosine - self.mm)
# 正解クラスのみマージンを適用
one_hot = F.one_hot(labels, num_classes=self.weight.size(0)).float()
logits = one_hot * phi + (1.0 - one_hot) * cosine
return logits * self.scale
# 使用例
def train_step(model, arcface, x, labels, optimizer, criterion):
"""ArcFaceを使った学習ステップ"""
optimizer.zero_grad()
# 特徴抽出
features = model(x) # [batch, feature_dim]
# ArcFaceでロジット計算
logits = arcface(features, labels) # [batch, num_classes]
# クロスエントロピー損失
loss = criterion(logits, labels)
loss.backward()
optimizer.step()
return loss.item()CosFaceとSphereFaceの実装
コード例: 05_margin_losses.py
import torch
import torch.nn as nn
import torch.nn.functional as F
class CosFace(nn.Module):
"""CosFace: コサインから直接マージンを減算"""
def __init__(self, in_features, num_classes, scale=30.0, margin=0.35):
super().__init__()
self.scale = scale
self.margin = margin
self.weight = nn.Parameter(torch.randn(num_classes, in_features))
nn.init.xavier_uniform_(self.weight)
def forward(self, x, labels):
x_norm = F.normalize(x, dim=1)
w_norm = F.normalize(self.weight, dim=1)
cosine = F.linear(x_norm, w_norm)
# 正解クラスのコサインからマージンを減算
one_hot = F.one_hot(labels, num_classes=self.weight.size(0)).float()
logits = cosine - one_hot * self.margin
return logits * self.scale
class SphereFace(nn.Module):
"""SphereFace: 角度を乗算(簡略化版)
注意: 実際のSphereFaceはより複雑なアニーリング戦略を使用する。
"""
def __init__(self, in_features, num_classes, scale=30.0, margin=4):
super().__init__()
self.scale = scale
self.margin = margin # 整数の乗数
self.weight = nn.Parameter(torch.randn(num_classes, in_features))
nn.init.xavier_uniform_(self.weight)
def forward(self, x, labels):
x_norm = F.normalize(x, dim=1)
w_norm = F.normalize(self.weight, dim=1)
cosine = F.linear(x_norm, w_norm)
# cos(m * θ) の計算(チェビシェフ多項式を使うのが一般的)
# ここでは簡略化のため m=2 の場合のみ示す
# cos(2θ) = 2cos²(θ) - 1
if self.margin == 2:
cos_m_theta = 2 * cosine**2 - 1
else:
# 一般の場合は acos → *m → cos が必要(数値不安定)
theta = torch.acos(torch.clamp(cosine, -1 + 1e-7, 1 - 1e-7))
cos_m_theta = torch.cos(self.margin * theta)
one_hot = F.one_hot(labels, num_classes=self.weight.size(0)).float()
logits = one_hot * cos_m_theta + (1.0 - one_hot) * cosine
return logits * self.scaleマージンの効果の可視化
コード例: 05_margin_effect_visualization.py
import matplotlib.pyplot as plt
import numpy as np
def visualize_margin_effect():
"""異なるマージン手法の効果を可視化"""
theta = np.linspace(0, np.pi, 100)
cos_theta = np.cos(theta)
# 各手法のマージン適用後のコサイン値
margin_arc = 0.5 # ArcFace: 約28.6度
margin_cos = 0.35 # CosFace
margin_sphere = 2 # SphereFace: m=2
arcface = np.cos(theta + margin_arc)
cosface = cos_theta - margin_cos
sphereface = np.cos(margin_sphere * theta)
plt.figure(figsize=(10, 6))
plt.plot(np.degrees(theta), cos_theta, "k-", label="Original cos(θ)", linewidth=2)
plt.plot(np.degrees(theta), arcface, "b-", label=f"ArcFace: cos(θ + {margin_arc})")
plt.plot(np.degrees(theta), cosface, "r-", label=f"CosFace: cos(θ) - {margin_cos}")
plt.plot(np.degrees(theta), sphereface, "g-", label=f"SphereFace: cos({margin_sphere}θ)")
plt.xlabel("Angle θ (degrees)")
plt.ylabel("Logit value")
plt.title("Comparison of Angular Margin Methods")
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(0, 180)
plt.ylim(-1.5, 1.5)
plt.axhline(y=0, color="gray", linestyle="--", alpha=0.5)
plt.show()
# 実行
visualize_margin_effect()参考文献
ArcFaceと角度マージン手法
- Deng, J., Guo, J., Xue, N., & Zafeiriou, S. (2019). ArcFace: Additive Angular Margin Loss for Deep Face Recognition. CVPR 2019. arXiv: arXiv:1801.07698.
- ArcFaceの原論文。角度マージンの標準的手法として広く引用されている。
- Wang, H., Wang, Y., Zhou, Z., Ji, X., Gong, D., Zhou, J., Li, Z., & Liu, W. (2018). CosFace: Large Margin Cosine Loss for Deep Face Recognition. CVPR 2018. arXiv: arXiv:1801.09414.
- CosFaceの原論文。コサイン空間での減算マージン。
- Liu, W., Wen, Y., Yu, Z., Li, M., Raj, B., & Song, L. (2017). SphereFace: Deep Hypersphere Embedding for Face Recognition. CVPR 2017. arXiv: arXiv:1704.08063.
- SphereFaceの原論文。角度乗算によるマージンの先駆的研究。
SVMと最大マージン理論
- Vapnik, V. (1995). The Nature of Statistical Learning Theory. Springer.
- SVMと統計的学習理論の古典的教科書。マージン最大化の理論的基礎。
- Cortes, C., & Vapnik, V. (1995). Support-Vector Networks. Machine Learning, 20(3), 273–297.
- SVMの原論文。
球面上の学習(関連)
- Wang, F., Xiang, X., Cheng, J., & Yuille, A. L. (2017). NormFace: L2 Hypersphere Embedding for Face Verification. ACM MM 2017. arXiv: arXiv:1704.06369.
- 球面埋め込みの先駆的研究。ArcFace等の基礎となった。