クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

トランスフォーマーの注意の仕組み

このレッスンのあとで: 1つのトークンについて、注意の出力を手で計算することができる。

65分のレッスンコマンド2件JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

この語には、前のどの語が大事か

注意とは、トランスフォーマーの中で、各トークンがほかのトークンを見て、必要なものを取り込む手順です。言語モデルが「それ」を、ずっと前の正しい名詞と結び付けられるのは、この手順のおかげです。

「先生の猫」の 猫 は、誰の猫かを知るために 先生 を見る必要があります。注意は、それを数で行う方法です。

このレッスンのゴール

メモ

1つのトークンについて、注意の出力を手で計算することができる。

キーワード

ことばいみれい
クエリトークンが何を探しているかを表すベクトル
キートークンが何を差し出せるかを表すベクトル
バリュートークンが渡す中身を持つベクトル
スコアクエリとキーがどれだけ合うか2
softmaxスコアを合計1の割合に変える計算
重み出力に入るバリューの割合0.665

学生が入力するセルは、このプレビューでは空白です。

どのトークンにもクエリ、キー、バリューがある

前に学んだ線形代数では、表とベクトルのかけ算を扱いました。注意では、各入力ベクトルに学習で決まる3つの表をかけて、3つの新しいベクトルを作ります。

クエリは、このトークンが何を探しているかです。キーは、ほかに何を差し出せるかです。バリューは、選ばれたときに渡す中身です。ここでは、3つのベクトルができたところから始めます。

例: 猫 のクエリのスコア

トークンキー猫 のクエリ × キースコア
先生2, 11×2 + 0×12
の0, 21×0 + 0×20
猫1, 11×1 + 0×11

学生が入力するセルは、このプレビューでは空白です。

softmax でスコアを重みにする

スコアはどんな大きさにもなり、0より小さいこともあります。softmax は、それをすべて正で、合計が1になる重みに変えます。

まず、各スコアを e の何乗かにします。電卓の exp のボタンです。どの数も正になり、大きいスコアはずっと大きくなります。それから、それぞれを合計で割ります。本物のモデルは、先に全スコアを決まった数で割ります。ここでは省きます。

例: 2、0、1 の softmax

トークンスコアe のスコア乗重み: 11.11 で割る
先生27.390.665
の01.000.090
猫12.720.245
合計11.111.000

学生が入力するセルは、このプレビューでは空白です。

NumPy でスコアと重みを出す

コマンド
docker exec jupyter python3 -c "import numpy as np; K = np.array([[2, 1], [0, 2], [1, 1]]); s = K @ np.array([1, 0]); w = np.exp(s) / np.exp(s).sum(); print(s.tolist(), w.round(3).tolist())"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力はバリューを重みで混ぜたもの

各トークンのバリューに重みをかけて、その結果を足します。その合計が、猫 の新しいベクトルです。

猫 は重みの約3分の2を 先生 に置いたので、先生 の意味の一部を持つようになります。どのトークンも、自分のクエリで同時に同じことをします。

例: バリューを混ぜる

トークン重みバリュー重み × バリュー
先生0.66510, 06.65, 0
の0.0900, 100, 0.90
猫0.2455, 51.22, 1.22
出力約 7.88, 2.12

学生が入力するセルは、このプレビューでは空白です。

Python で1トークンの注意を計算する

コード: python
import math

keys = [[2, 1], [0, 2], [1, 1]]       # 先生、の、猫
values = [[10, 0], [0, 10], [5, 5]]
query = [1, 0]                        # 猫 のクエリ

scores = []
powers = []
for key in keys:
    score = query[0] * key[0] + query[1] * key[1]
    scores.append(score)
    powers.append(math.exp(score))
total = sum(powers)

weights = []
mix = [0, 0]
for i in range(len(values)):
    weight = powers[i] / total
    weights.append(round(weight, 3))
    for j in range(2):
        mix[j] = mix[j] + weight * values[i][j]

print("スコア:", scores)
print("重み:", weights)
print("出力:", round(mix[0], 2), round(mix[1], 2))
# query を [0, 1] に変えて実行してください。いちばん重みが大きいのはどれですか。

よくある間違い

注意

注意は1つのトークンを選び、ほかを無視すると考えがちです。実際は、すべてのトークンのバリューを少しずつ取り込みます。重みが0に近いのは、キーがクエリにあまり合わないときだけで、重みの合計はいつも1です。

3つのトークンの注意を一度に出す

コマンド
docker exec jupyter python3 -c "import numpy as np; Q = np.array([[0, 1], [1, 1], [1, 0]]); K = np.array([[2, 1], [0, 2], [1, 1]]); V = np.array([[10, 0], [0, 10], [5, 5]]); S = Q @ K.T; W = np.exp(S) / np.exp(S).sum(axis=1, keepdims=True); print(W.round(3).tolist()); print((W @ V).round(2).tolist())"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

このラボとソースについて: JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。