ChatGPTやInstructGPTが間違った答えを出すときには、解決の手順となる「思考の連鎖」と呼ばれる情報をプロンプトに含めることで、よりよい解答を得られることがあります。これを実際に試してみましょう。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
タイミングを考えると、プロンプトとか思考の連鎖をやっている場合じゃなくって、ChatGPT APIをやるべきだろ! となるのですが、それは次回のネタとさせてください(かわさき)。
OpenAI Cookbookの「Techniques to improve reliability」ページでは言語モデルからの信頼性を高めるためのノウハウが紹介されています。そこでは「明確な指示を与える」「複雑なタスクは幾つかのタスクに分割する」「モデルがタスクから逸脱することがないようにプロンプトを構造化する」といったことが書かれています。そして、その中には「答えを出す前に説明するようにモデルに指示する」(Prompt the model to explain before answering)という項目があります。
この中で出てくる概念に「思考の連鎖」(Chain of Thought、CoT)というものがあります。思考の連鎖とは「複雑なタスクを最終的に解決する過程における、中間的な推測ステップの連なり」といえます。こういう表現だと少し分かりにくいのですが、「リンゴが10個ありました。そのうちの5個を食べた後に、食べ過ぎたと思って3個を買い直しておきました。リンゴは今何個あるでしょうか」を考えるときに、「10−5=5個になったね」「5+3=8個になったね」「じゃあ今は8個あるよ」という風に問題を解くまでに頭の中で考えていることの過程を示すものだと考えてもよいでしょう。「AならB」「BならC」だから「AならC」のような論理記述を行う際にも思考の連鎖が使えますね。
「Chain-of-Thought Prompting Elicits Reasoning in Large Language Models」という論文では、このような思考の連鎖(以下、CoTとしましょう)をプロンプトに組み込むことで、言語モデルからよりよい答えを引き出せることが述べられています。こうしたプロンプトのことを「思考の連鎖プロンプト」「CoTプロンプト」などと呼びます。これに対してCoTを含まないプロンプトを「標準的プロンプト」(Standard Prompting)と呼ぶことがあります。
ここでは「Q:このカフェテリアには23個のリンゴがあります。そのうちの20個を使ってランチを作りました。その後、6個を買い足しました。リンゴは何個あるでしょう?」という問題について考えてみます(この問題は前述の論文で使われているものです)。正解は「23−20+6=9」ということで9個です。
以下は標準的プロンプトを使って、これをChatGPTに尋ねてみたところです。
いい感じに答えてくれました。実はいい感じに答えてもらうと都合が悪いのです。
失敗してくれないと話が進まないので、InstructGPTに同じことを聞いてみましょう(背景色が薄い緑色のテキストがInstructGPTからの出力です)。
こちらは何を考えたのか「29個」だと答えを返してきました(「9個」だと正解を返してくることもあります)。プロンプトを使って正解を得られるようにしていくのがここでのテーマです。
その前に、InstructGPTのプロンプトと答えで少し注目してほしいところがあります。それはプロンプトを「Q:」で始めたら、答えが「A:」で始まるようになっている点です。これは、プロンプトに合わせて解答が「A:」で始まるようにInstructGPTがしてくれているということです(プロンプトから「Q:」を削除すると、出力から「A:」がなくなります)。
それだけではありません。例えば、アヒルの鳴き声についてInstructGPTに尋ねてみましょう。
日本語が微妙に変なところは置いておいて、ここで「ガーガー」とだけ答えてくれればよいとします。このようなときには本題の前にどのように答えてほしいのか、その例を提示できるのです。今見たように言語モデルは「Q:」と「A:」のような係り受けをうまく処理してくれますが、さらにプロンプトの入力者が例を示すことで出力のフォーマットを言語モデルに強制する、つまり、プロンプトで言語モデルの振る舞いを制御できるということです。
以下に例を示します。
ここでは最初の4行は入力とそれに対する応答の例です。これらの4行は言語モデルからの出力ではなく、プロンプトに含められた入力と応答の例です。プロンプトに例を内包することから「インコンテキストサンプル」(in-context Exemplars)と呼ぶこともあります(上述の「Chain-of-Thought Prompting Elicits Reasoning in Large Language Models」という論文による)。
「exemplar」は「模範、手本、原型、典型、実例」といった意味です。が、ここではサンプルという語を当てはめています。モデルに示す「お手本」(このような問題はこのようにして解く)とか「典型的な解法」のような意味合いで使っていると思われるので、もしかしたらサンプルという語はよろしくないかもしれませんね。
プロンプトに含められた入力と出力の例から言語モデルは学習をして、例に合わせた出力を返します。このように言語モデルをファインチューニングするのではなく、プロンプトを介して幾つかの入力と出力の例(ここでは2つの例)を言語モデルに与えることで、言語モデルに学習させることを「プロンプトによるfew-shot学習」と呼びます(例が1つだけの場合、one-shot学習と呼ぶこともあるようです)。また、例を含んだプロンプトのことを「few-shotプロンプト」と呼びます。
人間も子供に答え方を教えるときには、こんな感じに教えるかなと思いました(一色)。
ここで先ほどの「Q:カフェテリアには23個のリンゴがあります。そのうちの20個を使ってランチを作りました。その後、リンゴを6個買い足しました。リンゴは何個あるでしょう?」という問題をもう一度、InstructGPTに尋ねてみましょう。
これは標準的プロンプトで、インコンテキストサンプルもないので、先ほどと同様に、間違った答えが返ってきます(正解が返ってくることもあるでしょう)。ここでインコンテキストサンプルとして「ロジャーは5個のテニスボールを持っています。さらに3個のテニスボールが入った缶を2つ買いました。ロジャーは何個のテニスボールを持っているでしょう?」という問題とその答え「A:答えは11個です」を書いてみます。このプロンプトにはインコンテキストサンプル(上で述べた入力と出力の例)が含まれていますが、CoT(問題を解く手順)は含めていないので、標準的なfew-shotプロンプトでもあります。
テニスボールを求める問題の解答例は「A:答えは11個です」になっています。そのため、リンゴの数を求める問題に対する答えもこれに合わせて「A:答えは29個です」になっています。ですが、肝心な答えが間違っています。ではどうすれば、インコンテキストサンプルを使って、言語モデルを正解へと導けるのでしょうか。
ここでようやく登場するのが、CoT(思考の連鎖)プロンプトです。プロンプトに例としてCoTを含めるので「few-shot-CoTプロンプト」といってもいいでしょう。具体的にはテニスボールの数を求める入力に対する出力例に、その計算をどんな手順で行うのかを含めるだけです。例えば、以下がその例になります。
テニスボールの数を求めるプロンプトとその出力(解答例)には「テニスボールが5個あった。そこで、3つ入りの缶を2つ買ったので増えたのは3×2=6個。よって、合計は5+3×2=11個」という答えにたどり着くための道筋(CoT)を含めるようにしました。そして、本題であるリンゴの数を求めるプロンプトを入力すると、その出力でも例に合わせて計算をするようになったというわけです。
入力と出力の例を書いたからといって、言語モデルが常に正しい答えにたどり着けるわけではないことには注意が必要です。また試したところでは、問題文はなるべく簡潔に記述することが重要なようです(例えば、「○○は××で、◇◇は▼▼で、云々」と書くよりは「○○は××です。◇◇は▼▼です。云々」のように一つの文を短くした方がよさそうだと筆者は感じました)。
論文によれば、CoTプロンプトには次のような効用があるとされています。
とはいえ、CoTをプロンプトに含めるためには、問題の解き方を人間が知っている必要があります。さらにこれをプロンプトに含めるにはキーボードをたくさん打つ必要もあります。
個人的に「ここは便利」と感じたのは言語モデルが間違ったときに、few-shot-CoTプロンプトを修正することで、言語モデルの考え方に人が介入できるという点です。
そこで、例をプロンプトに含めずともよくしたものが「zero-shot-CoT」プロンプトです。
Copyright© Digital Advantage Corp. All Rights Reserved.