[上級編]LLMへ至る道~TransoformerのEncoderって何をエンコードするの?~[17日目]

[上級編]LLMへ至る道~TransoformerのEncoderって何をエンコードするの?~[17日目]

Clock Icon2023.12.17

みなさんこんにちは!クルトンです。

前日はTransformerモデルのAttentionについて見ていきました!queryとkeyとvalueというものを使って計算しているものでした。

本日は、Transformerモデルの主要な機構の一つであるEncoderについて確認していきます!

Encoderは何するものぞ

Encoderとは、文脈を考慮した単語埋め込みをするものです。

文脈を考慮した単語埋め込みといえば、以前紹介したELMoがありましたね。

ただしAttentionを使うのみでは関連性の高い単語を割り出すことは出来ても、文脈を考慮することは出来ないです。どうやっているのかを確認していきましょう。

まずはEncoderの図を下に掲載します。

road-to-llm-advent-calendar-2023-17-01

処理には以下のものが使われています。

  1. 入力トークンの埋め込む
  2. 位置符号
  3. Multi-head Attention
  4. 加算&層正規化
  5. Feed Forward
  6. 残差結合

入力トークンを埋め込む

入力された文章をトークンにして埋め込みます。 Encoderにおけるトークンはサブワードの単位です。 サブワードについては、以前トークナイザーについてご紹介する時にご説明したものです。お忘れの方は以下のブログでぜひ確認しておいてください。

位置符号

トークンに分解して埋め込みをしただけでは、元の文の位置の情報がなくなります。したがって、文字の位置情報を追加情報として与えます。

なぜ単語の位置情報を与えないといけないかというと、「僕はご飯を食べる」と「ご飯は僕を食べる」が同じものとして処理されてしまうからです。全然違う意味であるのが分かるのは、単語の順番(位置)が異なるからです。

位置符号で位置の情報を与える時には、位置の情報を被らないように与えたいです。 以下の2つの数式によって、定義されています。

PE ( i , 2 k+1 ) = sin ( i 10000 2 k / D )

PE ( i , 2 k+2 ) = cos ( i 10000 2 k / D )

上記式はi番目の単語において、埋め込み表現時のk番目を計算する、というものです。

例えば、ある文における5番目の単語が[0.01,0.13, 0.002, 0.0103]のように埋め込みをしていたとすると、iには5が入り、kには順番にベクトルの次元数(値の集まりのことで、4つの数値からなるので4次元)の数値を入れます(1~4を入れていきます)。

本当にこれで位置が被らない情報を手に入れられるでしょうか。Pythonコードで確認してみましょう。

import matplotlib.pyplot as plt
import numpy as np

K = 50 # 単語列の最大の長さ
D = 65 # 埋め込みしたときのベクトルの次元数(何個の値からなるベクトルかを設定)

# 位置符号を格納する場所(変数)を初期化
pe = np.empty((K,D))

for i in range(K): # 単語位置 i で以下の処理をD÷2回分繰り返し(あまりは切り捨て)
  for k in range(D//2):
    theta = i / (100000**(2*k/D))
    pe[i, 2*k] = np.sin(theta)
    pe[i,2*k+1] = np.cos(theta)

# peの計算結果を画像で確認
plt.figure(figsize=(12,6))
plt.pcolormesh(pe, cmap='Pastel1')
plt.colorbar()
plt.xlabel('number of Dimensions')
plt.ylabel('Position')
plt.show()

road-to-llm-advent-calendar-2023-17-02

上記コードを実行すると、横軸が単語埋め込み後のベクトルの次元数(何個の数値を集めたベクトルなのか)と、縦軸がトークンが出てきた番号になります。

上のグラフは縦軸に沿って見ると、それぞれのトークンにどの色が割り振られているかを確認できます。特に横軸の数値が小さいところが分かりやすいのですが、確かに違う色が割り振られているのが分かりますね!

この位置符号を与えることで単語の位置が分かり、それとプラスしてAttentionで得られる情報から文脈を考慮した単語埋め込みにしています。

Multi-head Attention

Self-Attention型のMulti-head Attentionを使っています。

Self-Attention型のMulti-head Attentionと言われて「?」が浮かんだ方はぜひ前日公開のブログをご参照いただければと思います。

残差結合

residual connectionとも言われます。入力に使った値と、入力から得られた出力、それらを足し合わせたものを次の入力にします。

次の入力値 = 現在の入力値 + 現在の入力値から得られた出力値

どうして上記のようなことをするかというと、経験的に最終的な出力が安定すると知られているためです。ニューラルネットワークの中でも層が深いものに対して使われます。

加算&層正規化

加算というのは残差結合で足すことです。

層正規化というのは、数値の大きさを整えるものです。導入することで得られるメリットを2点書きます。

  • 非線形の表現力
    • 活性化関数についてご紹介した時にも非線形の表現力についてご紹介しましたが、活性化関数と合わせて層正規化でも非線形の表現力を保つという点があります。
    • 例として活性化関数のReLUは0より大きい値しか入力されない場合には非線形でなく線形の変換となってしまいます(入力された値をそのまま返すため)、層正規化を使うと入力される値が正と負の両方の値に散らばるため活性化関数の非線形な変換の効果を保てます
      • 例えば[1,2,3,4,5]は平均が3です。後ほどご紹介しますが、それぞれの値を平均である3で引くため[-2,-1,0,1,2]のように正と負の値を含むようになります。
  • 学習が高速化
    • 入力の大きさが偏ると大きい値が学習に使われ、小さい値は学習に使われない(無視される)という事態が発生します。その結果学習で良い結果が得られなくなり、学習がなかなか終わりません。したがって入力されたデータの大きさを整えることで学習が高速化します。

数式を確認します。xと書いているのがベクトル、Dと書いているのがベクトルの次元数です。

平均μ k = 1 D i = 1 D x i 標準偏差σ k = 1 D i = 1 D ( x i μ k ) 2 layer norm (k) = g k x k - μ k σ k + b k

layer norm(k)と書いているのが、層正規化の式です。 層正規化の式では、平均値と標準偏差を用いて計算をしています。平均値と標準偏差の中で使われているxは入力されたベクトルを表し、Dはベクトルの次元数です。

層正規化ではgと書かれているゲイン(gain)ベクトルと、bと書かれているバイアス(bias)ベクトルを使っています。

ゲインベクトルは入力された値の大きさを整える役割です。入力されているデータそれぞれに数値を掛け算して、大きさを整えます。

バイアスベクトルは出力する時の値の大きさを整える役割です。

値の大きさを整える理由はメリットについてご説明したReLUのような例の場合に重要です。また、値の大きさが大きい事が重要であるのでなく、入力されているデータで大小関係がどうなっているかが重要なので大きさを整えます。 例えば[100,200,3000]というものと比べて[1,2,30]というふうにしたって大小関係は分かりますよね。また、大きい値を入れると学習がそちらを重要視してしまうため、出力も偏った結果になってしまいますので値を小さくしています。

層正規化の式の意味するところは入力されるデータ(文の長さ)は一定でないため、入力されたデータの大きさを整えるという意味があります。大きさを一定に整えない場合、値の大きなものが入力されたものを学習してしまうと、それ以外の値の小さなものを学習しづらくなってしまう(学習が収束しづらくなる)という事態が発生します。そういった事態を避けるため導入されているものです。 (ちなみに程度の情報ですが、このLayer NormalizationはBatch Normalizationの発展系です。)

Feed Forward

正確にはPosition-wise Feed-Forward Neural Networkというものです。Multi-head Attentionでの出力をまとめるために使われています。

Position-wiseというのは、「位置ごとに」という意味で入力された単語ごとに適用するという意味です。

早速式を確認してみます。

F F N N ( x ) = ReLU ( 0 , x W 1 + b 1 ) W 2 + b 2

上記式では、活性化関数ReLUを適用しつつ、バイアスベクトルbを足すなどして整えています。Wは入力の値のうち、どれを重要視するのかを調整するのに掛け算をしています。

数式をイメージ化してみます。

road-to-llm-advent-calendar-2023-17-03

つまりは活性化関数を使って表現力を得ているものです!

もう少し詳しく知りたい方へ

Wは重みをかけています。論文中ではWの1は[512,2048]です。512の次元数から2048次元数へ表現できる幅を広げてReLUをかけて表現力を獲得し、Wの2で[2048, 512]もとの次元数のベクトルへ戻して機械学習モデルが出力できるようにしています。

終わりに

本日はTransformerモデルのEncoderについて学びました!Attentionだけでもかなり大きなボリュームになりましたが、Encoderについてもそこそこのボリュームになってしまいました。いかがでしたでしょうか。

明日はDecoderについてご説明いたします!AttentionとEncoderを理解した状態ならDecoderは本当に一瞬で終わります。ただし、Encoderと繋げる場合とDecoder単体で使用する場合においてDecoderの中身が異なりますので、そちらを説明したいと考えています。

本日はここまで。よければ明日もご覧ください!

参考文献

Transformerの論文です。

残差結合の論文です。(深層学習での良い学習のために残差結合を使っています。)

層正規化の論文です。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.