Transformer
Transformer にはencoderのみ、decoderのみ、 encoder-decoderの三種類の構成がある。
- enocder のみ構成
- 入力:シーケンス ※
- 出力:文脈化トークン表現
- decoder のみ構成
- 入力:シーケンス
- 出力:入力シーケンスの次のトークン
- encoder-decoder 構成
- 入力:シーケンス
- 出力:入力シーケンスとは別のシーケンスに関する、次のトークン
- ややこしい表現になってしまったが、encoderとdecoderでそれぞれ別の学習目標や語彙を持つことで、入力シーケンス(例:日本語)と別のシーケンス(例:英語)の「次のトークン」を出力、つまり自己回帰的に繰り返すことで「別のシーケンスを出力」する。
※ シーケンス : 文をトークナイザーによりトークンに分割した「トークンの配列」
例 : ['私は', 'GPT', '-', '5', 'です', '。']
コンポーネント
いずれの構成も、以下のコンポーネントの組み合わせからなる。
- トークン埋め込みの作成
- これはencoderブロックやdecoderブロックの外側に置かれる。
- 自己注意機構 (self-attention mechanism) ※
- マスク付き自己注意機構 (masked self-attention mechanism) ※
- 交差注意機構 (cross-attention mechanism) ※
- フィードフォワード層 (feed-forward layer)
※ Transformerにおいては、全ての注意機構は マルチヘッド注意機構 (multi-head attention) が採用されている。複数の独立した注意機構(ヘッド)に対して同じクエリを与え、出力を連結する。
トークン埋め込みの作成
- 入力されたシーケンスをベクトル行列化
- このベクトル行列を便宜上「入力トークン埋め込み」という
- これに位置情報を加える(以下のいずれかの方法)
- 位置符号 position encoding
- 入力トークン埋め込みと同次元のベクトル
- その場で算出する
- 入力トークン埋め込みに加算
- 位置埋め込み position embedding
- 入力トークン埋め込みと同次元のベクトル
- 学習で作成する
- 推論時には単に入力トークン埋め込みに加算する
- 位置符号 position encoding
- 最終的に、「位置情報を含むベクトル」の配列を出力する
- 便宜上「位置情報付き入力トークン埋め込み」という
自己注意機構 (self-attention mechanism)
- 入力 : 位置情報付きトークン埋め込み
- 出力 : 行列内の他の全アイテムからの影響を加味したベクトルの行列
- これを便宜上「文脈化トークン表現」と呼ぶ。
Transformerでは key-query-value attention mechanism が採用されている。
- 入力トークン埋め込み(ベクトルの行列)から三種類の埋め込み(ベクトルの行列)を作成
- query 埋め込み
- 「どの特徴を参照したいか」を表現。
- 後述するマルチヘッド注意機構では、ヘッドごとにここを変える。
- key 埋め込み
- 「どんな情報を含むか」を表現。
- value 埋め込み
- 情報の本体。
- query 埋め込み
- 各 query ベクトルごとに、全 key ベクトルそれぞれとの 関連性スコア を算出
- 算出した関連性スコアで、value ベクトルを加重平均
- これにより、シーケンス内の全トークンを加味したベクトルが得られる。
query, key, value はそれぞれ以下のようなイメージ
- クエリ:「マウス」
- キー「マウス(動物)」:バリュー「哺乳類、齧歯類、不衛生、実験、ミッキー」
- キー「マウス(コンピュータ)」:バリュー「デバイス、PC、Mac、ポインタ、カーソル、USB」
つまり、自己注意機構とは「位置情報付きトークン」の行列を受け取り、その各アイテム(トークン)ごとに「行列内の他の全アイテムからの影響」を加算して出力する機構といえる。
マスク付き自己注意機構 (masked self-attention mechanism)
自己注意機構は、入力行列の各アイテムに対して「全アイテムからの影響」を加算する機構。そのため、影響を与えたくないアイテムを隠したい(マスク)場面がある。
- 入力シーケンス全体を表現したい場合
- つまり、encoderとしての用途
- 隠すべき部分がないのでマスク不要 ※
- 入力シーケンスの一部(途中まで)を表現したい場合
- 言い換えると「正解シーケンスの途中までわかっている状況で、次のトークンを予測」したい状況。
- これは「次トークン予測」の学習時の状況。つまりdecoderとしての用途。
- つまり、decoderの学習時に、未来のトークン(正解トークン)をマスクする。 ※
- decoderの推論時は未来のトークンが存在しないのでマスク不要 ※
※ ここで言っているのは「因果マスク」であり、このほかに「Padマスク」もある。Padマスクは、なんらかの都合でシーケンスに付加された padding (特殊トークンや 0
など) を無視するために用いられる。また、decoderの推論時は原理的に因果マスク不要だが、実装では様々な理由(キャッシング対応等)でマスクをつけるのが一般的。
交差注意機構 (cross-attention mechanism)
自己注意機構では query 、key 、value の全てを同一の入力から作成したが、これを2種類の入力から作成する。具体的には入力Aから query を、入力Bから key と value を作成する。そのため出力行列は入力Aと同じ長さになる。「ターゲット行列をソース行列で表現する」と言ってよさそう。
なお、ここでいう入力Aを ターゲット 、入力Bを ソース と呼ぶ。
フィードフォワード層 (feed-forward layer)
- ニューラルネットワーク。
- 一般的には2層(中間層が1つ)。
- 活性化関数は Transformer 提案当初は ReLU だったが、LLMではGELUが標準的。
- 提案時で、 Transformer 全体のパラメータの 2/3 がフィードフォワード層。
- 入力次元 512 に対して 中間層の次元は 2048
- 入力、出力ともに便宜上「文脈化トークン表現」と呼べる。情報の付加というより、ニューラルネットワークによって表現力を増すレイヤといえる。
LMヘッド
フィードフォワード層からの出力は「文脈化トークン表現」のまま。一般的なニューラルネットワークにおける「出力層」は出力したいベクトルに合わせるAffine変換を行うが、Transformerの(エンコーダまたはデコーダ)ブロックはブロック単位で直列に繋げて処理できる(例:GPTはデコーダを12個直列)設計になっているので、ターゲットフォーマットへの変換はブロックの外に置く(最後に一度だけ行いたいので)。イメージとしては「 フィードフォワード層=出力層のないニューラルネットワーク」のような感じ。
この、ブロックの外で最後に一度だけ行うAffine変換層を LMヘッド と呼ぶ。
Transformer 全体の構成
encoderのみ、decoderのみ、 encoder-decoderの三種類の構成がある。各構成について、コンポーネントの組み合わせ・フローを説明する。
- enocder のみ構成
- エンコーダブロック
- トークン埋め込みの作成
- 自己注意機構
- フィードフォワード層
- (必要に応じてタスク用ヘッド)
- エンコーダブロック
- decoder のみ構成
- デコーダブロック
- トークン埋め込みの作成
- 自己注意機構(マスク付き)
- フィードフォワード層
- LMヘッド
- デコーダブロック
- encoder-decoder 構成
- トークン埋め込みの作成
- エンコーダブロック
- 自己注意機構
- フィードフォワード層
- 以下をループ(出力を入力に戻す)
- トークン埋め込みの作成
- デコーダブロック
- 自己注意機構(マスク付き)
- 交差注意機構
- ソース = エンコーダの作成した「文脈化トークン表現」
- ターゲット = 前段からの入力
- フィードフォワード層
- LMヘッド
なお、いずれの構成でも各コンポーネント間の接続では 残差結合 (residual connection) と 層正規化 (layer normalization) を行う。
エンコーダのみ構成
- エンコーダブロック
- トークン埋め込みの作成
- 入力シーケンスから「位置情報付きトークン埋め込み」を作成する。
- 自己注意機構
- 「位置情報付きトークン埋め込み」から「文脈化トークン表現」を作成する。
- フィードフォワード層
- 「文脈化トークン表現」の表現力を増す。
- トークン埋め込みの作成
- (必要に応じてタスク用ヘッド)
- 分類・回帰などのタスクごとにヘッド(文脈化トークン表現をターゲットベクトルフォーマットへ対応させるAffine変換層)を置く
入力としてシーケンスを受け取り、最終的に「文脈を加味したベクトル表現」を出力する。
デコーダのみ構成
- デコーダブロック
- トークン埋め込みの作成
- 自己注意機構(マスク付き)
- フィードフォワード層
- LMヘッド
エンコーダと異なり、自己回帰的(自分の出力を入力に戻す)なのが特徴。
- 例:
['私は', 'GPT', '-', '5']
の次のトークンを予測- 入力:
['私は', 'GPT', '-', '5']
→出力:です
- 入力:
['私は', 'GPT', '-', '5', 'です']
→出力:。
- 入力:
['私は', 'GPT', '-', '5', 'です', '。']
→出力:<終了トークン>
- 入力:
デコーダブロックの機能は「次のトークンを予測」だが、フィードフォワード層の出力(デコーダブロックの出力)は入力シーケンスの表現であり、次のトークンではない。最後のLMヘッドがターゲット=次のトークンを出力するわけだが、LMヘッドは1層のAffine変換のみ。これでなぜそんなことができるかというと、「フィードフォワード層の出力(文脈化トークン表現)のアイテム(ベクトル)→LMヘッド→次トークン確率」となるように学習しているから。少し乱暴だが「文脈化トークン表現が次のトークンを表現している」と理解してしまっても差し支えない。
エンコーダ・デコーダ構成
エンコーダ・デコーダ構成は「エンコーダの作成した表現を元に、デコーダで0からシーケンスを生成する」機構と言える。
- トークン埋め込みの作成
- エンコーダブロック
- 自己注意機構
- フィードフォワード層
- 以下をループ(出力を入力に戻す)
- トークン埋め込みの作成
- 入力 = 前回までのデコーダの出力
- デコーダブロック
- 自己注意機構(マスク付き)
- 交差注意機構
- ソース = エンコーダの作成した「文脈化トークン表現」
- ターゲット = 前段からの入力
- フィードフォワード層
- LMヘッド
- トークン埋め込みの作成
上の書き方だと上から下までリニアに見えるが、エンコーダブロックの出力を得た後、デコーダブロックを(<終了>
トークンが出るまで)自己回帰的にループする。エンコーダブロックの出力はデコーダブロックの入力ではなく、交差注意機構のソースとして与える。デコーダブロックの入力はあくまで(前回までの)自分自身の出力。
デコーダは「入力シーケンスの次のトークンを予測」するものだが、エンコーダ・デコーダ構成ではデコーダの入力シーケンスの初期値は空。そのため1つめのトークンとして「開始トークン」を用いる。その上で、交差注意機構において「開始トークン」についてエンコーダの作成した表現の加重平均を取った結果、1つめのトークンを得ると説明してよいだろう。
Discussion