🎃

Auto Evol-Instructのプロンプト最適化をローカルモデルでやる

2024/12/14に公開

LLM・LLM活用 Advent Calendar 2024の14日目です!

https://qiita.com/advent-calendar/2024/large-language-model

面白い記事がたくさん投稿されていますので、他の方の記事もぜひご覧ください!

要約

  • プロンプト最適化によって安定したinstructionの進化が行えるようになった

目的

Evol-Instructは、合成データを作る際にLLMを使ってinstructionをより難しいものに書き換えることで、指示追従性の高いモデルを作るためのデータを構築することができる手法です。

MicrosoftのWizard-LMで提案された手法なのですが、新たにWizard-LM2ではAuto Evol-Instructという手法が提案されました。これは、

  1. 進化させたいinstructionからサブセットを取得
  2. サブセットに対して初期の進化プロンプトでinstructionを進化
  3. 実際に進化していたinstructionの数をカウント
  4. 最適化プロンプトで進化プロンプトを改善
  5. 改善した進化プロンプトでサブセットのinstructionを進化
  6. 実際に進化していたinstructionの数をカウント
  7. 5,6を複数回繰り返して、instructionの進化数が最も多かった進化プロンプトを採用
  8. 採用された進化プロンプトで4〜7を行い、スコアが改善し続けるまで繰り返す
  9. 最終的な進化プロンプトでinstruction全体を進化

というサイクルを回すことでinstructionの進化を最適化していくことで、人の手を介すことなく、より高品質なinstructionデータセットを構築していくというものです。

詳しくはこちらをご覧ください。
https://arxiv.org/abs/2406.00770
https://note.com/hatti8/n/nb70175b906ed

今回はこちらをローカルモデルを使って実装していこうと思います。

実施方法について

実験に使ったコードは以下のリポジトリにまとめてあります。

https://github.com/kkendama/Auto-Evol-Instruct

進化用モデルと評価用モデルにはQwen/Qwen2.5-32B-Instructを使用しましたが、このタスクは難しかったようで動作が少し不安定になります。

進化対象のinstructionデータセットにはaya-datasetの日本語instructionを使用しました。

プロンプトの進化

instructionの進化に用いるプロンプトは、本家を参考にして少し調整を加えたものを使用しました。

初期の進化プロンプト

以下のinstructionをより複雑なものに書き換えてください。
なお、「複雑」とは、ChatGPTやGPT-4のようなAIアシスタントにとって扱いが少し難しくなることを言います。

Step1: instructionを注意深く読み、この<instruction>をより複雑にするために可能な方法を<method_list>にすべて列挙する
Step2: Step1で作成した<method_list>に基づいて、<instruction>をより複雑にするための包括的な計画を<plan>として作成してください。計画には、<method_list>からいくつかのmethodを含める必要があります。
Step3: Stepごとに計画を実行し、<rewritten_instruction>を提出してください。<rewritten_instruction>は<instruction>に10から20語程度を追加する程度で構いません。
Step4: <rewritten_instruction>を注意深く観察し、不合理な部分を特定してください。<rewritten_instruction>が<instruction>をより複雑なものにしたにすぎず、異なるinstructionになっていないことを確認してください.それらの結果を<evaluation>にまとめてください。
Step5: <evaluation>の内容を注意深く読み、<rewritten_instruction>を修正する包括的な計画を<modify_plan>として作成してください。
Step6: Step6の結果を踏まえ、<finally_rewritten_instruction>を提出してください。ここでは、前置きなどはせずに<finally_rewritten_instruction>のみを提出してください。

Format

Step1:
<method_list>

</method_list>

Step2:
<plan>

</plan>

Step3:
<rewritten_instruction>

</rewritten_instruction>

Step4:
<evaluation>

</evaluation>

Step5:
<modify_plan>

</modify_plan>

Step6:
<finally_rewritten_instruction>

</finally_rewritten_instruction>

Instruction

<instruction>
INSTRUCTION
</instruction>

これでinstructionの進化を行い、<finally_rewritten_instruction>タグで囲まれた最終的なinstructionを進化後のinstructionとして取得します。

進化の評価

instructionの進化を行ってみると、実際には与えられたinstructionの応答を生成してしまうケースや、冗長なものになっただけで難易度自体変わらないケースなど、進化に失敗していることがあります。

Auto Evol-Instructではそういった失敗を減らすことも目的の一つで、プロンプト最適化の評価指標は実際にinstructionが進化していた割合になります。

そこで、元のinstructionと進化後のinstructionを比較して、実際に難易度が上がっているかをLLMに評価させます。

評価のプロンプトには以下のものを使用していますが、結果を一つひとつ確認すると評価精度はあまり良くなかったです(おそらくモデルサイズによる性能の限界)

進化判定プロンプト

以下のinstruction2がinstructionをより複雑なものに書き換えられているか判定してください。
なお、「複雑」とは、ChatGPTやGPT-4のようなAIアシスタントにとって難易度の高いinstructionに変化していることを言います。

  • instruction2がinstruction1をより複雑なものに書き換えている場合は、1を出力すること
  • instruction2がinstruction1をより複雑なものに書き換えていない場合は、0を出力すること
  • instructionが複雑化せず、説明が書き加えられただけなど、冗長なものに書き換えられる場合には0を出力すること
  • instruction2がinstruction1と比べてAIアシスタントにとって難易度の高いものに変化していない場合は0を出力すること
  • 判定結果は「Evaluation: 」の後に出力すること
  • 前置きはせず、フォーマットに従って判定結果のみを出力すること

Instruction1

BASE_INSTRUCTION

Instruction2

EVOLVED_INSTRUCTION

Format

Evaluation: 1/0

プロンプトの最適化

評価の結果を受けて、さらに最適な進化プロンプトを探索していきます。

ここでは生成時のステップを加えたり、説明を書き換えたりすることで、多様な進化プロンプトを生成させるようにします。

最適化プロンプト

以下のプロンプトは与えられたinstructionを確実かつ正確に、より難易度の高いものに書き換えるためのものです。
このプロンプトを改善して、より確実にinstructionを難易度の高いものに書き換えられるようにしてください。
与えられたプロンプトのそれぞれのStepを注意深く観察し、積極的にStepを追加して処理を改善してください。
また、既存のStepを見直し、Stepの修正も積極的に行ってください。

条件

  • 与えられているプロンプトは<prompt>タグで囲まれている
  • 与えられるinstructionは<instruction>タグで囲むこと
  • 与えられるinstructionを記載する箇所はINSTRUCTIONと記載すること(後の処理でINSTRUCTIONをreplaceするため)
  • Stepは最大20まで増やすことができる
  • Stepを修正した場合にはFormatの修正を欠かさず行うこと
  • 最終的に書き換えたinstructionは<finally_rewritten_instruction>タグで囲んで出力すること
  • まずは改善点を<improvement>タグで囲んで出力し、書き換えたプロンプトのみを<prompt>タグで囲んで出力すること
  • 書き換えた箇所だけでなく、プロンプトの全文を出力すること

プロンプト

PROMPT

このプロンプトで複数の進化プロンプトを生成し、それぞれのプロンプトでinstructionを進化させ、その進化を評価します。ここで最も進化に成功していたプロンプトを起点に、さらなる最適化を行うサイクルを回していきます。

結果

実際に上記のプロンプトを使って進化プロンプトの最適化を行いました。

step 進化成功率
初期プロンプト 54.4%
step1 68.4%
step2 70.9%

当初は54%だった進化成功率が1度目の最適化で68%に上昇し、2度目の最適化でさらに少し上昇しています。

3週目には71%を超えるプロンプトがなく、2週目の進化プロンプトが今回の最適解として採用されました。

最終的なプロンプトはこちらです。

最終的な進化プロンプト

以下のinstructionをChatGPTやGPT-4にとって処理がより難しくなるような複雑な形に書き換えてください。
「複雑」とは、指示の理解と実施がより困難になることを指します。

Step1: <instruction>を詳細に分析し、複雑さを増すための方法をリストアップします。この方法には既存の指示の難易度を引き上げるための多くの要素が含まれています。<method_list>タグ内で提供していただくのが望ましいです。

Step2: <method_list>を用いて、指示を複雑にするための詳細な計画を策定します。この計画は<method_list>の中から少なくとも2つの異なる方法を組み合わせることを含むべきです。<plan>タグ内で提供してください。

Step3: <plan>に基づき、<rewritten_instruction>を作成します。<instruction>から15から30語を追加することで指示の難易度が上がるようにします。<rewritten_instruction>は<rewritten_instruction>タグ内で提供してください。

Step4: <rewritten_instruction>を見直し、その複雑さが既存の<instruction>よりも上がっていることを確認します。ただし、それが全く異なる指示になっていないことも確認してください。この評価を<evaluation>タグ内で提供します。

Step5: <evaluation>をもとに、指示の複雑さと明確さを調整するために計画を修正するための具体的な内容を<modify_plan>タグ内で提供します。

Step6: 修正がなければ、現在の指示が複雑さの基準に達していることを確認し、<finally_rewritten_instruction>を<finally_rewritten_instruction>タグ内で提供します。確認が足りない場合はStep3に戻り、指示をさらに複雑にするために必要な変更を行います。

Step7: <finally_rewritten_instruction>の評価を再度行います。評価は複雑さが求められている以上に明確であるか、または明確さが求められている以上に複雑であるかを見るべきです。この評価を<balance_evaluation>タグ内で提供し、バランスが悪ければStep2に戻って改善を行います。

Format

Step1:
<method_list>
</method_list>
Step2:
<plan>
</plan>
Step3:
<rewritten_instruction>
</rewritten_instruction>
Step4:
<evaluation>
</evaluation>
Step5:
<modify_plan>
</modify_plan>
Step6:
<finally_rewritten_instruction>
</finally_rewritten_instruction>
Step7:
<balance_evaluation>
</balance_evaluation>

Instruction

<instruction>
INSTRUCTION
</instruction>

大きく変わったのは、最終的なinstructionを生成したあとに評価を行い、複雑化していない場合には進化の計画を立てるところからやりなおすようになっている部分です。

これが1週目の最適化で導入され、進化率の大幅な向上に繋がりました。

この方法は自分でプロンプトを考えているときには思いつかなかったので、32Bのモデルでもちゃんと最適化がされていることに驚きました。

まとめ

今回はAuto Evol-Instructのプロンプト最適化をQwen2.5-32B-Instructでやってみました。

プロンプトの最適化は色々な場面に適用できる技術で、特にプロンプトの設計が重要になるローカルモデルでは今後も使われていくのではないかと思います。プロンプトエンジニアリングは精神的負荷も高く、個人的には可能な限り避けたいと思っているので、今後は適用できそうな場面を探って色々と検証していければと思います!

また、今回はリソースの関係で進化の有無によるモデルの性能向上については検証できませんでしたが、そちらも追々やっていこうと思います!

Discussion