内積は近さを測る
検索窓に単語を打っても、エンジンは文章を一文字ずつ比べたりしません。各文章をベクトルに変え、二つのベクトルがどれだけ同じ方を向くかを見ます。この「どれだけ同じ方か」を一つの数に詰めこむ道具が内積です。a·b = |a||b|cos(theta)。二つの長さと、なす角のコサインを掛けた値ですね。ここから長さを取り除くと cos(theta) だけが残り、これがコサイン類似度です。同じ向きなら近く、直角なら無関係、反対なら正反対。検索も推薦も単語埋め込みも、すべてこの一行の上で動きます。
緑の矢印 a は固定して、青の矢印 b を二つのつまみで操作してみてください。片方のスライダーは b の角度を、もう片方は b の長さを変えます。画面の a·b の値が両方のつまみに反応するのを見てください。b を長くすると値がまるごと大きくなり(長さの効果)、b を回すと、同じ方を向くとき正、直角で 0、反対で負へと曲がります(整列の効果)。符号に応じて色が緑・淡色・赤に変わります。a へ落とした b の足(射影)も一緒に動きます。一つの内積が長さと整列の二つを同時に担うことを、手で感じてみてください。
内積は別の目でも見られます。a を +x 軸に長さ 2 で寝かせ、b の角度だけをスライダーで回してみてください。軸の上に金色で描かれるのが、b を a へまっすぐ落とした影、すなわち射影です。すると a·b はちょうど |a| 掛けるその射影の長さになります。b を a の方へ倒すと影が伸びて内積は大きく、b を立てるほど影が縮んで内積は小さくなります。直角になると影が 0 なので内積も 0。内積は結局、「一方のベクトルがもう一方の向きへどれだけ伸びたか」を長さで測り、|a| 倍した値です。
内積の符号だけ取り出すと、規則はとても単純です。a を +x 軸に置き、b の角度 theta を 0 度から 360 度までスライダーで掃いてみてください。平面が二つの領域に塗り分けられます。a と同じ側の半平面(theta が 90 度以内)は緑がかり、そこでは内積が正です。ちょうど 90 度と 270 度、直角では 0。反対側の半平面(90 度と 270 度の間)は赤みを帯び、内積が負です。b を回すと、画面の語が正・0・負に切り替わり、値も一緒に出ます。符号一つで「同じ側か、無関係か、反対側か」が一目で決まります。
今度は長さを完全に取り除きます。cos(theta) = a·b / (|a||b|)。この値はつねに -1 と +1 の間に収まります。a を固定し、b の角度と長さを二つのスライダーで変えてみてください。決定的な場面があります。b の長さだけ伸ばしても縮めても、cos(theta) はびくともしません。下に -1 から +1 まで引かれたゲージの針はその場のままです。逆に角度を回すと、針がすっと滑ります。コサイン類似度は大きさを無視し、向きだけを見ます。だから検索エンジンも埋め込みも、文章が長かろうと短かろうと、指す向きだけで二つの文章が近いかを比べます。
最後に、内積がちょうど 0 になる瞬間を自分で捕まえてみてください。a は固定。青の矢印 b を手で引いて平面の上を動かしてみましょう。画面に a·b の値がリアルタイムで出ます。b が a と直角をなす場所を通るとき、値が 0 を横切って矢印が光り、「直交」という語が現れます。内積が 0 とは、二つの向きが完全に垂直、つまり互いに無関係で独立だという意味です。この性質が座標軸をきれいにします。x 軸と y 軸が直交しているから、一方の軸へ動いても、もう一方の軸の値は揺れません。きれいな基底はすべて、この「内積 0」から生まれます。