サポートベクターマシン
📂機械学習サポートベクターマシン
モデル
簡単な定義
二値分類binary Classificationが可能なデータを最もよく区別する直線や平面を見つける方法をサポートベクターマシンという。
難しい定義
内積空間 X=Rp とラベリングlabeling Y={−1,+1} に対し、n 個のデータを集めた学習データセットtraining Datasetを D={(xk,yk)}k=1n⊂X×Y とし、
X+:=X−:={xk∈X:yk=+1}{xk∈X:yk=−1}
とする。あるウェイトweight w∈Rp とバイアスbias b∈R を持つ線形関数 f(x)=wTx+b によって作られる超平面を H:wTx+b=0 とするとき、H と最も距離が近い x+∈X+ と x−∈X− をサポートベクターsupport Vectorといい、これらの間の距離 δ をマージンmarginという。これに対して
f(x+)=f(x−)=+1−1
を満たしながらマージンが最大になるような w,b を見つける機械学習技術をサポートベクターマシンsVM, Support Vector Machineという。
説明
簡単に言えば、次の図のようにオレンジ色と空色のデータを二分する線や平面を見つけることである。平面図では赤い矢印で示されているのがサポートベクターに該当する。

図では 2次元なので線を見つけ、3次元なので平面を見つけたが、さらに大きなp次元になると超平面を見つけなければならず、図示するのは難しくなる。しかし、このように空間を二つに分けるという点は変わらない。学習データセットで二値分類が完了すれば、新しいデータを受け取ったときもf に入れて線形分類器linear Classifierとして使えばよい。

当然ながら、同じデータを二値分類しても、左側が右側よりも良い。右側の場合、空色のデータに対するマージンが過度である。具体的にこれを求める方法は、いずれにせよパッケージがすべて自動で処理するため、知らなくてもよい。
学部生レベルであれば、ここまでの簡単な定義を受け入れて図で大まかに理解するだけでも、今後実際に使用する際や用語を理解する上で大きな問題はない。これより少し難しい内容、実践的な要点の要約、Pythonの例示コードなどは、国内のウェブでもよく整理された文書がたくさんある。
内積空間
ご覧の通り、SVM自体は概念的にそれほど難しくはないが、数学的な定義を引き出し数式を記述した理由は、今後具体的に、理論的に話すことが多いためである。
ユークリッド空間 Rp はもちろんベクトル空間であり、内積空間でもあり、内積空間は距離空間であるため距離空間でもある。これを強調するのは、実際のデータの世界で内積空間というのが思ったよりも良い仮定であるためである。例えば、画像や文書、分子構造などをSVMにそのまま入れてもいいのか、頭を悩ませることになる。定義では暗黙のうちに「距離が近い」やベクトルの内積が含まれる線形関数 f を使用しているが、理論に近づくほど、これらの仮定を当然とすることはできない。
サポートベクター
元々このような幾何問題では、境界boundary上にあるものをサポートと呼ぶが、例えば最小包含円問題でも円を決定する円周上の点をサポートとする。SVMの起源となったサポートベクターも同様で、x+,x− は二つの集合 X+,X− の観点から見ても、δ/2 からX+,X− の距離に位置する境界上にある。
サポートベクターがH それぞれで一意である保証はないが、今後の議論で一意性が重要ではないため、一般性を失わずに一意であると仮定しよう。{xk}k=1n のマージンにはデータが存在せず、
f(x){≥+1≤−1,if x∈X+,if x∈X−
であるため、すべての∣f(xk)∣≥1 に対してH でなければならない。
マージンの最大化
サポートベクターはH と最も近い点であるため、δ/2 との距離H はサポートベクターがw 方向に垂直に離れたときの距離である。このマージンはx+ でもx− でも同じであり、両方とも超平面H との距離がδ/2 であることは、二つのサポートベクター間の距離が
δw=x+−x−
として表されることを意味する。ここでx+−x− のような演算はX がベクトル空間であるという仮定に基づいて許可される。δw=x+−x− の両辺にw と内積を取ると、つまりwT を左側に掛けるとf の定義に従って
⟹⟹⟹⟹⟹δw=x+−x−δwTw=wTx+−wTx−δ∥w∥22=(wTx++b)−(wTx−+b)δ∥w∥22=+1−(−1)δ∥w∥22=2δ=∥w∥222
を得る。つまり、マージンを最大化することは目的関数 ∥w∥22/2 を最小化することであり、要約するとSVMとは次のような最適化問題を解くオプティマイザーoptimizerである。
Minimizesubject to21∥w∥22∣f(xk)∣≥1k=1,⋯,n
派生モデル
難しい定義に従えば、SVMは直線であれ超平面であれ、いずれにしても線形関数を見つける線形回帰モデルであるが、当然ながらここで満足するわけがない。
ソフトマージンSVM
例えば、次のようなデータが入ってきたとしよう。SVMはデータが混在している中央部分のために、これを完全に二値分類することができない。

ここで、サポートベクターのマージンにデータが存在できないという制約のもとで∣f(xk)∣≥1 という条件を満たさなければならなかったことに注目してみよう。この不等式を1 より小さい値に許容すれば、完全な二値分類ではないにしても、完全に諦めるよりは良い結果をもたらすだろう。そして、この許容を各データごとにξk≥0 とすると、新たな制約条件∣f(xk)∣≥1−ξk を得る。このように条件が緩和されたマージンをソフトマージンsoft Marginという。
もちろん、制約が少し緩和されたとはいえ、すべてをξl=⋯=ξn=1 にしてしまうとSVM自体を放棄してしまうことになる。これを防ぐためには、目的関数に∑kξk のような項を加えることがある。これは不可能な二値分類を可能にしたことに対する代償penaltyである。もちろん、このような単純なペナルティはデータのスケールによっては全く意味がなかったり、逆に過敏に反応したりするため、0≤∑kξk≤n そのままではなく、適切な正の数λ>0 を掛けて追加することにしよう。
Minimizesubject to21∥w∥22+λ∑k=1nξk∣f(xk)∣≥1−ξkξk≥0k=1,⋯,n
カーネルトリック

例えば、上のようなデータが与えられた場合、ソフトマージンであろうとなかろうと、SVMでは決して二値分類することができないように見える。しかし、よく見ると0 に近い側には空色の点が集まっており、外側にはオレンジ色の点が現れていることが明らかである。この情報を活用するために、次のようにz 軸を新たに作ってみよう。
ϕ(x,y):=(x,y,x2+y2)
上の図は、下の図を適切にキャプチャしたものである。下はマウスで対話可能な3D空間なので、いろいろと回して見てみてください。
元のR2 ではデータを二分する直線を見つけるのが難しかったが、このようにデータを説明する次元を増やしたR3 では、適切な平面でデータを分類するSVMを使用できるようになった。ここで自然に思い浮かぶ疑問は、「それでは、このように便利な変換ϕ をカーネルkernelと呼び、カーネルを使用する方法をカーネルトリックkernel Trickと呼ぶのか?」ということである。半分正しく、半分間違っている。ϕ にさらに一歩進んで、内積まで含まれたものがカーネルである。
再びマージンの最大化に戻って、我々に与えられた最適化問題を再検討してみよう。
Minimizesubject to21∥w∥22∣f(xk)∣≥1k=1,⋯,n
制約条件∣f(xk)∣≥1 は見た目はすっきりしているが、実際にこの問題を解く際にはあまり役に立たない。元の学習データセットでの形に戻すと、k=1,⋯,n に対して
{f(xk)≥1f(xk)≤−1,if yk=1,if yk=−1⟹{yk(wTxk+b)≥1yk(wTxk+b)≥1,if yk=1,if yk=−1⟹yk(wTxk+b)≥1
でなければならない。このような制約条件自体を目的関数に反映させて、制約条件がないかのように扱う方法がラグランジュ乗数法である。yk(wTxk+b)−1≥0 にαk≥0 を掛けた項を元の目的関数から引いたL(w,b) に対して、次の最適化問題を得る。
Minimizesubject to21∥w∥22−∑k=1nαk[yk(wTxk+b)−1]αk≥0k=1,⋯,n
再び強調するが、我々の目的はこの目的関数を最小化するw,b を見つけることであった。w,b に対する目的関数の偏微分が0 となる条件は次の通りである。
∂w∂L=0⟹∂b∂L=0⟹w=k=1∑nαkykxk0=k=1∑nαkyk
これをそのままL に代入してみると
=======L(w,b)21∥w∥22−k=1∑nαk[yk(wTxk+b)−1]21wTw−k=1∑nαkyk(wTxk+b)+k=1∑nαk21wTk=1∑nαkykxk−k=1∑nαkykwTxk−bk=1∑nαkyk−k=1∑nαk−21k=1∑nαkykwTxk−b⋅0+k=1∑nαkk=1∑nαk−21i=1∑nj=1∑nαiyiajyjxiTxjk=1∑nαk−21i=1∑nj=1∑nαiajyiyjxiTxjL(α1,⋯,αn)
を得る。当然ながら、具体的なw とb を計算するためには、学習データ{(xk,yk)}k=1n が必要である。
ここで注目すべき点は、数式でxi とxj の内積が使用されていることである。結局のところ、最終的に、我々は内積を取らなければならず、X が内積空間でなければ、このように順調に進む保証はない。逆に言えば、X が内積空間でなくても、変換ϕ がX を内積空間に送ることができれば、その目的関数が
k=1∑nαk−21i=1∑nj=1∑nαiajyiyjϕ(xi)Tϕ(xj)
であるSVMを検討する価値がある。機械学習では、このように二つのベクトルに対する変換、内積まで含まれた関数
K(xi,xj):=⟨ϕ(xi),ϕ(xj)⟩
をカーネルkernelと呼ぶこともある。[ 注: データサイエンスでは、これと混同される別のカーネルも存在する。元々、数学全般でのカーネルは、名前は同じでも全く異なる機能の関数である。 ]
数式的にここまでの内容を受け入れることができれば、なぜカーネルではなく変換ϕ を導入することをカーネルトリックと呼び、変換後に内積空間であることが保証されることが重要なのかを理解したことになる。
条件を満たす限り、カーネルはいくつかの種類を考えることができる。特に元のSVMも線形カーネルlinear Kernel
K(xi,xj)=⟨xi,xj⟩1=xiTxj
を使用したものと見なすことができる。
参照
カーネルトリックの部分で数学的に簡単な内容を扱ったが、より深い理論に興味がある場合は、SVMを超えて以下の内容を学ぶことをお勧めする。
コード
以下はカーネルトリックを実装したJuliaのコードである。
struct Sphere
d::Int64
end
Sphere(d) = Sphere(d)
import Base.rand
function rand(Topology::Sphere, n::Int64)
direction = randn(Topology.d, n)
boundary = direction ./ sqrt.(sum(abs2, direction, dims = 1))
return boundary
end
using Plots
A = 0.3rand(Sphere(2), 200) + 0.1randn(2, 200)
B = rand(Sphere(2), 200) + 0.1randn(2, 200)
scatter(A[1,:],A[2,:], ratio = :equal, label = "+1")
scatter!(B[1,:],B[2,:], ratio = :equal, label = "-1")
png("raw.png")
Plots.plotly()
ϕ(z) = z[1]^2 + z[2]^2
scatter(A[1,:],A[2,:],ϕ.(eachcol(A)), ms = 1, label = "+1")
scatter!(B[1,:],B[2,:],ϕ.(eachcol(B)), ms = 1, label = "-1")
savefig("kernel.html")