見出し画像

トランスフォーマーの自己アテンションの理解③レコメンダーと内積

この記事ではアテンションの計算で使われる内積(Dot Product)についてレコメンダーシステム(Recommender System)を例に解説します。ベクトルを使った内積の計算自体は簡単なのですが、なぜそれが役に立つのかを具体例で見ることでトランスフォーマーの自己アテンションを理解する際の足がかりになるからです。

では、さっそく始めましょう。


レコメンダーシステム

Netflixが映画やドラマの推薦をする際に、ユーザーの好みや映画の特徴などからどのユーザーにどの作品をオススメするのか判断するシステムを使っています。これをレコメンダーシステムと呼びます。また、Amazonが商品をオススメする際にも何らかのレコメンダーシステムが使われています。

実際のシステムの実装の詳細までは分かりませんが、何らかのベクトル値を使って映画の特徴などを捉えていると考えられます。第一弾、第二弾で話をした分散表現もベクトルであり、それがトークンの特徴であるか、映画の特徴であるか、あるいはユーザーの特徴なのかといった違いはありますが、ベクトルとして表現された何らかの特徴であることは同じ概念になります。

ここでは映画とユーザー(視聴者)を使った簡単な例を使って説明します。

ユーザーのアクション好きの度合い

例えば、ユーザーがアクション関連の映画をどの程度好むかの情報があるとします。数値が高いほどアクションが好きなユーザーになります。

$$
\begin{bmatrix}
タロウ 1.2 \\
ジロウ 1.5 \\
サトコ 2.1 \\
シズカ 1.3
\end{bmatrix}
$$

サトコはアクション好きですね。

映画のアクション度

また、各映画ごとのアクション度を数値化した情報があるとします。数値が高いほどよりアクションが多く含まれています。

$$
\begin{bmatrix}
ゴージラ君 & ガーンガム & キリンの惑星 \\
4.5 & 6.3 & 0.5
\end{bmatrix}
$$

「ガーンガム」はアクション性が高く、「キリンの惑星」は平和な映画でしょう。

ユーザーによる映画の評価

ここで、ユーザーの好みを行列Pとし、映画のアクション度を行列Qで表します。

$$
\begin{align*}
P &= \begin{bmatrix}
1.2 \\
1.5 \\
2.1 \\
1.3
\end{bmatrix} \\
 \\
Q &= \begin{bmatrix}
4.5 & 6.3 & 0.5
\end{bmatrix}
\end{align*}
$$

この二つの行列を掛け合わせると、ユーザーごとにどの映画にどのくらいの評価・格付けをするであろうかが見えてきます。

$$
\begin{align*}
R &= P\,Q \\
&= \begin{bmatrix}
1.2 \\
1.5 \\
2.1 \\
1.3
\end{bmatrix}
\begin{bmatrix}
4.5 & 6.3 & 0.5
\end{bmatrix} \\
&= \begin{bmatrix}
5.4 & 7.56 & 0.6 \\
6.75 & 9.45 & 0.75 \\
9.45 & 13.23 & 1.05 \\
5.85 & 8.19 & 0.65
\end{bmatrix}
\end{align*}
$$

以下に、表にまとめました。

ユーザーのアクション好き度と映画のアクション性の掛け合わせ

黄色でハイライトした数値を見ると、サトコが「ガーンガム」を高く評価したであろうと推測されます。なぜなら、サトコはアクション好きでガーンガムはアクション性が高いからです。

他のユーザーに何を勧めるか

ここでもう一人のユーザー、ジョンが登場します。ジョンがどれほどのアクション好きかは未知数です

ただし、情報としてジョンが「ゴージラ君」に高い評価10点を与えたと分かっているとします。その他の映画は見ていません。さて、どの映画をオススメしましょうか。

「ゴージラ君」のアクション度は4.5なのでジョンの「ゴージラ君」に対する評価が10点であることを考慮して、ジョンのアクション好きの数値を計算します。

$$
\begin{align*}
4.5 x &= 10 \\
       x &= \frac{10}{4.5} \\
       x &\approx 2.2
\end{align*}
$$

ジョンのアクション好き度の数値はおおよそ2.2であることがわかりました。サトコ以上にアクション好きですね。

ジョンのアクション好き度がわかったので、残りの映画に対する評価の予想も計算できます。

アクション好きのジョンには「ガーンガム」がお勧めですね。

アクション好きに対してアクション映画を選ぶのは当たり前のように思えますが、全て数値で計算できていることが重要です。

逆にいうと数値化してしまえば、その意味を解釈する必要もなくなります。というか簡単に解釈できないようなことも数値化できてしまいます。

次に、これを深掘りしましょう。

ユーザーと映画を分散表現に

ここまで、アクション度に対する好みという一つの特徴を元にしたユーザーと映画の関係を見てきました。また、ユーザーの映画に対する評価から、ユーザーの特徴を引き出すこともできました。

この話を拡張していきます。映画の特徴としてアクション、コメディ、恋愛、クラシック、サムライ、SFなどたくさんの項目が考えられます。しかし、映画の特徴は複雑ではっきりとした項目に分解できるとも限りません。

そこで映画の特徴を分散表現としてベクトルで表します。仮に2次元ベクトルを使うとします。

$$
\begin{align*}
\text{映画1} &= [ 1.3, 3.6 ] \\
\text{映画2} &= [ 2.4, 0.9 ] \\
\text{映画3} &= [ 0.5, 0.1 ]
\end{align*}
$$

ユーザーの特徴も分散表現にします。簡単のため、これも2次元ベクトルにしておきます。

$$
\begin{align*}
\text{ユーザー1} &= [ 0.6, 2.5 ] \\
\text{ユーザー2} &= [ 1.7, 3.1 ]
\end{align*}
$$

分散表現では、各次元の意味は分かりません。アクション好きとかコメディ好きとか個別に数値になっているわけでわありません。ベクトル空間上の位置に何らかの意味が埋め込まれているとしか言えません。

映画もユーザーも分散表現になる、つまりはベクトルなので、内積の計算ができます。内積の値が大きいほど違いの関係が強いと判断します。ここでは単純にユーザーのベクトルと映画のベクトルの内積の結果をユーザーの映画に対する評価値とします。

ここで、内積の計算について解説をします。内積とはベクトル内の各次元の数値を掛け合わせてから全てを足し合わせたものです。英語ではdot-product(ドット・プロダクト)と呼び、内積を点で表します。

例えば、ユーザー1と映画1の内積は以下のように計算できます。

$$
\begin{align*}
\text{ユーザー1} \cdot \text{映画1} &= [0.6, 2.5] \cdot [1.3, 3.6] \\
&= 0.6 \times 1.3 + 2.5 \times 3.6 \\
&= 9.78
\end{align*}
$$

同様に、映画2の内積を計算して評価の値を出します。

$$
\begin{align*}
\text{ユーザー1} \cdot \text{映画2} &= [0.6, 2.5] \cdot [2.4, 0.9 ] \\
&= 0.6 \times 2.4 + 2.5 \times 0.9 \\
&= 3.69
\end{align*}
$$

ユーザー1は映画1を映画2よりも高く評価していることがわかりました。

2次元なのでベクトルを描いてみるとユーザー1と映画1の方向が映画2よりもより似ているのが分かります。

つまり、似た方向を向いている(ベクトル間の角度が小さい)ベクトル同士の内積はより大きくなるのがわかります。

以上から、ユーザーの特徴と映画の特徴をベクトルとして表現し、内積を計算することでそのユーザーの映画に対する評価の値を得ることができました。

また、ベクトルの次元を増やせばより多くの情報を埋め込むことができます。そして内積は次元が増えても計算の方法は同じく単純なので相性が良い手法だと言えます。

ユーザーや映画同士を比べる

ベクトルにすることで映画同士どのくらい似た特徴を持つのかも計算することができます。その際には2つの映画のベクトルで内積を計算します。また、ユーザー同士で似ているかも2つのユーザー間の内積で推定できます。

似ているユーザーが高く評価する映画をオススメしたり、ユーザーが過去に見た映画と似た映画を進めるといった使い方が成り立ちます。

内積の手法は単純で応用が効きます。映画やその視聴者などだけでなく、何らかの関係があるもので分散表現、つまりベクトル化できるものなら何でも適用できるのです。もちろん、ニューラルネットワークなどを使って効果的な埋め込みを行うことが必要ではあります。デタラメの分散表現では、内積の結果もデタラメにしかなりません。よって、埋め込みを上手に行うことが最も重要になります。

繰り返しますが、埋め込みによるベクトル化と内積による関係の強さの数値化が非常に重要ですそれは人間が考えてルールを決められるようなものではありません。そのため、たくさんのデータを集めてモデルの訓練する必要があるわけです。

内積で質問をする

これまで単純な内積でベクトル同士が似ているかどうかの判断をしてきました。しかし、映画と人間を同等に扱うのもちょっとおかしな話で実際のシステムはもっと込み入ったことをしているでしょう。ただし、内積の意味は十分に感じ取っていただいたのではないかと思います。内積は似たもの同士で強い反応をしまします。

さて、内積を単に似たものを探すための計算として見るのではなく、ユーザーから映画への問いかけとしてとらえてみましょう。あるいは、ユーザーからユーザーへの問いかけでも構いません。

「私はこういう評価をするんだけど、あなたはどんな感じ?」

質問としての内積

そう考えると単純な内積は似たものを探す質問と解釈できます。では、もっと異なる質問をしたいとしたらどうでしょうか。

質問したい内容に関連した特徴を各々のベクトルから抽出した上で内積を計算すれば良いのです。そうすれば、質問の内容と似た特徴を持つベクトルを見つけることができます。

例えば、ユーザーのベクトルからホラー映画好き関連を特徴量として抽出できるとします。そして、映画からホラーの度合いなどの特徴を引き出すこともできるとします。この二つの特徴ベクトルで内積を計算すれば、ユーザーがその映画をどのくらい評価するのかが数値として計算できます。

ただし、ホラー映画好きの度合いを抽出するすべを人間が考えて作るのは困難です。映画のホラー度を引き出す計算方法を定義するのも同じく難しいです。ではどうやって質問や質問に関連した重要な要素(キー、Key)を抽出するのでしょうか。

ユーザーベクトルはユーザー空間にあります。これを質問のための特徴を引き出す行列Qを使って特徴空間へと写像(異なる空間のベクトルに変換)します。

ユーザー空間から特徴空間への写像

ここでユーザー空間と特徴空間の次元は同じである必要はありません。ユーザー空間が512次元で特徴空間が128次元でもいいわけです。よって、ユーザーの空間から特徴の空間へと引き出した特徴を転送するといったイメージになります。行列Qと呼んでいるのは質問(QuestionあるいはQuery)からQを取っただけです。

ちなみに、行列がベクトルの次元を変えられるのは以下の例を見れば明らかです。2行3列の行列で3次元ベクトルを2次元ベクトルに変換しています。

$$
\begin{bmatrix}
1 & 2 & 3 \\
2 & 1 & 5
\end{bmatrix}
\begin{bmatrix}
3 \\
2 \\
1
\end{bmatrix}
=
\begin{bmatrix}
10 \\
13
\end{bmatrix}
$$

さらに、映画のベクトル空間から質問に応じた特徴を取り出すための行列Kを使います。KはKey(キー)からきています。

映画空間から特徴空間への写像

行列Kによって映画のベクトルから質問に応じて取り出したキー要素を特徴空間のベクトルに変換します。ここでも、映画空間の次元は特徴空間の次元と同じである必要はありません。また、映画空間の次元はユーザー空間の次元と異なっていても構いません。これでユーザーと映画の分散表現を同じ空間のベクトルとして扱う必要がなくなりました。

行列Qによってユーザーが質問する特徴を特徴空間のベクトルに変換しました。また、行列Kによって質問に応じた映画の特徴を特徴空間のベクトルに変換したので、これで質問とキー要素が特徴空間のベクトルとなり、同じ次元のベクトル同士なので内積を計算することができます。

ではどのようにして行列Qと行列Kを定義するのでしょうか。これもニューラルネットワークの一部として訓練します。よって、行列Qを使って質問を引き出す時は、必ず行列Kを使う必要があります。そうすることで両方の行列が一緒に訓練されるので行列Qの質問に応じたキー要素を行列Kが取り出せるようになっていきます。

トランスフォーマーでも同様な行列を使いますが、QとKの1組だけでなく、複数の質問行列とキー要素行列を使い、様々な質問とそれに対する応答ができるようになっています。

$$
Q_1 \leftrightarrow K_1 \\
Q_2 \leftrightarrow K_2 \\
Q_3 \leftrightarrow K_3 \\

$$

イメージをつかみやすいようにホラー映画の例に例えると、行列$${Q_1}$$がホラー関連の特徴をユーザーからの質問として取り出し、行列$${K_1}$$がホラー関連の特徴を映画からのキー要素としてとして取り出します。そして、この両方の要素で内積を計算することでホラー関連の特徴におけるユーザーと映画の関係の強さを見ることができます。

もちろん、実際にはホラーの度合いなど人間が簡単に理解できる質問になるわけではありません。ニューラルネットワークが学習してどのような質問とキー要素を引き出せば映画の推薦に適しているかの判断ができるようになるのである意味ブラックボックスではあります。また、ユーザーのフィードバックなどを通して常に(あるいは定期的に)学習し微調整していくことは必要になります。

そのようにして鍛えられたネットワークはもしかしたらこんな質問をユーザーから引き出しているのかもしれません。

「私はゾンビが出てくるホラーが好きで、しかもハッピーエンドじゃないとイヤ、さらにSF的な要素も欲しいし、できればゾンビはゆっくり歩くタイプがいい」

あるユーザーの質問

それはユーザー自体も意識していないような特徴を表現しているのかもしれません。大量のデータから得られた情報のなせる技です。

まとめると、ユーザーのベクトルから全ての値をそのまま使うのではなく、ある質問に関連した特徴量(質問)だけを取り出します。また、映画のベクトルからも特定の特徴量(その質問に対するキー要素)を取り出します。その特徴量同士での内積を計算すれば、相性の強さがわかるわけです。

よって、ホラー好きの人から取り出した特徴量は、ホラー映画とマッチする可能性は高くなります。また、ホラー好きでない人から取り出した特徴量は、ほとんどのホラー映画の特徴とはマッチしないのでホラー映画をオススメすることはなくなります。

これまで映画に関連した例で話してきましたが、次には言語モデルに当てはめて議論を進めます。

言語トークンへの質問

映画の代わりに言語トークンを考えましょう。埋め込みによりベクトル化されたトークン間の関係の強さは内積によって測ることができます。これはRNNベースのエンコーダ・デコーダでもアテンションの計算に使われていました。

トランスフォーマーでも内積を使ってアテンションを計算します。また、質問やキー要素を引き出すことで様々なトークン同士の関係を引き出すことができます。これによってどのトークンからどのくらいの情報(文脈、隠れ状態)を受け取るかの判断を行います。

そこには再帰を使う必要が全くありません。なぜならトークン間の関係を直接に計算するからです。

また、前述したようにトランスフォーマーでは質問やキー要素を引き出す行列をいくつか用意しているため、多方面からトークン関係の強さを得ることができます。それはもしかすると文法に関するものや決まり台詞にかかわるものかもしれません。私たちが想像もできないような特徴をとらえている可能性もあります。

大量のデータによる訓練によって調節されたネットワークのパラメータによって抽出されるので、基本的にはブラックボックスですが、アテンションの効果をビジュアル化する試みも行われています。

トランスフォーマーでは、シーケンスの中の各トークンから全てのトークンに対して質問をし、キー要素を引き出して重要な関係を見つけて、関連のつよいトークンからの隠れ状態をより多く取り込んでいきます。このようにして、広い範囲に渡って文脈を抽出できるよう学習することができます。

自己アテンション

そしてこの仕組みが自己アテンションとなり、RNNやLSTMに見られた再帰の構造なしに文脈を抽出することに成功しました。よって再帰に構造による勾配消失の問題もありません。

それでは、次回は本題のトランスフォーマーの自己アテンションの仕組みを見ていきましょう。

(続く)


いいなと思ったら応援しよう!