※本記事は、スタンフォード大学のCS224N「NLP with Deep Learning | Spring 2024 | Lecture 1 - Intro and Word Vectors」講義の内容を基に作成されています。講義の詳細情報は https://www.youtube.com/watch?v=DzpHeXVSC5I でご覧いただけます。本記事では、講義内容を要約しております。なお、本記事の内容は原講義の内容を正確に反映するよう努めていますが、要約や解釈による誤りがある可能性もありますので、正確な情報や文脈については、オリジナルの講義をご視聴いただくことをお勧めいたします。
この講義はChristopher Manning教授(機械学習Thomas M. Siebel教授、言語学・コンピュータサイエンス教授、スタンフォード人工知能研究所(SAIL)所長)によって行われました。スタンフォード大学のオンライン人工知能プログラムの詳細については https://stanford.io/ai をご参照ください。このコースへの登録に関する詳細は https://online.stanford.edu/courses/c... でご確認いただけます。
1. コース概要
1.1 コースの学習目標
このコースでは、主に3つの学習目標を設定しています。学期末の評価でもこれらの目標が達成できたかどうかを聞かれることになります。
まず第一の目標は、自然言語処理に応用する深層学習の基礎と現在の手法について教えることです。このクラスでは基礎から積み上げていくアプローチを取ります。最初に単語ベクトルやフィードフォワードニューラルネットワーク、再帰型ネットワーク、アテンションなどの基本を学び、その後すぐに2024年のNLPにおける主要な手法に移ります。具体的にはTransformerやエンコーダ・デコーダモデル、そして大規模言語モデルについても触れます。さらに事前学習や事後学習、適応(adaptation)、モデルの解釈可能性、エージェントなどのトピックも扱います。
第二の目標は、人間の言語とそれをコンピュータで理解・生成する際の難しさについて理解を深めることです。このクラスには言語学専攻や記号系システム専攻の学生もいますが、多くの方にとってはこのクラスが言語がどのように機能するかを学ぶ唯一の機会かもしれません。そのため、言語構造における問題点や、なぜ人間同士は簡単に理解し合えるのに、コンピュータでの言語理解が難しいのかについて、いくつかの洞察を伝えたいと思います。
第三の目標は、実際にシステムを構築することです。これは単なる理論の授業ではなく、実践的なスキルを身につけることを重視しています。このクラスを終えるとき、最初の就職先がスタートアップでも大手テック企業でも非営利団体でも、「テキスト分類システムが必要」とか「文書から事実を抽出する情報抽出が必要」といったNLPに関連するニーズに対して、「それを構築できます、CS224Nで学びました」と言えるようになることを目指しています。
1.2 授業の構成と評価方法
評価は主に4つの課題と最終プロジェクトによって構成されています。課題は、最初の課題を除いて基本的に1週間半の間隔で出されます。これらの課題で成績の約半分を占めます。残りの半分は最終プロジェクトによって決まります。最終プロジェクトにはデフォルトと独自の2つのバリエーションがあり、後ほど詳しく説明します。
また、少数のパーセンテージは授業への参加度によって評価されます。提出に関しては、全部で6日間の遅延が認められています。
協力ポリシーについては、他のCS授業と同様に、自分自身で課題に取り組むことが期待されています。過去に他人の作業をコピーするなどの問題があったため、このポイントを強調しておきます。真に学ぶためには自分自身で作業することが必要です。友人と話し合うことは構いませんが、課題は自分で完成させることが求められます。一方、最終プロジェクトについてはグループでの取り組みが可能です。
AIツールの使用については、このクラスでは大規模言語モデルを扱いますが、「ChatGPTに課題の質問3に答えてもらう」というやり方は学びにつながりません。コーディング支援などのツールとしてAIを活用することは構いませんが、課題の回答は自分自身で考えることが求められています。
1.3 課題とプロジェクトについて
このコースでは4つの課題があります。まず課題1は、簡単に始められるようにデザインされた入門用の課題で、Jupyterノートブックを使用します。すでにウェブページで公開されており、次週の授業前までに提出する必要があります。つまり、約7日以内に完成させなければなりません。すぐに取り組み始めるようにしましょう。
課題2は、一部の学生にとっては最も難しいと感じる課題かもしれません。私たちはコーディングブートキャンプではなく、優れた教養と工学の教育機関であるため、物事の仕組みに対する深い理解を持ってほしいと考えています。そのため、課題2では実際に数学的な作業を行い、ニューラルネットワークの仕組みを理解することを重視します。また、この課題ではPyTorchというニューラルネットワーク構築用のソフトウェアパッケージを導入し、依存構文解析(dependency parser)の構築も行います。これについては後ほど詳しく説明します。
課題3と4では、より大規模なプロジェクトに移行し、GPUを使用したPyTorchを活用します。これらの課題ではGoogle Cloudを利用しながら、機械翻訳やTransformersを使った情報抽出などに取り組みます。
最終プロジェクトには2つのオプションがあります。デフォルトの最終プロジェクトでは、システム構築のための足場と概要を提供しますが、それでも自由度の高いプロジェクトとなっています。システムの性能を向上させるためのさまざまなアプローチを試すことができ、探求することを奨励します。もう一つのオプションは、完全に独自のプロジェクトを考案し、それに取り組むことです。
最初の課題を支援するため、明日からすぐにオフィスアワーが始まり、金曜日にはいくつかのチュートリアルも行われます。最初のチュートリアルはPythonとNumPyについてで、他のクラスで既に学んだ人は必要ないかもしれませんが、このクラスはすべての人がアクセスできるようにしているため、Pythonの復習やNumPyの使い方を学びたい人は参加するとよいでしょう。
1.4 協力ポリシーとAIツールの利用について
他のCSクラスと同様に、学生が自分自身で作業を行うことに関して問題が発生したことがあります。このクラスでは皆さんに真に学んでほしいと考えており、それを実現するには自分自身で作業することが必要です。そのため、このポリシーを理解していることを確認してください。
課題に関しては、全ての学生が自分自身で取り組むことが期待されています。友人と話し合うことはできますが、課題は自分自身で完成させる必要があります。一方、最終プロジェクトについてはグループで取り組むことができます。
AIツールに関しては、もちろんこのクラスでは大規模言語モデルを重視していますが、「ChatGPT、質問3に答えてくれませんか?」というようなアプローチで課題を行うことは望んでいません。それは学びにつながる方法ではありません。コーディング支援などのツールとしてAIを活用することは構いませんが、課題の回答は自分自身で考えることが必要です。このポリシーを遵守することで、より効果的に学ぶことができるでしょう。
1.5 質疑応答
講義の概要説明の後、学生からいくつかの質問がありました。最初の質問は最終プロジェクトのメンターがどのように割り当てられるかについてでした。これに対して、自分自身で関心のある分野のメンターを見つけることができれば、その人をメンターにすることができると説明しました。それが難しい場合は、コースのTAの中から一人がメンターとして割り当てられます。最終プロジェクトを担当するTAが、専門知識を持つ人を見つけつつ、すべての学生をメンター間でほぼ均等に分配するよう努めます。
2. 人間の言語と単語の意味
2.1 言語と人間の知性について
人工知能の分野において、人間の知性と言語の関係性は議論の的となる部分があります。ソーシャルメディアではこのトピックについて様々な議論が交わされていますが、言語学者としての私の見解を共有したいと思います。
人間と最も近い動物であるチンパンジーやボノボなどと比較してみると、大きな違いの一つが言語です。彼らには言語がなく、我々人間には言語があります。ただ、それ以外の面では、チンパンジーは人間と非常に似ています。彼らは道具を使うことができ、問題解決のための計画を立てることができ、優れた記憶力を持っています。実際、チンパンジーは人間よりも優れた短期記憶を持っています。言語を除けば、チンパンジーと人間の間に知能の差を示すことは難しいのです。
しかし、言語を持つことが人間にとって非常に大きな差別化要因となりました。地球上には私たち人間より強く、速く、毒を持つなど、あらゆる面で優位性を持つ生物がいますが、人間が地球全体を支配するようになったのはなぜでしょうか。それは言語を持っていたからです。言語によるコミュニケーションが人間の優位性を可能にしたのです。
言語の役割は単にコミュニケーションを可能にするだけではありません。言語は人間がより高いレベルの思考を達成することも可能にしたと考えています。言語なしでも持てる思考の種類はいくつかあります。例えば、ある場面を想像したり、頭の中で家具を動かしたりすることには言語は必要ありません。恐怖や興奮などの感情的な反応も言語なしで起こります。しかし、高次の認知を行うとき、例えば「友達が昨夜言ったことで気分を害しているようだ、どうやって修復しようか」といった思考は、言語で行われていると思います。言語が私たちにより詳細な思考と計画のための足場を提供しているのです。
2.2 言語によるコミュニケーションと思考の関係
最も近年になって、人間は書く方法を発明しました。これは非常に新しい発明です。人間の言語がどれくらい古いのか誰も本当のところは知りませんが、ほとんどの人は数十万年程度と考えています。進化の時間スケールでは非常に短いものです。しかし、書き言葉についてははっきりしています。書き言葉は本当に非常に最近のもので、約5,000年前のものです。
書き言葉はこの驚くべき認知ツールであることが証明され、人類に巨大な優位性を与えました。なぜなら、突然情報を共有し、自分の50フィート以内に立っている人々からだけでなく、時間と空間を超えて知識を共有できるようになったからです。実際、書き言葉を持つことは、青銅器時代の非常に単純な金属加工から、今日私たちが持ち歩いているモバイルフォンやその他の技術に至るまで、非常に短時間で私たちを導くのに十分でした。
言語はかなり素晴らしいものですが、言語の知識的側面だけに注目すべきではありません。言語には別の側面があり、言語は人間によって社会的ツールとして使用されるこの非常に柔軟なシステムです。私たちは多くの不正確さと微妙なニュアンス、感情を持って話すことができ、人々に理解してもらうことができます。言葉を使って物事についての新しい考え方を設定することができます。言語は静的なものではなく、人間がそれを使用するにつれて変化します。言語は神から板に書かれて下された何かではなく、人間が構築し、世代ごとに変化させてきたものです。
実際、言語におけるほとんどの革新は若者の間で起こります。つまり、あなた方のほとんどより数年若い人々、10代前半から20代に入る人々の間です。これが言語革新の大きな時期であり、人々はクールな新しいフレーズやものの言い方を考え出し、そのいくつかが埋め込まれ拡張され、それが言語の未来となるのです。
2.3 言語の社会的側面と変化
言語は単に知識を伝えるだけのものではなく、人間によって社会的ツールとして使用される非常に柔軟なシステムです。私たちは多くの不正確さやニュアンス、感情を込めて言語を使うことができ、それでも相手に理解してもらうことができます。言葉を使って物事について新しい考え方を生み出すことができ、言語は静的なものではなく、人間が使用するにつれて変化していきます。
言語は神から板に書かれて下されたものではなく、人間が構築し、各世代によって変化させてきたものです。実際、言語におけるほとんどの革新は若者の間で起こります。10代前半から20代にかけての若者たちが、クールな新しいフレーズや表現方法を考え出し、そのいくつかが定着して広がり、それが言語の未来となっていくのです。
かつてスタンフォード大学の心理学者だったハーブ・クラークは現在引退していますが、彼は次のような印象的な言葉を残しています:「言語使用は主に単語とその意味に関するものだという一般的な誤解があります。そうではありません。それは主に人々とその意図に関するものなのです。」この言葉は、言語の社会的な側面と、言語が意味の伝達だけでなく人間同士の相互作用のツールであることを強調しています。
2.4 言語の意味と使用に関する考察
かつてスタンフォード大学の心理学者だったハーブ・クラークは現在引退していますが、彼は次のような印象的な言葉を残しています:「言語使用は主に単語とその意味に関するものだという一般的な誤解があります。そうではありません。それは主に人々とその意図に関するものなのです。」
この洞察は、言語を単なる辞書的な意味のやり取りとしてではなく、人々が意図を伝え合う社会的な現象として捉える重要性を強調しています。言語は社会的ツールであり、人々が様々な目的のために柔軟に使用し、常に進化させていくものなのです。
この言語の社会的側面の理解は、後ほど説明するディープラーニングにおける言語理解の進歩と密接に関連しています。過去10年ほどで、私たちはディープラーニングを使って人間の言語をコンピュータで理解させる能力に大きな進歩を遂げました。このトピックの歴史については後で詳しく説明しますが、人間の言語を処理する試みは1950年代から始まり、約60年続いてきました。ある程度のことはできましたが、言語の理解と生成能力は常に疑問視されてきました。しかし、本当に過去10年間でニューラルネットワークを使って非常に大きな進歩が遂げられてきたのです。
3. Word2Vecの概要
3.1 従来の単語表現の問題点
意味について考えるとき、単語とその意味について考えてみましょう。辞書で「意味」を調べると、「単語やフレーズによって表される概念」「人が単語を使用することで表現したい概念」「表現される概念」などと定義されています。
言語学では、意味論のクラスに参加すると、意味は一般的に記号(単語)とアイデアや物事のペアリングとして考えられています。これは「指示的意味論」(denotational semantics)と呼ばれ、記号の指示対象がその意味となります。この同じ指示的意味論の考え方はプログラミング言語にも使われています。プログラミング言語では「while」や「if」などの記号や変数があり、それらには意味があります。
つまり、「tree(木)」の意味は、世界中にあるすべての木であると言えます。これはある程度妥当な意味の概念ですが、それをどのようにコンピュータに取り込むかは、少なくとも伝統的には明らかではありませんでした。
ニューラルネットワーク以前の世界では、コンピュータ内の意味を考えるとき、人々はより原始的な方法で単語とその関係を見る必要がありました。伝統的な解決策としてよく使われていたのがWordNetでした。WordNetは一種の高度な類語辞典で、単語間の関係を示すものでした。同義語や「種類の一つ」などの関係を教えてくれます。例えば、パンダは肉食動物の一種で、それは哺乳類の一種、というような関係です。「good」にはさまざまな意味があり、「商品」や「善」の意味があります。
しかし、WordNetのようなシステムは計算的な意味としては優れていませんでした。多くのニュアンスを見逃し、例えばWordNetでは「proficient」は「good」の同義語だと教えてくれますが、「それはgoodなショットだった」と言えても「それはproficientなショットだった」と言うと奇妙に聞こえます。単語の使い方には多くの色合いとニュアンスがあるのです。また、WordNetは非常に不完全で、よりクールでモダンなスラングは含まれていません。人間が手作業で作ったものなので、多くの問題があります。
このような問題から、意味を異なる方法で表現できないかという考えが生まれ、それが単語ベクトルという概念につながりました。「wicked」「badass」「nifty」「wizard」といった単語をコンピュータで扱うとき、これらは基本的に離散的な記号であり、一種の原子あるいは記号に過ぎません。これをより数学に近いものに変換する方法として、一般的に使われてきたのが「one-hotベクトル」です。
語彙があり、単語はその語彙内のある項目です。「motel」はその語彙内のその単語であり、「hotel」はこの単語です。通常、計算システムではすべての文字列をインデックス化して数字に変換し、それがベクトル内の位置となります。しかし、単語の数は膨大なので、非常に大きく長いベクトルになります。
これらは「one-hotベクトル」と呼ばれ、単語の意味を表現するのに使われてきましたが、計算に使用するには良い方法ではないことが判明しました。数十年間使用されてきましたが、問題があります。その一部の理由は、単語の意味の自然な固有の感覚がないためです。「hotel」と「motel」と「house」と「chair」があるとしても、ベクトル表現においては「motel」と「hotel」が似ているという指標はなく、ただベクトルの異なる位置に1を持つ異なる記号に過ぎません。
数学的には、これら2つのベクトルの内積を取ると0になります。2つのベクトルは直交しており、互いに何の関係もありません。もちろん、単語の類似性に関する別のリソースを作成し始め、そのリソースを参照して「motels」と「hotels」が似ていることを知らせることはできます。ウェブ検索ではこれを「クエリ拡張技術」と呼んでいました。しかし、one-hotベクトルには自然な類似性の概念がないのです。
このベクトル表現は「局所的表現」(localist representation)と呼ばれ、各単語がベクトル内の1つの点で表現されることを意味します。「motel」の表現はここにあり、「hotel」の表現はここにあるというように、各単語はベクトル内の1つの場所で表現され、それは次に説明する方法とは異なります。
3.2 分布的意味論の考え方
意味論に対する代替的なアイデアがあります。これは英国の言語学者J.R. Firthが1957年に述べた「単語はその仲間によって知られる」という言葉としてよく引用されるものです。また、ヴィトゲンシュタインなどの哲学的研究にも遡りますが、単語の意味をその出現コンテキストによって表現すべきだというものです。つまり、単語の周りに現れる単語が、その意味に関する情報を提供するという考え方です。
これは「分布的意味論」(distributional semantics)と呼ばれ、先ほど説明した「指示的意味論」(denotational semantics)と対照的です。例えば「banking」という単語の意味を知りたければ、この単語を使用したいくつかの文を見てみます。「2009年に起きたような政府の債務問題が銀行危機に変わる」などのコンテキスト、つまり「banking」の周りに出現する単語がその意味となります。そして、これらの単語の統計情報、特に単語の周りにどのような他の単語が現れるかという統計を使って、単語の新しい種類の表現を学習することになります。
私たちの単語の新しい表現は、単語の意味を与える、より短く密度の高いベクトルとして表現することです。ここでのベクトルは非常に短く、スライドに収まるように8次元程度ですが、実際にはそれほど短くありません。200や2000次元かもしれませんが、合理的に短いものです。50万の異なる単語からなる語彙のような50万次元ではありません。
このアイデアは、単語同士に関連性がある場合、それらは類似したベクトルを持ち、それらの内積が大きくなるということです。例えば、「Banking」と「monetary」の例では、どちらも第1次元と第2次元では正、第3次元では負、第4次元では異なる符号を持っています。内積を計算するとき、対応する項の積を取り、対応する値が同じ符号を持つほど大きくなり、また大きな値を持つほど大きくなります。
これらを「単語ベクトル」(word vectors)と呼び、「埋め込み」(embeddings)や「ニューラルワード表現」とも呼ばれています。最初にやりたいことは、異なる単語に対する良い単語ベクトルを学習することです。もし単語ベクトルが単語の意味の良い感覚を与え、どの単語が意味的に他の単語と似ているかを知っていれば、それらは良い単語ベクトルとなります。
これらを「埋め込み」と呼ぶのは、高次元空間内のベクトルとして考えることができ、各単語をその高次元空間内の位置として埋め込んでいるからです。空間の次元性はベクトルの長さとなるため、300次元の空間のようなものになるかもしれません。
3.3 単語ベクトルの概念
単語ベクトルは、単語の意味を高次元空間内の点として表現する手法です。これは「埋め込み」や「ニューラルワード表現」とも呼ばれています。私たちが目指すのは、異なる単語に対する良質な単語ベクトルを学習することです。単語ベクトルが良質であるとは、それが単語の意味の良い感覚を与え、どの単語が意味的に他の単語と似ているかを示せることを意味します。
これらを「埋め込み」と呼ぶのは、各単語を高次元空間内の位置として埋め込んでいるからです。空間の次元性はベクトルの長さとなり、約300次元の空間といったものになることがあります。この高次元空間は人間が直接見たり理解したりすることが難しいため、私が示せるのは2次元空間のみですが、高次元空間と2次元空間では振る舞いが非常に異なることを頭に入れておくとよいでしょう。
2次元空間では、他の何かの近くにあるのは、XとY座標が似ている場合のみです。しかし高次元空間では、物事は空間の異なる次元で様々なものに非常に近くなることができます。これにより、単語の異なる意味や単語同士の類似性をさまざまな形で捉えることができるのです。
結果として得られる図は、すべての単語をコンテキスト内の他の単語に基づいてベクトルとして表現し、このベクトル空間に埋め込むというものです。この空間の一部を拡大して見てみると、例えば国や場所を表す単語が集まっている領域があります。上部には国々が、また「British」「Australian」「American」「European」といった国籍を表す言葉があります。
別の空間の一部では、動詞が集まっている領域があり、単に動詞があるだけでなく、動詞に関する多くの微細な構造が表現されています。コミュニケーション、発言、思考、期待などの動詞がグループ化され、「come」と「go」が一緒にグループ化され、下部には「have」の形態があり、その上には「be」動詞の形態があります。さらにその上には「become」と「remain」があり、これらは実際には「be」動詞に似ています。「I am angry」と言えるのと同様に、「he remained angry」や「he became angry」と言えるからです。
このように、意味的に似た単語が互いに近くに配置される興味深い意味空間が得られます。そして、どのようにしてこれらの空間を得るのか、それがWord2Vecアルゴリズムの目的です。
3.4 単語の埋め込み表現の特徴
私が説明した単語ベクトルは、スライドに収めるために非常に短い8次元のベクトルでしたが、実際にはそれほど短くはありません。実践では200次元や2000次元になることもあり、語彙に含まれる50万もの異なる単語を表すone-hotベクトルほど長くはありませんが、それでも合理的な長さを持ちます。
先ほど言及したように、高次元空間は2次元空間とは大きく異なる振る舞いをします。2次元空間では、あるものが他のものの近くにあるのは、XとY座標の両方が似ている場合だけです。しかし高次元空間では、空間の異なる次元において、さまざまなものに非常に近くなることができます。これにより、単語の異なる意味や、単語が互いに似ている様々な方法を捉えることができます。
次元数をどのように決めるかについては、データ量に依存する部分があります。表現を作成するためのデータ量やベクトルをどれだけ大きくしたいかによって、経験的に最も効果的なものや実用的な観点から決定されます。おおよその目安としては、100次元程度の空間から物事が上手く機能し始めます。長い間、300次元が非常に効果的だとされてきましたが、より大規模なモデルがより多くのデータで構築されるようになるにつれ、1000や2000次元のベクトルを使用することがますます一般的になってきています。
埋め込み空間には、小さな領域と大きな領域の両方に様々な隠れた構造があります。異なる領域に異なる構造が現れますが、一般的には「距離」が単一の類似性指標として使用されます。ただし、私たちは距離だけでなく、空間内の方向も意味を持つものとして使用しています。これについては後ほど例を示します。
埋め込みの値は必ずしも-1から1の間に収まる必要はありませんが、通常私たちは正則化と呼ばれる方法を使用して係数を小さく保とうとするため、一般的に非常に大きな値にはなりません。時には長さを1に正規化することもありますが、必須ではありません。
例えば「bank」という単語については、各単語(各文字列)に対して単一の埋め込みがあります。現段階では、この埋め込みはすべての意味(金融機関としての銀行や川岸としての意味など)の平均と考えることができます。興味深いことに、この学習された表現は、両方の意味によって喚起される単語に似たものになります。これは「star」についても同様で、ハリウッドのスターとしての意味と天文学的な星としての意味の両方を持ちますが、高次元空間の特性により、この表現は「nebula(星雲)」のような天文学的な単語と「celebrity(セレブ)」のようなハリウッドスターを意味する単語の両方に近いものになります。
3.5 意味空間における単語の位置関係
単語ベクトルを用いると、私たちが得るのは、すべての単語をコンテキスト内の他の単語に基づいてベクトルとして表現し、このベクトル空間に埋め込むという図です。もちろん、この全体図では小さすぎて何も読めませんが、この空間の一部を拡大して見てみると、興味深い構造が見えてきます。
例えば、空間の一部を拡大すると、国や場所を表す単語が集まっている領域があります。上部には国々があり、「British」「Australian」「American」「European」などの国籍を表す用語もあります。さらに下には他の場所に関する単語があります。
別の空間の一部を見ると、動詞が集まっている領域があります。単に動詞があるだけでなく、動詞に関する多くの微細な構造が表現されています。コミュニケーション、発言、思考、期待などの動詞がグループ化されています。「come」と「go」が一緒にグループ化され、下部には「have」の形態があります。その上には「be」動詞の形態があり、さらにその上には「become」と「remain」があります。これらは実際には「be」動詞に似ています。なぜなら、「I am angry(私は怒っている)」と言えるのと同じように、「he remained angry(彼は怒ったままだった)」や「he became angry(彼は怒った)」と言えるからです。これらの動詞は、ほとんどの動詞よりも「be」動詞に似ているのです。
このように、意味的に似た単語が互いに近くに配置される興味深い意味空間が得られます。そして問題は、どのようにしてこれらの空間に到達するのか、それがWord2Vecアルゴリズムの目的なのです。
4. Word2Vecの目的関数と勾配
4.1 コーパスと文脈窓の定義
Word2Vecアルゴリズムでは、まず大量のテキストから始めます。これは単に単語の長いリストとして考えることができ、NLPではこれを「コーパス」と呼びます。コーパスはラテン語で「体」を意味します。つまり、床に横たわる死体と同じように、それはコーパスです。ただし、私たちが意味するのは「テキストの本体」であり、生きている人または死んでいる人ではありません。
ちなみに、今日では古典的な教育があまり良くないので、ラテン語についてもう少し説明しますと、「corpus」はUS語尾にもかかわらず第4変化の中性名詞です。これは「corpus」の複数形は「corpy」ではなく「corpora」であることを意味します。おそらく後にこのクラスでプロジェクト課題を読むとき、「corpy」と書いている人がいれば、その人が最初の講義で注意を払っていなかったか、「corpora」と書くべきだったことがわかります。
さて、テキストがあれば、各単語(「star」や「bank」などの各単語タイプ)をどこに出現しても単一のベクトルで表現することがわかっています。このアルゴリズムでは、テキスト内の各位置を通過します。テキスト内の各位置(単語のリスト)には、中心語とその周りの単語があります。そして、中心語Cとその周辺語の単語ベクトルの類似性を使用して、それらが発生する確率を計算します。そして、ベクトルを微調整して良い単語ベクトルを学習します。
より具体的に示すと、各単語タイプ(単語タイプとは、「problems」というような単語がどこに出現しても同じものを指し、単語トークンは「problems」のこのインスタンスを指します)に対してベクトルを持ちます。そして、「turning」という単語が「into」という単語の前に出現した確率を知りたいと思います。「turning」という単語が「into」の近くに出現する確率を計算し、例では左右2語ずつの狭いコンテキストの各単語について同じことを行います。
私が行いたいのは、これらの確率推定をできるだけ良くすることです。特に、実際に互いに近接したコンテキスト内に出現する単語については、共起確率を高くしたいのです。そして次の質問は、どうやってこれをするのか、ということです。1つの単語に対してこれを行ったら、次の単語についても同じように続けていきます。
私たちのモデルがこれらの確率を「うまく」予測できるようにしたいのですが、もちろん、どれだけうまくできるかには大きな限界があります。なぜなら、単純なモデルを使用しているからです。明らかに「banking」という単語を見たとき、「into」がその前に出現するかどうかは言えませんが、できるだけうまく予測したいのです。モデルには「banking」の後に「crisis」がかなり起こりそうだと言ってほしいですが、「skillet」という単語はあまり起こりそうにないと言ってほしいです。それができれば良い仕事をしていることになります。
4.2 尤度関数の最大化と負の対数尤度の最小化
これを数学的に表現する方法を説明します。コーパス内のすべての位置を調べ、例で示した通り固定のウィンドウサイズM(この例では2)を持ち、コンテキスト内の単語の確率をできるだけ高くしたいと考えます。つまり、この尤度を最大化したいのです。テキスト内のすべての位置を通過し、コンテキスト内のすべての単語について、これを大きくしたいと考えます。
ただし、実際にはこれを正確に行うことはありません。ここで2つの小さな工夫を使います。最初の工夫は、完全に任意の理由によるもので、実際には違いはありませんが、最大化ではなく最小化する方向に行きました。使用するアルゴリズムは「勾配降下法」と呼ばれ、すぐに説明します。まず、最大化ではなく最小化できるようにマイナス記号を前に置きます。これは非常に単純な部分です。
第二の工夫は、ここでは巨大な積を扱っており、巨大な積を扱うのは数学的により難しいことです。そこで対数を導入します。尤度の対数を取ると、積の対数は和に変わります。これで、テキスト内の各単語位置について和を取り、コンテキストウィンドウ内の各単語について和を取り、これらの対数確率を和します。そして前にマイナス記号があるため、対数確率の和を最小化したいということになります。
最後の工夫として、これはコーパス内の単語数に応じて大きくなるため、コーパス内の単語数で割ります。このようにして目的関数は平均負対数尤度となります。この目的関数を最小化することで、コンテキスト内の単語の確率を最大化しています。
これがやりたいことです。あとは、どのようにこの確率を最大化するのか、そもそもこの確率とは何なのかを定義する必要があります。ここで単語ベクトルが登場します。この確率を単語ベクトル自体の観点から定義します。各単語タイプは実数のベクトル(例えば100個の実数)で表現され、単語ベクトルによってのみ確率を計算する式を持ちます。このモデルには他のパラメータはありません。
ここでは、パラメータθがモデルのパラメータを表しています。そして、モデルのパラメータはすべて語彙内の各単語のこれらの単語ベクトルです。語彙に多くの単語があり、かなり大きな単語ベクトルを持つため、これは多くのパラメータですが、唯一のパラメータです。
4.3 Softmax関数の導入と確率計算
確率の計算にはこの小さな工夫を使います。中心語が与えられた場合の周辺語の確率は、2つの単語ベクトルの内積によって定義されます。内積が高ければ単語は類似しており、したがって共起確率も高くなります。ここで言う「類似」は少し変わった意味です。確かに「hotel」と「motel」は類似していると言いたいのですが、「the」という単語が「student」の前に簡単に現れるようにしたいとも考えます。つまり、奇妙なことに「the」は基本的にどんな名詞とも「類似」している必要があるのです。
内積で作業し、ここで少し特殊な数学を使って確率を得ます。まず内積から始めます。内積は2つのベクトルを取り、各成分を掛け合わせて合計します。両方が同じ符号であれば内積は増加し、両方が大きければ大きく増加します。これにより2つのベクトル間の類似性が得られますが、この値は無制限で、正か負の実数となります。
ところが、出力として確率が欲しいのです。そこでまず指数関数を適用します。任意のxに対してe^xを取ると、必ず正の値が得られます。これが指数関数の役割です。次に、確率は0から1の間であるべきなので、可能な限り最も単純な方法でこれを0から1の数値に変換します。つまり、すべての可能なコンテキスト単語に対して分子の値を計算し、それらの合計で割るだけです。これにより、コンテキスト内でどの単語がどの程度起こりやすいかの確率分布が得られます。
この小さな工夫は「softmax関数」と呼ばれています。softmax関数では、無制限の実数を取り、今説明したようなステップを通して確率分布を得ます。この例では、コンテキスト単語に対する確率分布を得ています。語彙内のすべてのコンテキスト単語に対する確率の合計は、構築方法から定義上1になります。
この関数が「softmax」と呼ばれる理由は、最大の値の確率を増幅するからです(これは指数関数によるもの)。しかし、「soft」なのは小さな項にもまだ確率を割り当てるからです。ただ、名前としては少し変わっています。「max」と聞くと通常は1つのものだけを選ぶことを考えますが、「softmax」は一連の実数をRnから確率分布に変換するものです。
このsoftmax関数はディープラーニングのあらゆる場所で使用されています。Rnのベクトルを確率に変換したいときはいつでも、softmax関数を通します。
4.4 パラメータ最適化の考え方
この部分はまだ非常に抽象的に感じられるかもしれません。その理由は、各単語にベクトルがあり、これらのベクトルを使用して確率を計算できると言いましたが、そもそもベクトルはどこから来るのでしょうか?という疑問があるからです。
ベクトルはどこから来るのかという質問への答えは、これを最適化問題に変換するということです。大量のテキストがあるので、観測されたテキスト内の単語のコンテキストの確率をできるだけ大きくする単語ベクトルを見つけることができると期待できます。
具体的に行うことは、すべての単語に対してランダムなベクトルから始め、コンテキスト内の単語の計算された確率が上がるようにこれらのベクトルを微調整し、確率がこれ以上上がらなくなるまで、つまり可能な限り最高の確率推定値が得られるまで微調整を続けます。
この微調整を行う方法は、微積分を使用します。概念的には、右側の図のような2次元空間で最小値を見つけたい場合と全く同じです。左上から始めた場合、その地点での関数の導関数を計算すると、それらは下方向と少し右方向を指しています。そこで下方向と少し右方向に進み、「現在の位置で導関数はどの方向を指しているか」と問い直すと、まだ下方向を指していますが、さらに右方向が強くなっているので、その方向にもう少し進みます。こうして歩き続け、最終的に空間の最小値に到達します。
私たちの場合、2次元よりもずっと多くの次元があります。モデルのパラメータはすべての単語ベクトルの連結ですが、説明したよりもさらに複雑です。なぜなら、実際には各単語に対して2つのベクトル、つまり中心語である場合のベクトルと周辺語である場合のベクトルを想定しているからです。これにより数学が少し単純になります。
例えば、100次元のベクトルを使用するとすれば、外側単語としての「a」に対して100個のパラメータ、外側単語としての「aardvark」に対して100個のパラメータ、…というように「zebra」まで続き、さらに中心語としての「aardvark」に対して100個のパラメータという具合に続きます。
語彙が40万単語あり、100次元の単語ベクトルを使用する場合、40万×2で80万、それに100を掛けると8000万のパラメータになります。これは非常に多くのパラメータがある空間で、物事を最適化するために調整しようとしていますが、幸いにも大きなコンピュータがあり、これが私たちが行うことです。
単純に「これは私たちの最適化問題です。これらのすべてのパラメータの勾配を計算します」と言い、それが私たちの答えを与えてくれるのです。これは魔法のように感じるかもしれません。何もないところから始め、ランダムな単語ベクトルとテキストの山から「いくつかの数学を行えば、何か有用なものが得られる」と言っても信じがたいかもしれません。しかし、これらのディープラーニング空間で起こる奇跡は、実際に有用なものが得られるということです。すべてのパラメータを最小化し、そして有用なものが得られるのです。
4.5 勾配計算の詳細な導出
ここでは、最小化の数学をより具体的に説明します。なお、このCS224Nクラスには様々な人がいます。中には私よりも数学を知っている人もいて、この次の10分は非常に退屈かもしれません。その場合はDiscordやInstagramで時間をつぶすか、退出してもかまいません。一方で、最後に数学の授業を受けたのがいつだったか思い出せない人もいて、そういった方々にも何かを学んでもらいたいと考えています。そのため、最初の2週間ではこれを少し具体的に説明したいと思います。
これが私たちの尤度関数でした。そして、私たちの目的関数はパラメータに関して、すべての単語にわたる平均負対数尤度であることを既に説明しました。この式を思い出すと、位置tプラスjの単語、つまりw(t+j)の確率の対数を取っています。
次に、確率の形式を思い出しましょう。中心語が与えられた周辺語の確率は、外側ベクトルと中心ベクトルのソフトマックス化された方程式で、語彙にわたる正規化項で割ったものでした。
パラメータを変更する方法を見つけるために、すべてのパラメータθに関するこの目的関数の偏微分を計算する必要があります。ここでは特に、中心語ベクトルに関する偏微分から始め、外側単語ベクトルについては別途計算します。
この偏微分は大きな和で、このような項の和です。大きな和の偏微分を計算する場合、各項の偏微分を独立に計算し、それらを合計することができます。つまり、この確率の対数、すなわち分子を分母で割ったものの対数に関する偏微分を計算したいのです。
この時点で、2つのものの比率の対数があるので、それを分子の対数から分母の対数を引いたものに分離できます。つまり、中心ベクトルに関する分子の対数の偏微分と、分母の対数の偏微分を計算することになります。
この時点で、一部は簡単です。ここでは対数と指数関数があり、これらの関数は互いに打ち消し合って消えます。そこで、中心ベクトルに関する外側ベクトルの転置と中心ベクトルの内積の偏微分を求めることになります。その答えはUとなります。
これを理解するには、これは全体がベクトルであることを考えてください。ここにベクトルがあり、ここにもベクトルがあるので、これはU1・V1 + U2・V2 + U3・V3などのような形になります。各要素Viに関する偏微分を計算したいので、例えばV1に関する偏微分は、他のすべての項がゼロになるのでU1だけになります。同様にV2に関する偏微分はU2となります。これをベクトル全体に対して行うと、結果としてベクトルU1、U2、U3...が語彙全体に対して得られます。
この部分は簡単ですが、次に他の部分の偏微分も計算する必要があります。ここでは少しより複雑になり、連鎖律を思い出す必要があります。ここで内部関数G(Vc)があり、その出力をZとすると、外部関数fを追加しています。このような場合、Vcに関するfの導関数は、Zに関するfの導関数と、Vcに関するZの導関数の積になります。
これをここに適用します。まず対数の導関数を取ります。対数の導関数は1/xで、これを覚えているか、調べるか、Mathematicaに計算させるかする必要があります。内部のZ部分の総和で割った1を得ます。これに内部部分の導関数を掛けます。
ここでも連鎖律を適用します。項の和W=1からVがあるので、和を外に出すことができます。内部部分の導関数を計算する必要がありますが、ここでも連鎖律を使います。指数関数の導関数は指数関数自身なので、これはUwの転置とVcの指数関数になります。そして内部部分のVcに関する導関数を取りますが、これは先ほど計算した部分と同じでUwとなります。
これらの形式を組み合わせると、分子の導関数を計算した部分と、分母の導関数を計算したこの部分を組み合わせることになります。分母の導関数は、この部分を上に、そしてその部分を下にして表現できます。
これを書き直すと、ソフトマックス方程式の形式を再現していることがわかります。結果として得られるのは、U - 中心語cが与えられたときのxの確率とUxの積の和です。
これは、実際に観測されたUベクトルと、現在のUxベクトルの重み付き予測を比較するものであり、それらがどれだけ発生しそうかに基づいて重みを付けています。
このような形式は導関数でよく見られるもので、「観測値 - 期待値」という形になります。重み付き平均が観測値と同じであれば、導関数はゼロになり、それは最大値に達したことを意味します。
これにより、中心ベクトルパラメータに関する導関数の形式が得られます。完全に導出するには、外側ベクトルパラメータについても計算する必要がありますが、公式の授業時間が終了したため、ここで終わらせておきます。
要するに、すべてのパラメータに対してこれらの導関数を計算し、これらの導関数が数値を変更する方向を与え、自動的に良い単語ベクトルを見つけることができるのです。この仕組みを理解してほしいと思いますが、幸いにもすぐに、コンピュータがこれを代わりに行ってくれることがわかるでしょう。通常、自分自身でこれを行う必要はありません。詳細については木曜日の授業で説明します。
5. 最適化の基礎
5.1 勾配降下法の原理
勾配降下法は、先ほど説明した目的関数を最小化するために使用する方法です。概念的には、右側の図のような2次元空間での例で考えるとわかりやすいでしょう。もし空間の最小値を見つけたいとき、左上から始めたとします。その地点での関数の導関数(勾配)を計算すると、それらは下方向と少し右方向を指しています。
そこで下方向と少し右方向に歩き、新しい位置に到達します。そして「現在の位置では、導関数はどの方向を指しているか」と再度問います。すると、まだ下方向を指していますが、今度は右方向への成分がより強くなっています。そこでその方向にさらに進みます。このプロセスを繰り返し続け、最終的に空間の最小値に到達します。
私たちの場合、2次元よりもはるかに多くの次元があります。モデルのパラメータはすべての単語ベクトルの連結です。さらに複雑なことに、各単語に対して2つのベクトル(中心語の場合と周辺語の場合)を持っています。そのため、語彙が40万単語で100次元のベクトルを使用する場合、40万×2で80万、それに100を掛けると8000万のパラメータになります。
これは非常に多くのパラメータを持つ空間で最適化を行おうとしていることになりますが、幸いにも現代の大きなコンピュータを使えば、この種の計算が可能です。単純に「これは私たちの最適化問題です。これらのすべてのパラメータの勾配を計算します」と言い、それが答えを与えてくれるのです。
これは魔法のように感じるかもしれません。ランダムな単語ベクトルとテキストの山から始めて、「数学を適用すれば有用なものが得られる」と言っても信じがたいでしょう。しかし、ディープラーニングの世界では実際にそのような奇跡が起きるのです。すべてのパラメータを最小化することで、本当に有用な結果が得られるのです。
5.2 高次元空間での最適化について
私たちの場合、2次元ではなくはるかに多くの次元を扱っています。モデルのパラメータはすべての単語ベクトルの連結になりますが、説明したよりもさらに複雑です。実際には各単語に対して2つのベクトルを想定しています。1つは中心語である場合のベクトル、もう1つは周辺語である場合のベクトルです。これによって数学的な処理が少し単純になります。
例えば、100次元のベクトルを使用した場合、「a」が周辺語としての場合に100個のパラメータ、「aardvark」が周辺語としての場合に100個のパラメータ、というように「zebra」までそれぞれ100個ずつパラメータがあります。そして中心語としての「aardvark」に100個のパラメータ、というように続いていきます。
語彙に40万単語があり、100次元の単語ベクトルを使用する場合、40万×2で80万、それに100を掛けると8000万のパラメータがあることになります。これは膨大な数のパラメータを持つ空間で、最適化のために調整を行うことになります。幸いにも現代の大規模なコンピュータを使えば、このような計算処理は可能です。
単純に「これが私たちの最適化問題です。これらすべてのパラメータの勾配を計算します」と言い、それが答えを与えてくれるのです。何もないところから始め、ランダムな単語ベクトルとテキストの山だけから「数学を適用すれば有用なものが得られる」というのは魔法のように思えるかもしれません。しかし、ディープラーニングの空間で起こる奇跡的なことは、実際に有用なものが得られるのです。すべてのパラメータを最小化するだけで、本当に有用な結果が出てくるのです。
5.3 連鎖律の適用
勾配計算の詳細を導出する際に、連鎖律を適用することが不可欠となります。この連鎖律は、複合関数の微分を扱う際の基本的なツールです。
具体的に見てみましょう。私たちは確率の対数に関する偏微分を計算する必要がありました。この時、確率は分子を分母で割った形になっているため、その対数は分子の対数から分母の対数を引いたものに分離できます。したがって、中心ベクトルに関する分子の対数の偏微分と、分母の対数の偏微分を別々に計算することになります。
分子の部分では、対数と指数関数が互いに打ち消し合うため簡単に計算できましたが、分母の部分ではより複雑な計算が必要でした。ここで連鎖律を利用します。内部関数G(Vc)があり、その出力をZとします。そして外部関数fがあるとき、Vcに関するfの導関数は、Zに関するfの導関数とVcに関するZの導関数の積になります。
この法則を適用して、まず対数の導関数(1/x)を取り、それに内部部分の導関数を掛けました。さらに内部部分も複合関数だったため、再び連鎖律を適用しました。指数関数の導関数は指数関数自身であるという性質を使って計算を進めることができました。
これにより、最終的に「観測値 - 期待値」という形式の導関数を得ることができました。この形式は最適化問題において非常に重要で、勾配降下法の各ステップでパラメータをどの方向に調整すべきかを示します。
5.4 「観測値 - 期待値」の形式について
勾配計算の結果として、私たちは次のような形式の式を得ました:U - 中心語cが与えられたときのxの確率とUxの積の和です。これは「観測値 - 期待値」という形式になっており、このような形は様々な種類の導関数で頻繁に見られるものです。
この式が何を意味しているのかというと、実際に観測されたUベクトル(観測値)と、現在のモデルに基づいた予測の重み付き平均(期待値)を比較しているのです。つまり、現在のuxベクトルの重み付き和を取っており、その重みはそれらがどれほど発生しやすいかに基づいています。
最適化の観点からすると、理想的には期待値(重み付き平均)が観測値と同じであってほしいと考えます。なぜなら、そうなると導関数がゼロになり、それは目的関数の最大値(または私たちの場合は最小値)に到達したことを意味するからです。
この「観測値 - 期待値」の形式は、モデルパラメータの更新方向を決める際に非常に直感的な指針を与えてくれます。モデルの予測(期待値)が実際の観測値と異なる場合、その差に比例してパラメータを調整します。予測が観測値よりも大きければパラメータを減少させ、予測が観測値よりも小さければパラメータを増加させるのです。
中心ベクトルパラメータに関する導関数の完全な導出を完了するには、外側ベクトルパラメータについても同様の計算を行う必要がありますが、基本的な考え方は同じです。これらの導関数が、各パラメータをどの方向に変更すべきかを教えてくれ、それによって良い単語ベクトルを自動的に見つけることができるのです。
6. 単語ベクトルの可視化と応用
6.1 2次元空間への投影
単語ベクトルは通常100~300次元、あるいは最近のモデルでは1000~2000次元の高次元空間で表現されます。しかし、人間は高次元空間を直接見たり理解したりすることが難しいため、これらを2次元や3次元に投影して可視化する必要があります。
私がお見せしている図は、t-SNE(t-distributed Stochastic Neighbor Embedding)と呼ばれる特定の方法を使用して作成されています。これは高次元の表現に対してより効果的に機能する非線形次元削減手法です。PCA(主成分分析)よりも、単語ベクトルのような高次元データの可視化に適しています。
t-SNEのような次元削減技術は、高次元空間での単語間の関係性を可能な限り保持しながら、2次元空間に投影します。つまり、元の高次元空間で近い単語は、投影された2次元空間でも近くに配置されるようにします。
このような可視化により、単語の意味的関係や言語の構造を直感的に理解することができます。単語ベクトルの空間全体を一度に見ることはできませんが、特定の領域を拡大して詳細を観察することができます。例えば、国名や言語名、動詞などの意味的に関連する単語がどのようにグループ化されているかを見ることができます。
高次元から低次元への投影は情報の損失を伴うため、すべての関係性を完全に保存することはできませんが、それでも単語ベクトルの重要な特性を視覚的に理解するための貴重なツールとなります。
6.2 単語の意味関係の可視化
単語ベクトルを空間に埋め込むと、私たちが得るのは、すべての単語をコンテキスト内の他の単語に基づいてベクトルとして表現し、このベクトル空間に埋め込むという図です。もちろん、この全体図では小さすぎて何も読めませんが、この空間の一部を拡大して見ると、非常に興味深い構造が見えてきます。
例えば、空間の一部では国名や場所を表す単語が集まっている領域があります。上の方には国名があり、その下には「British」「Australian」「American」「European」といった国籍を表す言葉があります。さらに下に行くと他の場所に関連する単語が見られます。
別の空間の領域を見ると、今度は動詞が集まっている部分があります。単に動詞があるだけでなく、動詞に関する多くの微細な構造が表現されています。コミュニケーション、発言、思考、期待などの動詞がグループ化されています。「come」と「go」が一緒にグループ化され、下の方には「have」の形態があります。その上には「be」動詞の形態があり、さらにその上には「become」と「remain」があります。
これらは実際には「be」動詞に似ているという興味深い特性を持っています。なぜなら、「I am angry(私は怒っている)」と言えるのと同じように、「he remained angry(彼は怒ったままだった)」や「he became angry(彼は怒った)」と言えるからです。つまり、これらの動詞はほとんどの動詞よりも「be」動詞に似ているのです。
このように、意味的に似た単語が互いに近くに配置される興味深い意味空間が得られます。空間内では関連する単語同士がクラスターを形成し、言語の構造と意味の関係を視覚的に表現しています。これらの視覚化は、私たちの単語ベクトルがしっかりと意味的情報を捉えていることを示しています。
6.3 単語ベクトルの応用例
単語ベクトルの空間において特に興味深い特性は、単語の多義性をどのように扱うかという点です。先に説明したように、私たちの現在のアプローチでは、各単語(各文字列)に対して単一のベクトル表現を学習しています。例えば「star」という単語は、ハリウッドのスターとしての意味と天文学的な星としての意味の両方を持っています。
高次元空間の特性により、この表現は「nebula(星雲)」のような天文学的な単語と「celebrity(セレブ)」のようなハリウッドスターを意味する単語の両方に近いものになります。同様に「bank」という単語も、金融機関としての銀行と川岸としての意味を持ちますが、その埋め込み表現は両方の意味に関連する単語に近くなります。
単語ベクトルは単に単語の類似性だけでなく、空間内の方向も意味を持つという点も重要です。例えば、「king」から「man」を引いて「woman」を足すと「queen」に近いベクトルが得られるという有名な例があります。これは、単語ベクトル空間が性別の関係性を捉えていることを示しています。同様に、国と首都、動詞の時制などの関係も、空間内の一貫した方向性によって表現されます。
これらの単語ベクトルは、様々な自然言語処理タスクの基盤として使用されます。テキスト分類、感情分析、機械翻訳、情報検索など、多くのアプリケーションの性能向上に貢献しています。また、より高度な言語モデルの初期化にも使用され、転移学習を可能にしています。
ただし、現段階の単語ベクトルはコンテキストに依存しない固定表現であるという限界があります。単語はコンテキストによって意味が変わるため、この制限を克服するために、後にBERTやGPTなどのモデルで使用される文脈依存の単語表現へと発展していきます。これについては、このコースの後半で詳しく学んでいきます。