※本記事は、スタンフォード大学CS224N「NLP with Deep Learning」Spring 2024講義の第5回「Recurrent Neural Networks」から作成されています。
講義の詳細情報は https://web.stanford.edu/class/archiv... でご覧いただけます。本記事では講義の内容を要約しております。正確な情報や文脈については、オリジナルの講義をご視聴いただくことをお勧めいたします。
講師はChristopher Manning教授(Thomas M. Siebel機械学習教授、言語学・コンピュータサイエンス教授、スタンフォード人工知能研究所(SAIL)所長)です。スタンフォードのオンラインAIプログラムの詳細は https://stanford.io/ai をご参照ください。
1. イントロダクション
1.1. 講義の概要紹介
今日の講義では、まず最初に数分を使って、ニューラルネットワークのいくつかの新しい概念について話します。これには実際に課題2で出てくる概念も含まれています。その後、今日の講義の主要部分に移り、言語モデルとは何かを紹介します。言語モデルを紹介した後、言語モデルを構築する一つの方法である、新しいタイプのニューラルネットワーク、リカレントニューラルネットワーク(RNN)を紹介します。これらは知っておくべき重要なものであり、課題3でも使用します。ただし、言語モデルを構築する唯一の方法ではなく、おそらく多くの人がすでに知っているように、トランスフォーマーと呼ばれる別のタイプのニューラルネットワークもあります。リカレントニューラルネットワークについて説明した後、トランスフォーマーの話に進む前に、RNNの問題点についても少し話します。時間があれば、最後にRNNと言語モデルのまとめに入ります。
1.2. CS224Nの履修者統計データ
講義の内容に入る前に、CS224Nの履修者に関する統計データを少し紹介したいと思います。CS224Nの受講者構成は、CS106aで見せるような円グラフに似ていますが、大学院生の割合がより多いです。最も大きな4つのグループは、コンピュータサイエンス学部生、コンピュータサイエンス大学院生、専攻未宣言の学部生、そしてNDO(非学位取得)大学院生です。これはSCPD(Stanford Center for Professional Development)の学生の大部分を占めていますが、その中にはコンピュータサイエンス大学院生もいます。これらで聴衆の約60%を占めています。
残りの40%はその他の多様なグループです。例えば、明るいオレンジ色で示されているのは数学と物理学の博士課程の学生です。統計学の大学院生の数は、SISの学部生よりも多くなっています。以前のNLPクラスではこのような比率ではありませんでした。個人的に気に入っているのは、マゼンタ色の小さなグループである人文学部の学部生です。
学年別の内訳では、1年目の大学院生が最大のグループとなっています。また、3年生と4年生も非常に多く、少数の1年生もいます。「勇敢な1年生はここにいますか?」と聞くと笑いが起こりましたが、実際に何人かの1年生が出席していました。
1.3. 言語モデルの規模の歴史的進化
現代のニューラルネットワーク、特に言語モデルは非常に巨大です。このチャートは2022年までしか示していないので少し古いですが、実際のところ2024年の正確なチャートを作るのは難しいです。なぜなら、ここ数年で最大の言語モデル開発者たちは、一般的に自分たちの言語モデルがパラメータの観点でどれほど大きいかを言わなくなったからです。とはいえ、これらが明らかに巨大なモデルであることは確かで、1000億を超えるパラメータを持っています。
これらの大規模かつ深層(多くの層を持つ)ニューラルネットワークは、現代のNLPシステムの礎石となっています。私たちはすぐにこれらの深層モデルを見ていきますが、まずはより単純なものから始めて、少し歴史を振り返りたいと思います。
ニューラルネットワークが前回人気だったのは1980年代と1990年代で、その時にJeff Hintonと同僚たちによってバックプロパゲーションアルゴリズムが考案され、有名になりました。そのアルゴリズムによって隠れ層を持つニューラルネットワークのトレーニングが可能になりました。しかし、当時は基本的に隠れ層を持つニューラルネットワークはすべて単一の隠れ層でトレーニングされていました。入力層、隠れ層、出力層があるだけでした。その理由は、非常に長い間、複数の隠れ層でうまく機能させることができなかったからです。
この状況が変わり始めたのは、2006年頃からの「ディープラーニング」と呼ばれるニューラルネットワークの復活からです。Yoshua Benjoと同僚による「深層ニューラルネットワークの貪欲な層ごとのトレーニング」という影響力のある論文では、次のように述べられています:「しかし、最近まで、深層多層ニューラルネットワークをトレーニングすることは難しすぎると考えられていました。経験的に、深層ネットワークは一般的に1つか2つの隠れ層を持つニューラルネットワークより優れているわけではなく、しばしば劣っていることが分かっていました。」
つまり、理論的には深層ニューラルネットワークが有望に思えたにもかかわらず、実際には機能せず、約15年間完全に行き詰まっていたのです。2000年代後半から2010年代にかけて新たな発展があり、深層ニューラルネットワークを実際に機能させる方法が見つかりました。これらは浅いニューラルネットワークよりもはるかに優れた性能を発揮し、現在のネットワークへとつながっていきました。
これらのブレークスルーを見ると、「これだけ?難しい科学とは思えないな」と肩をすくめて失望する傾向があるかもしれません。ある意味ではそれは真実で、新しいアイデアや既存のものの微調整はわずかでした。しかし、それでもこれらの小さなアイデアや微調整が、15年間行き詰まり、ほとんどの人が見捨てていた分野を一変させました。突然、これらの深層ニューラルネットワークをトレーニングできるようになり、それ以前のものよりも驚くほど優れた機械学習システムとして機能するようになったのです。それには多くの時間がかかりました。
2. ニューラルネットワークの追加概念
2.1. 過去のニューラルネットワークの限界(深層学習以前)
ニューラルネットワークが前回人気を博したのは80年代と90年代で、その時期にJeff Hintonと同僚たちによってバックプロパゲーションアルゴリズムが広く知られるようになりました。私たちが先ほど見たバックプロパゲーションアルゴリズムにより、隠れ層を持つニューラルネットワークのトレーニングが可能になりました。しかし当時は、隠れ層を持つニューラルネットワークのほとんどすべてが単一の隠れ層でトレーニングされていました。入力層、隠れ層、出力層だけがあり、それ以上はありませんでした。
その理由は、非常に長い間、より多くの隠れ層を持つモデルをうまく機能させることができなかったからです。これが変わり始めたのは、「ディープラーニング」としてよく呼ばれるニューラルネットワークの復活が約2006年頃から始まってからでした。この時期に出された影響力のある論文の一つが、Yoshua Benjoと同僚による「ディープニューラルネットワークの貪欲な層単位トレーニング」です。
この論文の冒頭で彼らは次のように述べています:「しかし、最近まで、ディープマルチレイヤーニューラルネットワークをトレーニングすることは難しすぎると考えられていました。経験的に、ディープネットワークは一般的に1つか2つの隠れ層を持つニューラルネットワークより優れておらず、むしろ劣っていることが多いとわかっていました。」Jerry Turroという、ニューラルネットワークを使った自動運転の初期研究に携わった教員も言及されていますが、これは否定的な結果なので機械学習文献ではあまり報告されていないとのことです。
つまり、私たちはニューラルネットワークとバックプロパゲーション、そして今日話す予定のリカレントニューラルネットワークを持っていましたが、非常に長い期間、約15年ほど物事は完全に行き詰まっていました。理論的にはディープニューラルネットワークが有望に思えたにもかかわらず、実際にはうまく機能せず、今日私たちが持っているネットワークへとつながる方法を実際に見つけ出すには、2000年代後半と、より決定的には2010年代に起こった新たな発展が必要だったのです。
私たちはこのクラスとこれから先のクラスでこれらのことについて話し始めますが、ニューラルネットワークをより良く機能させるようにした要素を見ると、自然な反応としては肩をすくめて「これだけ?これは難しい科学とは思えない」と感じるかもしれません。ある意味ではそれは真実で、新しいアイデアや調整はわずかなものでした。しかし、それでもこれらのわずかなアイデアと調整によって、15年間行き詰まり、ほとんどの人が見捨てていた分野が一変し、これらの深層ニューラルネットワークをトレーニングする能力が突然現れました。それまでの手法を上回り、その間の時期を支配していた他の手法よりも驚くほど優れた機械学習システムとして機能するようになったのです。それには多くの時間がかかりました。
2.2. 正則化の概念と現代的理解
ニューラルネットワークをより良く機能させた要素の一つは、正則化の改良です。正則化とは、データを記述する損失を最小化するだけでなく、他の方法でもパラメータの学習を操作して、モデルをより良く機能させるという考え方です。通常、より複雑な損失関数を使って正則化を行います。
最も一般的な方法はL2損失と呼ばれるもので、最後にパラメータの二乗項を追加します。この正則化は「パラメータの重みが小さいモデルを見つけるのが良いので、データをうまく説明する最小のパラメータ重みを見つけるべきだ」と言っています。正則化については多くのことが言えますが、他のクラス(CS229機械学習など)でより詳しく議論されるので、ここではあまり詳しく説明しません。
しかし、最近のニューラルネットワーク研究に非常に関連する注意点を一つ挙げておきたいと思います。正則化の古典的な見方では、これはオーバーフィッティングを防ぐために必要だと考えられていました。オーバーフィッティングとは、トレーニングデータに対しては非常に良い性能を示すが、新しいデータに対する一般化が悪くなることを意味します。
示されていた図は次のようなものでした:トレーニングデータでトレーニングすると、誤差は必然的に減少します。しかし、ある時点から、トレーニング例に特有の性質を学び始め、トレーニング例だけに当てはまることを学習することになり、テスト時に異なるデータには一般化しません。そのため、別のバリデーションセットや最終テストセットでの誤差や損失を追跡すると、ある時点から再び上昇し始めます。これがオーバーフィッティングであり、パラメータを数値的に小さくすることで、トレーニングデータへのオーバーフィッティングの程度を軽減することを目的としています。
しかし、これは現代のニューラルネットワーク研究者が全く信じていない図です。代わりに、図は次のように変わりました:もはやオーバーフィッティングは存在しないと考えられていますが、異なるデータへの一般化が重要です。
古典的な統計学では、現在の大規模ニューラルネットワークのように数十億のパラメータをトレーニングするという考えは、それらのパラメータを適切に推定できないため、馬鹿げているとみなされるでしょう。しかし、実際に分かったのは、確かに数値を正確に推定することはできないが、これらの膨大な数字からある種の興味深い平均化関数が得られるということです。正しく行えば、しばらくトレーニングを続けるとオーバーフィッティングが始まるように見えるかもしれませんが、巨大なネットワークでトレーニングを続けると、トレーニング損失はごくわずかに減少し続けるだけでなく、バリデーション損失も減少します。
現在の巨大なネットワークでは、トレーニングデータにほぼ完全にオーバーフィットするようにモデルをトレーニングします。巨大なネットワークをトレーニングセットでトレーニングすると、本質的にゼロ損失(おそらく0.007損失など)にまでトレーニングできます。非常に豊かなモデルを持っているため、トレーニングセット全体を完璧に適合・記憶できるのです。
古典的には、トレーニングデータにオーバーフィットしたことで災害とみなされていたでしょう。しかし現代の大規模ニューラルネットワークでは、正則化が適切に行われていれば、モデルは異なるデータにも良く一般化するため、災害とは見なされません。ただし、その反面、通常このようなL2正則化やL1正則化などの類似の手法は、その効果を達成するのに十分な強力な正則化ではなく、ニューラルネットワーク研究者は他の正則化手法に目を向けています。その中で最も人気があるのはドロップアウトです。
2.3. ドロップアウト正則化
ドロップアウトは課題にも含まれているものの一つで、この時点で謝罪しておくべきかもしれません。ここで紹介するドロップアウトの実装方法は元々の定式化ですが、課題で提示されているものは現在ディープラーニングパッケージで一般的に行われている方法です。いくつかの細かい違いがありますが、ここでは主なアイデアを紹介し、数学の詳細についてはあまり心配しないことにします。
ドロップアウトのアイデアは、訓練時に例を使って訓練するたびに、ニューラルネットワークの中間層の中で一部の入力を単に捨ててしまうというものです。技術的には、毎回サンプリングするゼロと1のランダムマスクを用意し、それとデータをアダマール積(要素ごとの積)することで、一部のデータ項目をゼロにします。そして毎回異なるマスクを使用するので、次回は別の部分をマスクアウトします。
この効果は、モデルに対して堅牢であること、うまく機能すること、そしてあらゆる入力を最大限に活用することを学習させることです。例えば、ベクトルの第17成分に極度に依存することはできません。なぜなら時々それがランダムに消えてしまうからです。もし他に次に何をすべきかを判断するのに役立つ特徴があれば、それらの特徴も活用する方法を知っておくべきです。
つまり、訓練時にはランダムに要素を削除し、テスト時には効率と回答の質のために何も削除せず、すべての重みを保持しますが、以前要素を削除していた事実を補うために単にスケールを調整します。
これを説明する方法はいくつかあります。よく挙げられる動機の一つは、特徴の共適応を防ぐというものです。モデルが特徴7、8、11の複雑な関数を学習して予測するのではなく、一部の特徴が欠けることがあるため、より柔軟な方法で物事を利用する必要があることを知ります。
別の考え方として、異なるモデルを混合してより良い結果を得るモデルアンサンブルの研究がたくさんあります。ドロップアウトでトレーニングする場合、特徴の可能なドロップアウトのべき集合、つまり指数関数的な数のすべての可能なドロップアウトのアンサンブルで一度にトレーニングしているようなものです。これが非常に良いモデルを提供します。
考え方は様々ですが、ナイーブベイズと線形回帰モデルを以前に見たことがあれば、その間の中間地点を提供すると考えるのが良いかもしれません。なぜなら、ナイーブベイズモデルでは他の特徴の存在に関係なく、データ統計に基づいて各特徴を独立に重み付けします。線形回帰では、重みは他のすべての特徴のコンテキストで設定されます。ドロップアウトでは、その中間にあり、一部の他の特徴のコンテキストで重みを見ますが、異なる時点で異なる特徴が消えます。
スタンフォードのStefan Varerなどによる研究に続いて、一般的に現在の深層学習研究者はドロップアウトを特徴依存の正則化の一形態と考えており、彼はそのように考える理論的な結果をいくつか示しています。
2.4. パラメータの初期化の重要性
パラメータ初期化は明白でないかもしれませんが、ニューラルネットワークのトレーニングを開始する際、ほとんどの場合、行列のパラメータをいくつかのランダムな数値で初期化することが不可欠です。その理由は、行列をすべてゼロや他の定数から開始すると、通常は対称性が存在するからです。
この図のサドルポイントからスタートするような状況を考えてみましょう。左右や前後に対称的で、どちらに進むべきか分からず、一か所に留まってしまう可能性があります。一般的には、行列内のすべての要素に対して行う操作は同じようなものなので、すべての要素が同じ初期値を持っていると、多くの特徴を持つというよりも、一つの特徴の多くのコピーを持っているようなものになってしまいます。
学習を初期化し、うまく機能させるためには、ほとんどの場合、すべての重みを非常に小さなランダムな数値に設定したいと考えます。ここで「非常に小さい」とは、それらをより小さくしてもゼロに消えないような範囲、かつ他の値と掛け合わせたときに巨大な数値に膨れ上がらないような範囲で設定したいということです。
この適切なスケールでの初期化は、以前は非常に重要なことと見なされており、行列の乗算を行った後に何が起こるかを考慮した特定の方法が開発され、よく使用されていました。その一つがXavier初期化で、層の入力と出力の数に基づいて一様分布の分散を決定するようなものでした。
課題2ではまだこれを使って初期化していますが、後になると、レイヤー正規化などの巧妙な方法が登場し、初期化に非常に注意を払う必要性がなくなります。しかし、何らかの形で初期化することは依然として必要です。
2.5. 最適化アルゴリズム(Adam等)
最後に、第二の課題にも登場するものについて少し説明したいのは、オプティマイザーです。授業では確率的勾配降下法について説明し、そのための基本的な方程式を提示しました。第一近似では確率的勾配降下法に問題はなく、十分に調整すれば、ほとんどどんな問題に対しても確率的勾配降下法をうまく機能させることができます。
しかし、うまく機能させるには、物事のスケールを適切に設定することに大きく依存しています。適切なステップサイズを持つこと、そして多くの場合、減少するステップサイズを持つ学習率スケジュールやその他の複雑さを持つ必要があります。
そのため、人々はニューラルネットワークのためのより洗練されたオプティマイザーを開発してきました。複雑なネットワークでは、これらが良い学習を得るために必要に見えることもあります。少なくとも、異なるハイパーパラメータを正しく設定することにそれほど依存しないため、安全性のマージンをたくさん提供します。
私が言及したすべての方法と最も一般的に使用される方法のアイデアは、各パラメータに対して過去の勾配の測定値を蓄積し、特定のパラメータに対する勾配の規模、つまり傾きのアイデアを持ち、それを使って各時間ステップでの学習率の移動量を決定するというものです。
開発された最も単純な方法の一つはAdagradと呼ばれ、John Duchiなどが共同発明者でした。これはシンプルで優れていますが、早期に停滞する傾向があります。その後、さまざまな方法が考案され、課題2で使用されているAdamは、非常に安全なスタート地点です。
しかし、ある意味では、単語ベクトルは特別な性質を持っています。それは疎性のためで、特定の単語は時々しか出現しないため、非常に疎にしか更新されません。そのため、単語ベクトルのような特別な性質を持つものに対して、特別なオプティマイザーが開発されており、末尾にWがついているものはしばしば試す価値があります。
さらに、オプティマイザーを改善するための様々なアイデアがあり、もっと学びたい場合は、凸最適化のような最適化クラスを受講することができます。運動量やネステロフ加速などのアイデアがあり、人々はこれらも様々に試しています。
他に何も覚えていなくても、Adamは覚えておくべき良い名前です。
2.6. ベクトル化の重要性
私たちは以前これについて暗黙的に見てきましたが、ベクトル化とはfor文を使わず、常にベクトル、行列、テンソルを使うという考え方です。ディープラーニングの成功とスピードは、ベクトル、行列、テンソルで物事を行えるという事実から生まれています。
例えば、for文を書いている場合、特にPythonでは、処理が非常に遅くなります。ベクトルと行列を使って処理を行えば、CPUでも少なくとも一桁速くなります。そして、ディープラーニングでみんなが本当に望んでいるのは、GPUや時には神経処理ユニット(NPU)で処理を実行することで、その場合は2〜3桁の高速化が得られます。
したがって、常に「ベクトルと行列で物事を行うべきだ」と考えてください。入力処理の非常に表面的な部分以外のもののためにfor文を書いている場合、ほぼ確実に間違いを犯しています。ベクトルと行列で物事をどのように行うかを考えるべきです。
例えば、ドロップアウトのようなことを行う場合、すべての位置を通過して一部をゼロに設定するようなfor文を書きたくありません。マスクを使ったベクトル操作を使用したいと思います。
3. 言語モデリング
3.1. 言語モデルの定義と技術的意味
言語モデルについて説明していきます。「言語モデル」は単に二つの英単語ですが、NLPでは特定の意味を持つ専門用語として使用されています。
言語モデルのアイデアは、次にどの単語が来るかをうまく予測できるもの、より正確には次に来る単語に対して確率分布を与えるものです。例えば、「The students open their...」(学生たちは彼らの...を開ける)という文があったとき、次に来そうな単語は何でしょうか?「bags」(バッグ)、「laptops」(ラップトップ)、「notebooks」(ノートブック)などが考えられます。これらの可能性のある単語に確率を割り当てたものが言語モデルになります。
形式的には、先行する項目のコンテキストを持ち、次の項目に対する確率分布を付けます。これは語彙内の項目の推定値の合計が1になることを意味します。このように次の単語の確率を予測するPを定義したものを言語モデルと呼びます。
言語モデルを考える別の方法として、言語モデルはテキストの断片に確率を割り当てるシステムだと考えることもできます。任意のテキストに確率を与えることができます。その理由は、連鎖律を使用できるからです。任意のテキストの確率を知りたい場合、先ほどの言語モデルの定義を使えば簡単です。X1の確率(先行コンテキストがない状態)に、X1が与えられた時のX2の確率を掛け、以下同様に計算していくことができます。この連鎖分解の各項は、前に定義した言語モデルがまさに提供するものです。
言語モデルはNLPにとって不可欠な技術です。最も単純なものから複雑なものまで、人間の言語とコンピュータに関わるほぼすべてのところで言語モデルが使用されています。特に、これらはチャットGPTと共に2022年に発明されたものではなく、言語モデルは少なくとも80年代からNLPの中心的存在でした。そのアイデア自体は少なくとも50年代にまで遡ります。
例えば、あなたがスマートフォンで入力している時に次の単語の提案が表示されるとき、それがあなたの好みかどうかに関わらず、それらの提案は言語モデルによって生成されています。非常に伝統的で、あまり高性能ではないコンパクトな言語モデルがキーボードアプリケーションで使われており、少ないメモリで迅速に実行できるようになっています。Googleで何かを入力し始めるとクエリを完成させるための提案がされますが、それも言語モデルによって生成されています。
3.2. 言語モデルの応用例
言語モデルはNLPにとって不可欠な技術です。単純なものから複雑なものまで、人間の言語とコンピュータが関わるほぼすべての場面で、言語モデルが使用されています。特に注目すべきは、これらはチャットGPTと共に2022年に発明されたわけではなく、言語モデルは少なくとも1980年代からNLPの中心的な存在でした。そのアイデア自体は少なくとも1950年代にまで遡ります。
例えば、あなたがスマートフォンで入力しているときに次の単語の提案が表示されるとき、それがあなたの好みかどうかに関わらず、それらの提案は言語モデルによって生成されています。これは非常に伝統的で、あまり高性能ではないコンパクトな言語モデルで、キーボードアプリケーションで少ないメモリと迅速な実行が可能なように設計されています。
また、Googleで何かを入力し始めると、クエリを完成させるための提案が表示されますが、それも言語モデルによって生成されています。このように、言語モデルは私たちが日常的に使用する多くのテクノロジーの基礎となっています。
3.3. n-gram言語モデル
言語モデルを構築する方法を見ていきましょう。ニューラル言語モデルに入る前に、言語モデリングの古い時代について少し説明したいと思います。これは実質的に1975年から2012年頃までの間、言語モデルが構築された方法です。
我々はこれらの単語の並びに確率を与えたいと考えています。そのために「n-gram言語モデル」を構築します。これは短い単語の部分列を見て、それを使って予測するという意味です。ここでのnは、予測に使用する単語列の長さを表す変数です。
単語の個別の確率だけを見る場合、それは「ユニグラム言語モデル」となります。単語のペアの確率を見る場合は「バイグラム言語モデル」、三つの単語の確率は「トライグラム言語モデル」となります。三つ以上の単語の確率については、「4-gram言語モデル」「5-gram言語モデル」「6-gram言語モデル」などと呼ばれます。
古典教育を受けた人にとっては、これは恐ろしいことです。特にこれらは正しくありません。「gram」はギリシャ語の語根なので、本当はギリシャ語の数字を前に付けるべきです。「モノグラム」や「ダイグラム」などとすべきです。実際、n-gramモデルのアイデアを導入した最初の人、情報理論を考案したClaude Shannonは、1951年の論文で「ダイグラム」という用語を使っていました。しかし、そのアイデアはそこで消え、他の全ての人は実際にはこれらの用語を使用しています。これは実用的な表記法として良いと思います。
これらのモデルを構築するためのアイデアは、テキスト中でさまざまなn-gramがどれくらいの頻度で現れるかを数え、それらを使って確率推定を構築するというものです。特に、マルコフ仮定を立てます。つまり、長いコンテキストに基づいて次の単語を予測する場合、その全てを使うのではなく、最も最近のn-1個の単語だけを使います。
従って、大きなコンテキストがあっても、そのほとんどを捨て、単語X_t+1を予測する際に単に直前のn-1個の単語に基づいて予測します。例えばnが3の場合、分子にトライグラム、分母にバイグラムを持つことになり、それによって異なる続きの相対頻度を得ます。
大量のテキストにおけるn-gramの出現回数を単純に数え、それらの数で割ることで、異なる続きの相対頻度推定を得ることができます。これで理解できますか?それがこれを行う方法です。
例えば、4-gram言語モデルを学習しているとしましょう。「As the proctor started the clock, the students open their...」というテキストがあるとします。推定を行うために、直前の3単語以外はすべて捨てます。つまり「students open their」に基づいて推定します。
そして、「students open their W」の出現回数と「students open their」の出現回数を調べることで確率を計算します。例えば、コーパス内で「students open their」が1000回出現し、「students open their books」が400回出現したとすると、「books」の確率推定は単純に0.4となります。「exams」が100回出現した場合、その確率推定は0.1となります。
これが悪いというわけではありません。単純な方法で次の単語を予測しようとすると、直前の単語を見るのが最も役立つ方法ですが、明らかに原始的です。なぜなら、もし「As the proctor started the clock」という先行テキストを知っていれば、次の単語は「exams」である可能性が高いように思えますが、「students open their」だけに基づいて推定していると、「books」の方が一般的なのでそちらを選ぶ可能性が高くなるからです。
ある意味では粗い推定ですが、開始するには十分な場所です。他の方法でも問題が生じる可能性があります。例えば、なぜこの確率推定を使うと問題が発生するのでしょうか?
最初の問題は、非常に多くのn-gramが存在することです。さらに、どんな妥当なサイズのコーパスを数えても、見たことのない単語がたくさんあるでしょう。例えば「students open their」の後に来る可能性のある単語はたくさんあります。「students open their accounts」や、生物学の解剖実習をしている学生なら「students open their frogs」かもしれません。
つまり、特定のコンテキストでは実際に可能な単語が多くあり、そのうちの多くは見たことがないでしょう。そうすると確率推定はゼロになります。これは確率を扱う上で特に悪いことです。確率推定がゼロになると、その計算に関わるすべての計算が即座にゼロになるからです。
このような疎性の問題に対処するために、カウントを少し調整して非ゼロにする方法が使われました。様々な方法が探求されましたが、最も簡単な方法は、カウントに小さなデルタ(例えば0.25)を追加することです。これにより、一度も見なかったものは0.25のカウントになり、一度見たものは1.25のカウントになり、ゼロはなくなり、すべてが可能になります。
第二の問題として、「students open their」という表現自体を一度も見たことがない場合、分母が未定義となり、分子にもカウントがありません。この場合、標準的な方法は「バックオフ」を使用することでした。「students open their」の後に来る単語の推定ができない場合、「open their」の後に来る単語の推定を計算し、それもできなければ「their」の後に来る単語の推定を使用します。つまり、推定に使用できるようになるまで、コンテキストを少なくしていきます。
しかし、これには相反する圧力があります。一方では、より良い推定のためにより多くのコンテキストを使いたい(より大きなn-gramを使用したい)と思いますが、他方では、コンテキストの単語を増やすと、誰かが言及したように保存サイズの問題が悪化します。コンテキストのサイズに応じてn-gramの数が指数関数的に増加するからです。また、疎性の問題もますます悪化し、ほぼ必然的にゼロに遭遇することになります。
そのため、実践的には最大で5-gramまで、時に6-gramや7-gramを使用することもありましたが、ほとんどの場合、疎性と保存コストの問題から5-gramが限界でした。例えば、2000年代にGoogleがリリースした有名なリソース「Google n-grams」は、1兆語のウェブコーパスで構築され、n-gramのカウントを提供していましたが、それはnが5までのものでした。これが彼らが止めた場所です。
保存の問題についてもう少し言及しましたが、保存の問題とは、これらのカウントを保存するためのスペースが必要であり、カウントの数はコンテキストサイズに応じて指数関数的に増加するということです。
しかし、n-gram言語モデルの良い点は、非常に構築しやすいことです。週末に少し楽しみたいときに、自分で作ることもできます。必要なのは、n-gramのカウントを保存し始め、それを使って物事を予測することだけです。数百万語程度の小さなコーパスでこれを行う場合、ラップトップでモデルを構築するのは数秒で済みます。ソフトウェアを書く必要はありますが、数分でソフトウェアを書き、モデルの構築は数秒で済みます。ニューラルネットワークをトレーニングする必要はなく、n-gramがどれくらい頻繁に出現するかを数えるだけです。
それが完了したら、n-gram言語モデルを使ってテキストを生成することもできます。チャットGPTの前にもテキスト生成はできたのです。トライグラム言語モデルを持っていれば、「today the」という単語から始めて、保存されたn-gramを調べ、次の単語の確率分布を取得できます。
ここではその確率分布が示されています。これらの確率のパターンが強いことに注目してください。これらはカウントから派生した確率なので、実際にはこれらは1回出現した単語、2回出現した単語、4回出現した単語などを表しています。より注意深く見ると、ある意味で粗いものですが、この時点でサイコロを振り、0から1までのランダムな数を生成し、この分布からサンプリングすることができます。
例えば、0.35のような乱数を生成したとします。上から下に行くと、「price」という単語を選ぶことになります。「today the price」となり、その後繰り返します。それに基づいて条件付けし、次の単語の確率分布を得て、乱数を生成し、分布からサンプリングします。例えば2を生成し、「of」を選びます。次に条件付けし、確率分布を得て、0.5のような乱数を生成し、「gold」が出てきます。「today the price of gold」となり、これを続けてテキストを生成できます。
ここに、トライグラム言語モデルを使って200万語のトレーニングデータから生成されたテキストがあります:「today the price of gold per ton while production of shoe lasts and shoe industry the bank intervened just after it considered and rejected an IMF demand to rebuild depleted European stocks September 3rd in primary 76 cents a share」
このテキストは素晴らしいものではありませんが、今日は皆さんに前向きな気持ちでいてほしいので、実際にはそれほど悪くありません。驚くほど文法的です。特に、すべて小文字にしていますが、IMF(国際通貨基金)は大文字にすべきでした。「the bank intervened just after it considered and rejected an IMF demand」のような大きな部分は、テキストとしてかなり意味をなしています。
つまり、ほとんど文法的で、英語のテキストのように見えますが、意味がありません。非常に一貫性がないので、改善の余地はありますが、これらの単純なn-gramモデルでも、非常に低いレベルから、テキストと人間の言語がどのように機能するかを下から近づけることができることがわかります。
n-gramモデルの質を簡単に向上させることもできます。200万語のテキストではなく、1000万語のテキストでトレーニングすればより良くなるでしょう。そしてトライグラムモデルではなく4-gramモデルを使えば、さらに良くなります。より良いテキスト近似を得ることができ、これが基本的に人々が2012年頃まで行っていたことです。
2010年代初頭のn-gram言語モデルに関する話も、今日のスケールが全てを解決するという話と全く同じでした。1000万語のテキストとトライグラム言語モデルで十分な結果が得られなければ、1億語のテキストと4-gram言語モデルを使えば良くなり、1兆語のテキストと5-gramモデルを使えばさらに良くなるだろう、という具合です。10兆語のテキストを集めてさらに良いn-gramモデルを訓練できたら素晴らしいと思われていました。同じ戦略です。
しかし、単にスケールだけでなく、より良いモデルでも改善できることがわかりました。そして、ニューラル言語モデルの構築で物事が再発明され、再開されました。
3.4. n-gramモデルの制限
n-gramモデルには重要な限界があります。まず、保存の問題があります。このモデルを構築するためには、これらのカウントを保存する必要があり、保存するカウントの数はコンテキストサイズに応じて指数関数的に増加します。
さらに相反する圧力があります。一方では、より良い推定を得るためにより多くのコンテキストを使いたい(より大きなn-gramを使用したい)のですが、コンテキストの単語を増やせば増やすほど、保存サイズの問題が悪化します。また、疎性の問題もますます深刻になり、ほぼ必然的にゼロのカウントに遭遇することになります。
そのため、実践においてはn-gramモデルの上限は5程度で、時に6-gramや7-gramを使用することもありましたが、ほとんどの場合、疎性と保存コストの問題から5-gramが限界でした。例えば、2000年代にGoogleがリリースした「Google n-grams」という有名なリソースは、1兆語のウェブコーパスで構築され、n-gramのカウントを提供していましたが、それはnが5までのものでした。
マルコフ仮定による文脈の制限も大きな問題です。先行文脈のほとんどを捨てて直近のn-1語だけを使用するため、より広い文脈から得られる情報を活用できません。これにより、長距離の依存関係を持つ言語現象を適切にモデル化することができません。
また、n-gramモデルはデータに強く依存し、未見の組み合わせに対しては良い予測ができません。バックオフやスムージングなどの技術で対応しようとしますが、根本的な問題は解決できていません。
3.5. n-gramモデルによるテキスト生成例
n-gram言語モデルを構築したら、それを使用してテキストを生成することもできます。チャットGPT以前にもテキスト生成は可能だったのです。トライグラム言語モデルを持っていれば、「today the」というフレーズから始めて、保存されたn-gramを調べ、次の単語の確率分布を得ることができます。
この確率分布を見ると、強いパターンがあることに注目してください。これらは実際にはカウントから派生した確率であるため、一度出現した単語、二度出現した単語、四度出現した単語などに対応しています。詳しく見ると少し粗いですが、この時点でサイコロを振り、0から1までのランダムな数値を生成して、この分布からサンプリングすることができます。
例えば、0.35のような乱数を生成したとすると、上から下に見ていくと「price」という単語をサンプリングすることになります。これで「today the price」となり、次にこれを条件として繰り返します。次の単語の確率分布を得て、再び乱数を生成し、その分布からサンプリングします。例えば2を生成して「of」を選びます。これを条件として確率分布を得て、0.5のような乱数を生成し、「gold」が出てきます。「today the price of gold」となり、このプロセスを続けることでテキストを生成できるのです。
以下は、200万語のトレーニングデータを使用したトライグラムモデルで生成されたテキストの例です:
「today the price of gold per ton while production of shoe lasts and shoe industry the bank intervened just after it considered and rejected an IMF demand to rebuild depleted European stocks September 3rd in primary 76 cents a share」
このテキストは完璧ではありませんが、実際にはかなり良いところもあります。驚くほど文法的であり、特に「the bank intervened just after it considered and rejected an IMF demand」のような部分は、十分に意味のある英語のテキストになっています。(ちなみに、IMFは国際通貨基金の略で、本来は大文字表記すべきです)
テキストは大部分が文法的で英語のように見えますが、全体として意味がありません。一貫性に欠けるため改善の余地はありますが、このような単純なn-gramモデルでも、テキストと人間の言語がどのように機能するかを下から近似できることがわかります。
より良い結果を得るために、200万語ではなく1000万語のテキストでトレーニングすれば良くなり、トライグラムモデルの代わりに4-gramモデルを使えばさらに良くなるでしょう。スケールを増やしていくことで、より良いテキスト近似が得られるというのが、2012年頃までのアプローチでした。
4. ニューラル言語モデル
4.1. 固定ウィンドウニューラル言語モデル
ニューラル言語モデルはどのように構築できるでしょうか。私たちは同じタスク、つまり単語の列があり、次に来る単語に確率推定を付けるというタスクを持っています。これを行う最も単純な方法は、前のクラスで行ったことと関連付けることでしょう。
私たちはすでに、いくつかの単語ベクトルを連結することでコンテキストを表現し、それをニューラルネットワークに入力し、何かを予測するという考え方を持っていました。過去のクラスで行った例では、中心語が場所であるかどうかという二項選択を予測するために使用しました。しかし、これはニューラルネットワークで予測できる唯一のものではありません。
他にも様々なことを予測できます。例えば、テキストが肯定的か否定的かを予測したり、英語で書かれているか日本語で書かれているかを予測したりすることができます。そして、予測の選択肢の一つとして、このテキストの窓の後に来る次の単語を予測することもできます。
これにより、基本的な構造は以前と同じで、上部で二項分類を行う代わりに、テキストに次に現れる単語が何であるかという多項分類を行うモデルを得ることができます。これにより、特に固定ウィンドウニューラル言語モデルが得られます。つまり、さらに遡るコンテキストを捨てるという同じマルコフ仮定のトリックを使用します。
固定ウィンドウモデルでは、連結できる単語埋め込みを使用し、それを隠れ層に通し、その隠れ層の出力を取り、別の層で乗算し、それをソフトマックスに通して出力分布を得ます。これにより固定ウィンドウニューラル言語モデルが得られ、多くのクラスにわたる分類を行うこと以外は、先週やったことと全く同じです。そのため、これは馴染みがあるはずです。また、課題2で行っていることとも非常に似ています。
これは基本的に最初に提案されたニューラル言語モデルの種類です。特に、Yoshua Benjoが21世紀の初めに、n-gram言語モデルの代わりに固定ウィンドウニューラル言語モデルを使用できると提案しました。彼と同僚は当時からこのモデルでいくつかの良い結果を得ることができましたが、その時点では広く注目されず、あまり普及しませんでした。
その理由は複合的です。固定ウィンドウだけでは、ある意味でn-gramとそれほど違わず、ニューラルネットワークはより良い一般化を提供できると主張できましたが、実際には、GPUなしでニューラルネットワークを実行するのは依然として難しく、スケールの物語を追求し、数千億語のテキストでn-gramカウントを収集する方がより効果的だと考えられていました。そのため、当時はあまり普及しませんでした。
しかし、原則的には良いことのように思われました。疎性の問題を解消し、保存コストを削減しました。もはや観測されたすべてのn-gramを保存する必要はなく、ニューラルネットワークのパラメータだけを保存すれば良いのです。しかし、すべての問題が解決されたわけではありません。特に、マルコフ仮定の問題、つまり予測に小さな固定コンテキストしか使用しないという問題は残っており、そのウィンドウを拡大することにはいくつかの欠点があります。十分に大きな固定ウィンドウは決して存在しません。
4.2. Bengio(2000年代初頭)の先駆的研究
最初のニューラル言語モデルは、21世紀初頭にYoshua Benjoによって提案されました。彼はn-gram言語モデルの代わりに固定ウィンドウニューラル言語モデルを使用できると提案しました。これは当時の画期的なアイデアでした。彼と同僚たちはこのモデルから肯定的な結果をいくつか得ることができました。
このアプローチは、単語の分散表現(単語埋め込み)を使用して、単語間の意味的な類似性を捉えることができました。これにより、従来のn-gramモデルの主要な問題の一つである疎性の問題に対処できました。例えば、「students open their books」というフレーズを訓練データで見たことがあるなら、「pupils open their textbooks」のような意味的に類似したフレーズについても、単語埋め込みの類似性を通じて確率を推定できます。
しかし、当時はこのアプローチが広く注目されることはなく、あまり普及しませんでした。その理由はいくつかあります。固定ウィンドウだけを使用する場合、ある意味ではn-gramと大きく違わなかったこと、そしてニューラルネットワークはより良い一般化を提供できるとしても、GPUなしでニューラルネットワークを実行するのは依然として計算コストが高かったことが挙げられます。
当時の多くの研究者は、ニューラルアプローチよりも、単に規模を拡大して数千億語のテキストでn-gramカウントを収集する方がより効果的だと考えていました。したがって、数億語のテキストで訓練したニューラルモデルよりも、数千億語のテキストで訓練したn-gramモデルの方が、実際に良い結果を出せると考えられていました。
それでも、Bengioの研究は後のニューラル言語モデルの発展に重要な基礎を築きました。彼のアプローチは疎性の問題を解消し、保存コストを削減するという利点がありました。もはや観測されたすべてのn-gramを保存する必要はなく、ニューラルネットワークのパラメータだけを保存すれば良くなりました。これは後のディープラーニング革命において非常に重要な進歩となりました。
4.3. 固定ウィンドウモデルの制限
固定ウィンドウニューラル言語モデルを技術的に見ると、いくつかの懸念点が浮かび上がります。もっとも明らかな問題は、依然としてマルコフ仮定を使用しているという点です。つまり、予測に使用するのは先行する小さな固定コンテキストだけであり、より古いコンテキストは捨ててしまいます。どんなに大きな固定ウィンドウを設定しても、十分に大きなウィンドウは決して存在しません。
もう一つの問題は、異なる位置にある単語が、この行列Wの完全に異なる部分によって処理されるという点です。例えば、「books」が次に来ることを予測するために、「student」という単語が重要だとしても、その単語がどの位置に出現するかは、予測にとってそれほど重要ではないはずです。
例えば、コンテキストが「the students slowly open their」のような少し異なる言語構造であっても、同じ「students」が存在しています。しかし、この行列Wは、ここでの「student」とこの位置での「student」について学習するために、完全に別々のパラメータを使用することになります。これは非効率で不適切に思えます。
これは、別のタイプのニューラルアーキテクチャが必要であることを示唆しています。そのアーキテクチャは、任意の長さの入力を処理でき、「student」という単語を見たことが、それが出現する位置に関係なく、「books」「exams」「homework」などの単語が出現する証拠になると言うために、同じパラメータを使用できるものです。
このような制限から、より柔軟で効果的なリカレントニューラルネットワークというアーキテクチャの探求につながりました。これが次に説明するトピックです。
5. リカレントニューラルネットワーク(RNN)
5.1. RNNの基本構造と計算方法
リカレントニューラルネットワーク(RNN)は異なるファミリーのニューラルネットワークです。このクラスでは実質的にいくつかのニューラルネットワークアーキテクチャを見ていきます。最初に見たアーキテクチャはWord2Vecで、これは非常に単純なエンコーダ・デコーダアーキテクチャです。2番目のファミリーはフィードフォワードネットワークまたは全結合層の古典的なニューラルネットワークでした。そして3番目のファミリーがこれから見るリカレントニューラルネットワークで、これにはいくつかの種類があります。その後、トランスフォーマーモデルに進みます。
リカレントニューラルネットワークのアイデアは、時間の連続する瞬間またはテキスト内の連続する位置に適用される一組の重みを持ち、進むにつれてパラメータを更新していくというものです。これを詳しく説明していきますが、基本的なアイデアはこうです。
「the students open their」という単語列があり、それを使って予測するとします。ここでの方法は—例では4つの単語しかありませんが、リカレントニューラルネットワークは任意の長さのコンテキストを扱えるため、24個の単語があっても問題ありません。
以前と同様に、単語は最初は単なる単語または1-hotベクトルであり、前と同じように単語埋め込みを検索することができます。しかし、次の単語の確率を計算するために、今度は異なることを行います。
隠れ層はリカレントになります。リカレントとは、テキストを左から右へと進むにつれて、各時間ステップで隠れ状態を変更するという意味です。h0という初期隠れ状態から始めます(これは実際にはすべてゼロでも構いません)。そして各時間ステップで、前の隠れ状態を重み行列で乗算し、単語埋め込みを別の重み行列で乗算し、それらの結果を合計します。これによって新しい隠れ状態が得られます。この隠れ状態は、これまでに見られたすべてのものの記憶を格納します。
このプロセスを続けていきます。次の単語ベクトルを同じ重み行列で乗算し、前の隠れ状態を同じ重み行列Whで乗算し、それらを加え合わせて新しい表現を得ます。
ここでは一部だけ説明しましたが、通常はさらに2つのことを行います。バイアス項を追加することと、非線形関数を適用することです。リカレントニューラルネットワークの場合、この非線形関数は通常はtanh関数で、正と負の側でバランスが取れています。
各ステップでこれを繰り返していきます。このh4の隠れ状態は、これまでのテキストを読み込んだ状態であり、「the students open their」をすべて見てきました。どの位置に「students」という単語が出現しても、それは同じ重み行列Weで乗算され、隠れ状態に追加されています。情報を取り込む、よりクリーンで少ないパラメータの方法が得られるのです。
次に、次の単語を予測します。最終的な隠れ状態に基づいて、前に行ったのと同様のことを行います。その隠れ状態に行列を乗算し、別のバイアスを追加し、それをソフトマックスに通します。ソフトマックスはすべての次の単語に対する言語モデルの確率を与え、それからサンプリングして次の単語を生成することができます。理解できましたか?
RNNでは、任意の長さの先行コンテキストを処理でき、より多くの情報を隠れ状態に入れることができます。計算は多くのステップ前からの情報を使用しています。長いコンテキストを持つからといってモデルサイズが増加するわけではありません。長いコンテキストに対してより多くの計算を行う必要がありますが、そのコンテキストの表現は常に固定サイズの隠れベクトルhのままです。したがって、指数関数的な爆発はもはやありません。また、各時間ステップで同じ重みが適用されるため、入力処理に対称性があります。
ただし、いくつかの問題点もあります。最大の実用的な問題は、リカレント計算が遅いということです。フィードフォワード層では、入力ベクトルを行列で乗算し、それを何度か繰り返して終了するだけでした。しかしここでは、各隠れベクトルを一度に一つずつ生成する必要があるため、順序性に縛られています。実質的には for ループを行っており、t=1 から T まで反復して各隠れベクトルを生成しています。これはRNNが支持されなくなった大きな問題の一つです。
もう一つの問題は、理論的にはすべての過去のコンテキストを隠れベクトルに取り込むことができますが、実際には完璧に機能しないことです。例えば、ここで見た単語はある意味で隠れベクトルの中でまだ生きていますが、こちらに来るにつれてその記憶はどんどん遠くなり、最近見た単語が隠れ状態を支配するようになります。ある意味では、これは正しいことです。最近のものが最も重要で、新鮮な情報だからです。人間も同様に、昔のことを忘れる傾向があります。しかし、RNNは特に今説明した単純な形式では、昔のことを早く忘れすぎる傾向があります。この問題については木曜日のクラスで再び触れる予定です。
5.2. RNNが任意の長さの入力を処理できる仕組み
リカレントニューラルネットワークの大きな強みは、任意の長さの先行コンテキストを処理できることです。次の単語を予測するために、さらに多くの情報を隠れ状態に入れていくことができます。
計算は多くのステップ前からの情報を使用していますが、長いコンテキストを持つからといってモデルサイズが増加するわけではありません。長いコンテキストに対してはより多くの計算を行う必要がありますが、そのコンテキストの表現は常に固定サイズの隠れベクトルhのままです。例えば、隠れ状態の次元が100であれば、5単語のコンテキストでも100次元のベクトル、50単語のコンテキストでも同じ100次元のベクトルで表現します。したがって、n-gramモデルで見られたような指数関数的な爆発はもはやありません。
また、RNNの重要な特徴として、各時間ステップで同じ重みが適用されるため、入力処理に対称性があります。これは固定ウィンドウモデルの問題点を解決します。例えば「student」という単語が文のどの位置に現れても、同じ重み行列を使って処理されるため、単語の意味的貢献が位置に関係なく一貫して扱われます。
具体的には、隠れ状態の更新式 h_t = tanh(W_h h_{t-1} + W_e x_t + b) によって、前の隠れ状態と現在の入力から新しい隠れ状態が計算されます。このプロセスを繰り返すことで、任意の長さの入力シーケンスを処理できるのです。シーケンスの最終的な隠れ状態は、そのシーケンス全体の情報を圧縮した表現となります。
これにより、n-gramモデルのようにコンテキストの長さに制限されることなく、理論上はどれだけ長いシーケンスでも処理できるようになります。ただし、後で説明するように、実際には長距離依存関係の学習には課題があります。
5.3. RNN言語モデルのトレーニング方法
RNN言語モデルをトレーニングするための出発点は、n-gramモデルと同様に大量のテキストコーパスを用意することです。そして、各時間ステップで次の単語の確率予測を計算し、実際の次の単語との間で損失を計算します。
損失関数は、予測された確率と実際の次の単語の間のクロスエントロピーです。これは前の例で示したように、実際の次の単語の負の対数尤度に過ぎません。理想的には、実際の次の単語を確率1で予測したいわけですが、その場合、1の負の対数は0となり、損失はゼロになります。実際には、例えば確率0.5と予測した場合は少しの損失が発生し、以下同様です。
全体の目的関数を得るために、各単語を順番に予測する際の平均損失、つまり平均負の対数尤度を計算します。例えば、コーパスが「the students open their exams」である場合、まず「the」の後に何が来るかを予測します。異なる確率で単語を予測し、「実際の次の単語は'students'だ」と言います。「students」に与えた確率(例えば0.05)の負の対数が、この予測の損失となります。なぜなら、最初の単語が「the」だったことしか知らなかったからです。
次に次の単語の確率推定を生成し、「実際の単語は'open'だった」と言います。それにどのような確率推定を与えたかを見て、「open」の負の対数確率を損失として得ます。このプロセスを続け、それらすべての損失を合計し、単語あたりの平均を取ります。これが単語あたりの平均損失であり、これをできるだけ小さくしたいと考えます。
この損失の生成においては、自由な生成は行わないということを知っておくことが重要です。モデルに「文を生成せよ」と言うのではなく、各ステップでいわば「プレフィックスは'the students open'である。それに続く単語の確率分布はどうなるか」と問いかけ、RNNでその分布を生成し、「実際の次の単語'their'にはどのような確率を与えたか」と尋ねます。これが損失です。
そして、「their」をRNNに入力する(正解を入れる)、次の単語の確率分布を生成し、「実際の次の単語'exams'にはどのような確率を与えたか」と尋ねます。そして再び実際の次の単語を使います。つまり、1ステップの生成を行い、それを実際にテキストにあったものに戻し、次の単語に対する予測を尋ね、これを永遠に繰り返します。
自由な生成を行わず、各ステップで実際のテキストに戻すという事実がものごとを単純にします。なぜなら実際の著者が次の単語として何を使ったかを知っているからです。このプロセスは「教師強制(teacher forcing)」と呼ばれ、言語モデルのトレーニングに最も一般的に使用される方法です。
これは全ての面で完璧ではありません。モデルが自ら生成したいかもしれない異なるものを探索せず、それに続くものを見ていないからです。人間が生成したテキストから次の単語を予測するだけです。
これが損失を得る方法であり、その後は、以前と同様に、これらの損失を使用してニューラルネットワークのパラメータを更新したいと考えます。
5.4. 教師強制(teacher forcing)
RNN言語モデルをトレーニングする際の重要な手法が教師強制です。この方法では、各時間ステップでモデルから予測を生成した後、次のステップの入力として実際のテキストデータから正解の単語を与えます。
具体的に説明すると、収集したテキストは実質的に非常に長い単語の並びと考えることができます。理論上はこの10億語のテキスト全体に対してRNNを実行し、コンテキストを更新していくことができますが、これでは訓練が非常に難しくなります。10億ステップの損失を蓄積して保存しなければならず、パラメータを更新するために隠れ状態も保存する必要があるため、実際には機能しません。
そこで実際に行うのは、トレーニングデータを適切な長さのセグメントに分割し、それらのセグメントに対してRNNを実行します。各セグメントの損失を計算し、その損失に基づいてRNNのパラメータを更新します。ここでは、セグメントを文書や文として言語的に意味のあるものにすると記述していますが、最近の実践では、GPUで最も効率的にスケールするために、言語的な区切りを考慮せず、単純に100単語ごとに区切ることもあります。これにより、すべて100単語の長さを持つセグメントのバッチを作成し、行列に入れて、ベクトル化されたトレーニングをより効率的に行うことができるからです。
教師強制の場合、各ステップでモデルによる予測を生成した後、次のステップの入力として、モデルが予測したものではなく、実際のテキストから次の単語を使用します。これにより、モデルは常に正確なコンテキストから学習することができ、誤差の蓄積を防ぐことができます。
例えば、「the students open their exams」という文を処理する場合、まず「the」という単語からスタートし、次の単語「students」を予測します。ここでモデルの予測が「children」であっても、次のステップでは実際のテキストの「students」を入力として使用します。これを続けることで、モデルは常に正確なコンテキストから学習します。
この教師強制アプローチは、トレーニングを安定させ、効率的に学習できるようにします。ただし、この方法はモデルが自分自身の予測に基づいて次の単語を生成するという実際の使用場面とは異なるため、いくつかの欠点もあります。モデルは自分の誤りを修正する方法を学習する機会がないのです。しかし、これらの欠点にもかかわらず、教師強制は言語モデルトレーニングで最も一般的に使用される方法です。
5.5. 切り詰めバックプロパゲーション
RNN言語モデルをトレーニングするには、ニューラルネットワークのパラメータに関する損失の導関数を計算する必要があります。興味深いのは、これらのWhパラメータやWeパラメータがニューラルネットワークの各段階で使われているため、損失に対するこれらの繰り返し重み行列の偏導関数をどのように計算するかという点です。
答えは実に単純です。それぞれの位置にあるWhが異なるものであるかのように振る舞い、一つの位置でのWhに関する偏導関数を計算し、Whに関する偏導関数を得るためには、異なる位置で見つかったものを合計するだけです。つまり、「繰り返し重みに関する勾配は、それが現れる各時間に関する勾配の合計である」ということです。
これが当てはまる理由は、講義3で説明したことに従っています。そこでは勾配が外向きに分岐することについて話しました。このような場合を考えると、各時間ステップでコピーされているWh行列があり、各時間ステップでWh1、Wh2、Wh3、Wh4などにアイデンティティコピーされています。これらはアイデンティティコピーなので、互いに対する偏導関数は1です。そこで、これらのコピーに多変数連鎖律を適用すると、外向きに分岐するノードがあり、各時間の勾配を合計して全体の勾配を得ることになります。
知っておく価値のあるもう一つのテクニックとして、例えば100単語の長さのセグメントがある場合、一般的な高速化手法は、「実際には100時間ステップ分のバックプロパゲーションを実行する必要はなく、20時間ステップ分実行して停止できるかもしれない」というものです。これは「切り詰めバックプロパゲーション(truncated backpropagation through time)」と呼ばれます。実際にはこれで十分なことが多いです。特に、前方パスではフルコンテキストを使用して隠れ状態を更新しますが、バックプロパゲーションではトレーニングを高速化するために短縮しているという点に注意してください。
6. RNNを用いたテキスト生成
6.1. 生成プロセスのロールアウト(roll-out)
先ほどn-gram言語モデルでテキストを生成できることを示しましたが、同様にRNN言語モデルを使用してテキストを生成することもできます。基本的なアイデアはほぼ同じで、n-gramの数を使用する代わりに、ニューラルネットワークの隠れ状態を使用して、サンプリングできる確率分布への入力を提供します。
最初に、初期隠れ状態から始めます。前の例では混乱を少なくするために「the」から直接始めましたが、実際には最初の「the」はどこから来たのかと疑問に思うべきでした。通常、実際に行うのは、この角括弧で囲まれた「<s>」のような特別な文頭記号を使うことです。これは擬似的な単語として扱われ、単語埋め込みを持っています。これに基づいて、テキストの最初の単語を生成するための表現が得られます。
これからは実際のテキストがないため、生成した単語(例えば「the」)を次の入力として使用し、ニューラルネットワークの次のステージを実行します。確率分布からサンプリングし、次の単語(例えば「favorite」)を得て、それを次の入力として使用し、このプロセスを続けてテキストを生成していきます。
これは「ロールアウト(roll-out)」と呼ばれ、継続的にサイコロを振り、前に進み、テキストを生成する過程です。通常、ある時点で停止したいので、「</s>」のような2番目の特殊記号を持つことができます。これは文末記号を示し、これが生成されたら停止します。
この方法を使って、テキストの断片を生成することができます。基本的に、例えばチャットGPTのようなものを使う場合、これとまったく同じことが起きています。モデルはまだ説明していないより複雑なモデルですが、一度に1つの単語を生成し、それを入力として扱い、次の単語を生成し、このロールアウトを行って応答を生成しています。これは確率的に行われるので、複数回実行すると異なる回答が得られることがあります。
チャットGPTにはまだ至っていませんが、少し楽しみましょう。ここで構築したシンプルなリカレントニューラルネットワークを任意のテキストでトレーニングし、それを使って何かを生成することができます。例えば、バラク・オバマの演説でトレーニングすることができます。これは小さなコーパスで、数十万語のテキストしかありません。大きなコーパスではありません。
これから生成されたテキストは次のようになります:「The United States will step up to the cost of a new challenges of the American people that will share the fact that we created the problem they were attacked and so that they have to say that all the task of the final days of war that I will not be able to get this done」
これはn-gram言語モデルよりは少し良いかもしれませんが、まだ完璧ではありません。質問がありましたか?
(質問:コーパスの短いセグメントでモデルをトレーニングしているので、意味のある内容を生成する能力に制限はありませんか?)
はい、テキストを100単語単位で分割すると提案しましたが、これは使用する前のコンテキストの量の制限になります。100単語はかなりの量で、通常は複数の文に相当しますが、さらに過去のコンテキストについて知りたい場合は不可能です。現代の大規模言語モデルがはるかに大きなコンテキストを使用しているのは確かに事実で、現在は数千語の前のコンテキストを使用しています。それは確かに、過去のコンテキストの制限です。
実際、理論的にはリカレントニューラルネットワークが任意の長さのコンテキストを取り込めるとしても、実際にはセグメントに分割すると言ったとき、結局再びマルコフ仮定を行っていることになり、過去のコンテキストは重要ではないと言っていることになります。
6.2. 特殊トークン(開始・終了)の使用
RNN言語モデルでテキストを生成する際、通常は特殊なトークンを使用して生成プロセスを制御します。特に、シーケンスの開始と終了を示す特殊トークンが重要です。
生成を開始するときは、初期隠れ状態を使用します。前の例では混乱を避けるために「the」から直接始めましたが、本来なら「最初の'the'はどこから来たのか」と疑問に思うべきでした。通常、実際に行うのは「<s>」(start of sequence)のような特殊な文頭記号を用いることです。この特殊トークンは擬似的な単語として扱われ、独自の単語埋め込みを持っています。
この開始トークンを入力として使用し、それに基づいて表現を生成します。その表現からサンプリングすることで最初の単語を得ることができます。この時点では実際のテキストがないので、生成された単語を次の入力として使用し、ニューラルネットワークの次のステージを実行します。確率分布からサンプリングして次の単語を得て、それを次の入力として使用するというプロセスを繰り返します。
ある時点で生成を停止したい場合は、「</s>」(end of sequence)という第二の特殊トークンを使用します。これはシーケンスの終了を示します。モデルがこの終了トークンを生成したら、そこで生成プロセスを停止します。
これらの特殊トークンを使用することで、単語の列を文や段落などの意味のある単位に分割することができます。また、トレーニング時にも同じ特殊トークンを使用することで、モデルは文の始まりと終わりを適切に予測する方法を学習します。
このように、開始トークンと終了トークンを使用することで、生成されるテキストにより自然な構造を持たせることができ、また生成プロセスを適切に制御することができます。
6.3. 様々なテキスト生成例
このシンプルなリカレントニューラルネットワークを任意のテキストでトレーニングし、それを使って様々なテキストを生成することができます。いくつかの面白い例を紹介します。
まず、バラク・オバマのスピーチでモデルをトレーニングしてみました。これは比較的小さなコーパスで、数十万語のテキストしかありません。このモデルから生成されたテキストは次のようになります:
「The United States will step up to the cost of a new challenges of the American people that will share the fact that we created the problem they were attacked and so that they have to say that all the task of the final days of war that I will not be able to get this done」
バラク・オバマの代わりに、ハリー・ポッターの本でモデルをトレーニングすることもできます。これはより大きなテキストコーパスです。このモデルから生成されたテキストはこのようになります:
「Sorry, Harry shouted panicking I'll leave those brooms in London are they no idea said nearly headless Nick casting low close by Cedric carrying the last bit of trial charms from Harry's shoulder and to answer him the common room perched upon it forearms held a shining knob from when the spider hadn't felt it seamed he reached the teams too well there you are」
他のタイプのテキストでもトレーニングできます。例えば、レシピでモデルをトレーニングして、レシピを生成することもできます。これは作ることをお勧めしないレシピですが、あまり注意深く見なければレシピのように見えます:
「Chocolate Ranch Barbecue categories game casseroles cookies cookies yield six servings two P two tablespoons of Parmesan cheese chopped um one cup of Co coconut milk and three eggs beaten um Place each pasture over layers of lumps shape mixture into the moderate oven and simmer until firm serve hot and bodied fresh mustard orange and cheese combine the cheese and salt together the dough in a large Skillet and the ingredients and stir in the chocolate and pepper H」
これはまったく一貫性のないレシピですが、レシピの言語を持っています。もっと規模を大きくし、より大きなコーパスを持っていればもう少しうまくいったかもしれません。しかし、それは確かに使用している材料を活用していません。
リカレントニューラルネットワーク言語モデルの構築のバリエーションとして、これまで単語単位でモデルを構築してきましたが、リカレントニューラルネットワークのアイデアは他のサイズの単位にも使用できます。バイオインフォマティクスのDNAなどにも使われますが、言語に留まっても、単語の代わりに文字単位でモデルを構築することもできます。これにより、一度に単語ではなく文字を生成し、英単語の構造を持つようなものを生成することができます。
そして、他にもできることがあります。以前、初期隠れ状態について、ゼロにすることもできると言いましたが、時には隠れ状態を他のもので初期化する文脈的RNNを構築することがあります。特に、隠れ状態を色のRGB値で初期化し、文字単位で塗料の色の名前を生成することができます。塗料会社のカタログからの色の名前とそのRGB値に基づいてモデルをトレーニングし、異なる塗料の色を与えて名前を生成させることができます。
これは実際に非常にうまくいきました。例えば、ここにある色は「Gasty Pink」、「Power Gray」、「Naval Tan」、「BCO White」、「HBLE Gray」、「Home Star Brown」などです。これらは塗料のカタログで見つけてもおかしくないと思いませんか?右下にはいくつか本当に良い名前があります。この色は「Dope」、そしてこちらは「Stoner Blue」、「Purple S」、「Stinky Bean」、「Turley」です。塗料会社市場で本当のビジネスチャンスがあると思います!
7. RNNの問題点
7.1. 系列処理の遅さ
RNNの最大の実用的な問題点の一つは、リカレント計算が遅いという点です。フィードフォワード層では、単に入力ベクトルを行列で乗算し、それを何度か繰り返して終了するだけでした。一方、RNNでは各隠れベクトルを一度に一つずつ順番に生成しなければならないため、順序性に束縛されています。
実際、これは授業の最初に言ったことと矛盾しています。なぜなら、基本的にここではforループを使用しているからです。時間tが1からTまで進むにつれて、各隠れベクトルを生成するという操作を行っています。この順序依存性こそがRNNが支持されなくなった大きな理由の一つです。
特に、現代の深層学習では並列処理が非常に重要です。GPUやTPUなどの並列計算デバイスの能力を最大限に活用するためには、できるだけ多くの計算を同時に実行できることが望ましいのです。しかし、RNNの本質的に逐次的な性質は、こうした並列処理の恩恵を受けにくくします。時間ステップt+1の計算は、時間ステップtの計算が完了するまで始めることができないからです。
これに対して、後に学ぶトランスフォーマーモデルなどのアーキテクチャは、シーケンス内のすべての位置を同時に処理できるため、GPUでの並列計算に適しています。これが、RNNが大規模言語モデルから段階的に置き換えられていった主要な理由の一つなのです。
7.2. 長距離依存関係の学習困難さ
もう一つの問題点は、理論的にはRNNは過去のコンテキスト全体を隠れベクトルに取り込むことができますが、実際には完璧に機能しないということです。例えば、かなり前に見た単語も隠れベクトルの中でまだ「生きて」いるとはいえ、時間が経つにつれてその記憶はどんどん遠くなり、直近で見た単語が隠れ状態を支配するようになります。
ある意味では、これは正しいことです。最近の情報が最も重要であり、それが記憶の中で最も新鮮だからです。人間も同様に、過去のことを忘れる傾向があります。しかし、RNN、特に今説明した単純な形式では、過去の情報を必要以上に速く「忘れて」しまう傾向があります。
これは長距離依存関係を持つ言語現象を扱う際に問題となります。例えば、「The man who spoke at the conference last week and impressed everyone with his eloquence is a professor at Stanford」という文では、主語「The man」と動詞「is」の間に長い修飾句があります。単純なRNNは、最終的な動詞「is」に到達したときに、主語が単数形の「man」であることを「忘れて」しまい、正しい動詞の形を予測できない可能性があります。
この問題はRNNの勾配の流れにも関連しています。バックプロパゲーションでは、長いシーケンスを通じて勾配が消失または爆発しやすいため、遠い過去からの情報に基づいて学習することが難しくなります。これは「勾配消失問題」として知られています。
この問題に対処するために、LSTMやGRUといった改良されたRNNアーキテクチャが開発されました。これらは特別なゲート機構を導入し、より長い期間にわたって情報を保持できるようにしています。しかし、それでも非常に長い依存関係を持つケースでは課題が残ります。