前回: (5/16)古典の「ニューラルネット」をおさらいする
🔗 ChatGPTのしくみとAI理論の根源に迫る:(6/16)機械学習とニューラルネットのトレーニング(翻訳)
さて、前章まで解説してきたニューラルネットは、どれも、特定のタスクを実行する方法を「別の場所でとっくに学習済み」であることが前提でした。
しかしニューラルネットの大きな強みは、原理的にあらゆる種類のタスクをこなせることに加えて「データの一部であるサンプルを渡すだけで(全データを与えなくても)学習できる」ことです。ニューラルネットのこうした強みは、当然ながら脳内でも発揮されます。
たとえば、イヌ画像やネコ画像を見分けるニューラルネットを作る場合、猫のヒゲがあるかどうかを専門にチェックする下請けプログラムをわざわざ作る必要はありません。代わりに、ニューラルネットに「この画像はイヌ」「この画像はネコ」というふうにラベリングしたサンプル画像データを大量に与えて、それを「機械学習(machine learning)」の手法を用いて区別する練習をさせればよいのです。
ここで大事なのは、ニューラルネットに全データを与えてやる必要はなく、一部のサンプルデータを学んだだけで、学習結果を「一般化(汎化)」できるということです。
言い換えれば、トレーニング(training: 訓練)を終えたニューラルネットは、ネコ画像の全ピクセルデータが学習済みデータと完璧に一致しなくても、それがネコらしい画像であれば、「これはネコだ」と判定できるということです。サンプル画像に全然なかった珍しいネコ写真でも、ちゃんとネコだとわかるのです。
では、ニューラルネットは具体的にどんな形でトレーニングを積むのでしょうか?
ニューラルネットをトレーニングするときは、ニューラルネットに渡したサンプルの特徴を正しく再現できる適切な重み(weight)というパラメータをいかにして見出すかが肝心です。
さらに、ニューラルネットになくてはならないもう1つの性質は、たとえばネコ画像Aとネコ画像Zから、その「中間となる」ネコ画像Bやネコ画像Qといったものを補間(interpolate)によって導き出す能力、言い換えると汎化(generalize)する能力です。
では、前章で扱った最近接点の問題よりもずっとシンプルな、画像処理と無関係な問題を見ていくことにしましょう。
ニューラルネットに、以下のグラフの関数のような振る舞いを学習させたいとしましょう。グラフのx軸に-1.0
〜1.0
の数値を渡したときに、y軸のように-1.0
、1.0
、0.0
の3種類の値を出力する関数です。
このタスクをこなすには、以下のように上から入力を1個与えると下から1個出力する、何らかのニューラルネットが必要になるでしょう。
しかし、ニューラルネットの矢印に与えるべき重みなどの値は、どうやって決めてやればよいのでしょうか?
ニューラルネットが何らかの関数を計算するときは、ありとあらゆる可能な重みの組み合わせ(=セット)を使います。
以下の4つの例は、それぞれ重みの組み合わせをまったく適当に選んだ場合の、入力と出力の関係を表すグラフです。
しかし、どの出力結果も、さっきの四角く折れ曲がった関数グラフと似ても似つかない代物ばかりです。どうやら、重みの組み合わせを適当に選んだだけではどうしようもなさそうです。
では、さっきの関数グラフを再現できる重みの組み合わせは、どうやって見つければよいのでしょうか?
基本的な手法は、ニューラルネットに「こういう入力を与えたらこういう出力を得られる」というサンプルを大量に与える形で学習させ、それによって重みの組み合わせを手に入れる、というものです。
以下の4つのグラフは同じニューラルネットですが、左から右に進むに連れて、学習用のサンプルを多く与えてあります。
このトレーニングで学習用のサンプル数が増えるに連れて、このニューラルネットに仕込まれた重みの組み合わせが次第に「いい感じ」に調整され、一番右のようにサンプル数が1千万個になると、欲しかった関数グラフの形が見事に再現されていることがわかります。
では、そういう重みの組み合わせを具体的にどう調整すればいいというのでしょうか?
基本的には、ステージごとの関数が(ここでは4つの図に応じたステージ)、欲しい関数グラフの形と比べたときに「どのぐらい遠いか」をチェックして、欲しい関数グラフに近くなる方向に重みの組み合わせを調整することになります。
この「どのぐらい遠いか」を得るために、いわゆる「損失関数(loss function)」と呼ばれるものを計算することになります。この損失関数はコスト関数(cost function)とも呼ばれます。
なお、この例で使っているのは、「得られた値と真の値の差を2乗したものの総和」を計算するだけの、極めて単純な損失関数です1。
その結果、トレーニングが図の左から右へと進むに連れて、損失関数が返す値も徐々に減少していきます(この「学習曲線(learning curve)」はタスクの種類によって異なります)。
このようにして、下の4つの図のように、上図の赤いグラフで損失関数が返す値(赤丸)が右の図に進むに連れて減少していくと、欲しい関数の形を下図で見事に再現する地点にまで到達するのです。
ここまで理解すれば、残る作業は「重みを具体的にどう調整すれば損失関数の出力を小さくできるか」を見出すことだけです。
既に述べたように、損失関数は文字通り、関数から得られる値と真の値という2つの値の距離(distance)がどのぐらい残っているのかを与えてくれる関数です。しかし、関数から得られる値は、重み調整のそれぞれの段階で「その時点のニューラルネットの状態」、すなわち「その時点で与えられている重みの組み合わせ」に応じて、異なる値となります。
しかしここで仮に、重みの組み合わせを変数化したとしましょう。たとえばとします(
は重みが複数あることを代表する添字です)。私たちが知りたいのは、こうした重みに応じて変化する損失を最小化するために、変数
をどのように調整すればよいかということなのです。
たとえば、実際に使われているニューラルネットよりもずっとずっとシンプルな場合を考えてみましょう。そこにはと
というたった2つの重みだけがあるとします。このとき、
と
の関数によって生じる損失は、以下の地形図のようなグラフで表せます(訳注: 右図は左図に等高線と立体表現(陰影と皺)を加えた以外は同じ図であり、青い場所ほど標高が低い、すなわち損失が少ないことを表します)。
数値解析と呼ばれる分野には、このような最小値を計算で求めるさまざまな手法が揃っています。しかしこのような場合は、直前のと
の値から次の
と
の値へと段階的に「最急降下経路(path of steepest descent)」をたどるのが定番の手法です(訳注: 以下の図には
と
がたどる経路が赤い矢印で示されています)。
ただし、水流が窪地に向かって山肌を駆け下りるときと同じように、この手法では山上湖のような局所的な最小値(local minimum)にたどり着くことは保証できても2、そこよりもっと標高の低い最終的なグローバル最小値(global minimum)が存在している場合、そこにたどり着くことまでは保証されません。
この最急降下経路法だけでは、この「重みランドスケープ(weight landscape)」と呼ばれる地図のどこかにあるであろう最小値にたどり着ける経路を発見できるかどうかまでは明らかにはなりませんが、ここで役に立つのが微積分3という手法です。
既に述べたように、ニューラルネットは数学的関数をひたすら計算し続けているとみなせます。そしてその関数は、ニューラルネットで計算の都度変わっていく入力と重みに依存しています。
ここで、そうした重みの組み合わせに関して関数を微分することを考えてみましょう。高校で習うように、微積分には連鎖律(chain rule)と呼ばれる有名な「合成関数の微分」法則があるので、これに沿って考えれば、ニューラルネットがある層から次の層に進んだときにどんな演算が行われるかを「解明」可能であることがわかります。こうすることで、少なくとも局所的な近似にとどまりはするものの、ニューラルネットの演算を「逆方向にたどる」形で、出力の損失を最小化できる重みの組み合わせに、一歩一歩近づいてたどり着けるようになるのです4。
上の図では、どんな最小化操作が必要かを示すために、「重み2つだけ」という非実用的な例を使いました。しかしこの最小化操作は、重みというパラメータがものすごく多い場合(実際ChatGPTでは1750億もの重みが使われています)であってもうまくいくことがわかっています。
実際、2011年頃の「ディープラーニング」ブームにおける大きなブレークスルーは、重みの数が多い方が、重みの数が少ない場合よりも(少なくとも近似値において)むしろ最小化しやすいという発見が元になっています。
これを言い換えると、一見直感に反しているのですが、ニューラルネットでは単純な問題よりも複雑な問題の方があっさり解けてしまう可能性が高いということなのです。
その理由を大まかに述べると、「重み変数」が多い場合は、最小値にたどり着けるさまざまな「方向(direction)」を抜け道のように隠し持った高次元空間が存在する可能性が高くなると考えられるからです。逆に重み変数が少ない場合は、脱出可能な「方向」を持たない局所的最小値(さっきの「山上湖」)に陥りやすくなります。
ここで指摘しておきたいのは、適切な重みの組み合わせは1種類ではないということです。すなわち、ニューラルネットに設定したときに、ほぼ同じ結果を出せる重みの組み合わせは莫大な数にのぼるのです。そして、実用的なニューラルネットのトレーニングの現場では、そうした膨大な重みの組み合わせの中から「適当に選んでいる(random choices)」のです5。このようにして、以下の4つの図のような「異なるが同等の解」がいくつも得られます。
しかし、こうした「異なる解」が示す振る舞いは、ごくわずかとはいえ違っているのが常です。そういう別解を、サンプルで学習した分野の外に適用するという「外挿(extrapolation)」を行うと、そうしたわずかな違いが思わぬ形で拡大されて、以下のように大きな違いをもたらすこともあります。
では、そうした別解のうち、どれが「正しい」のでしょうか?どれも「観測データと一致している」のですから、どれが正しいなどと客観的には決めようがありません。
しかしどの別解も、その中に生来の「考え方」をそれぞれ持ち合わせていて、「学習データにないものを与えられたとき」に、そうした考え方が使われるのです。そして、人間目線では「こっちの解の方があっちの解より適切だ」と思える場合もある、ということなのです。
概要
原文サイトのCreative Commons BY-NC-SA 4.0を継承する形で翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。原文が長大なので、章ごとに16分割して公開します。
スタイルについては、かっこ書きを注釈にする、図をblockquoteにするなどフォーマットを適宜改善し、文面に適宜強調も加えています。
元記事は、2023年2月の公開時点における、ChatGPTを題材とした生成AIの基本概念について解説したものです。実際の商用AIでは有害コンテンツのフィルタなどさまざまな制御も加えられているため、そうした商用の生成AIが確率をベースとしつつ、確率以外の制御も加わっていることを知っておいてください。
本記事の原文を開いて、そこに掲載されている図版をクリックすると、自分のコンピュータでもすぐに実行して試せるWolfram言語コードが自動的にクリップボードにコピーされるようになっています。
コモンズ証 - 表示 - 非営利 - 継承 4.0 国際 - Creative Commons