watsonxを使用してPythonでGraniteモデルをプロンプト・チューニング

著者

Anna Gutowska

AI Engineer, Developer Advocate

IBM

プロンプト・チューニングとは

このチュートリアルでは、犬のグルーミングビジネスのカスタマーレビューを含む合成データセットを使用して、IBM Graniteモデルをプロンプト・チューニングします。

プロンプト・チューニングは、モデル全体を再トレーニングして重みを更新することなく、人工知能(AI)基盤モデルを新しい下流タスクに適応させる効率的で低コストの方法です。

LLM最適化の概要

基盤モデルは大規模言語モデル(LLM)上に構築され、大量のトレーニングデータを受け取ります。基盤モデルのユースケースは、チャットボットとバーチャル・アシスタントです。

基盤モデルのインプットの解釈と応答の品質を向上させる方法はいくつかあります。これらのニュアンスをより深く理解するために、いくつかの方法を比較してみましょう。

  • プロンプト・エンジニアリングは、適切に設計されたプロンプトを提供することで事前学習済みモデルの応答を最適化する手法です。この手法では新しいデータは入力されず、モデルはそのままの状態を維持します。この手法では、モデルはインプット・プロンプトとその前に設計されたプロンプトを受け取ります。例えば、「おはようございます」というインプットに対して、「英語をスペイン語に翻訳してください」というプロンプトを使用できます。この手法ではユーザーの作業負担が大きくなります。しかし、効果的なプロンプトを作成するためのこの手作業によって、生成AIモデルは基盤モデル全体を再学習することなく、タスク固有の応答を生成することができます。
  • 大規模言語モデルのファイン・チューニングでは、多数のラベル付きデータセットを提供することによって同じモデルを調整します。ファイン・チューニングではモデルの重みが変更され、タスクが多様化するにつれて管理が困難になります。これには、大量の計算リソースが必要です。さらに、非常に特定のユースケースに合わせてモデルをトレーニングできるため、この方法の精度が最高となる傾向があります。
  • 微調整とは異なり、プロンプト・チューニングでは事前トレーニング済みモデルの重みは変更されません。代わりに、この手法はパラメーター効率が高く、プロンプト・パラメーターを調整することで、モデルの応答を好みの方向に導きます。このモデルには、AI自体が生成したインプットと調整可能なソフト・プロンプトが提供されます。このタスク固有のコンテキストにより、大規模モデルは、限られたデータであっても狭いタスクへの応答を調整できます。
  • プロンプト・チューニングと同様に、プレフィックスチューニングでは、好みのアウトプットのサンプルをモデルがいくつか受け取ります。ここでの違いは、一連のタスク固有ベクトルであるプレフィックスも含まれていることです。事前修正には、ソフト・プロンプトとディープラーニング・モデルの層に注入されるプロンプトの両方が含まれます。これらのいわゆる「仮想トークン」により、調整されたモデルはさまざまな新しいタスクを一度にサポートできる柔軟性が得られます。この方法では、すべての層をファイン・チューニングするのと同様のパフォーマンスを達成でき、約0.1%のパラメーターのみをトレーニングすることができます。プレフィックスチューニングは、データ量の少ない設定でも、ファイン・チューニングよりも優れたパフォーマンスを発揮します。

ソフト・プロンプト対ハード・プロンプト

ハード・プロンプトはユーザー対応で、ユーザーのアクションを必要とします。ハード・プロンプトは、LLMが応答を生成するためのテンプレートまたは指示と考えることができます。次に、ハード・プロンプトのサンプルを紹介します。このプロンプトタイプとその他のプロンプトタイプの詳細については、IBMドキュメントページをご覧ください。

###For demonstration purposes only. It is not necessary to run this code block.
hard_prompt_template = """Generate a summary of the context that answers the question. Explain the answer in multiple steps if possible.
Answer style should match the context. Ideal Answer length is 2-3 sentences.\n\n{context}\nQuestion: {question}\nAnswer:
"""

このハード・プロンプト・テンプレートを使用すると、LLMに、好みのアウトプットの構造とスタイルに関する具体的な指示を提供できます。この明示的なプロンプトを通じて、LLMはより高品質で望ましい応答を生成する可能性が高くなります。

ソフト・プロンプトは、ハード・プロンプトとは異なり、自然言語で書かれません。代わりに、プロンプトは、より大きなモデルから知識を抽出する各入力埋め込みの先頭に追加される、AI生成の数値ベクトルとして初期化されます。この解釈可能性の欠如は、特定のタスクに最適化されたプロンプトを選択するAIにも及びます。多くの場合、AIは、なぜこれらの埋め込みを選択したのかを説明できません。他のプロンプト方法と比較して、これらの仮想トークンは、モデル自体が固定された重みでフリーズされたままになるため、ファイン・チューニングよりも計算コストが低くなります。また、ソフト・プロンプトは、人間が作ったハード・プロンプトよりも優れたパフォーマンスを発揮する傾向があります。

このチュートリアルでは、プロンプト・チューニングのためにソフト・プロンプトを取り扱います。

前提条件

watsonx.aiプロジェクトを作成するにはIBM Cloudアカウントが必要です。

手順

ステップ1. 環境を設定する

いくつかあるツールの中から選択することもできますが、このチュートリアルでは、Jupyter Notebookを使用してIBMアカウントを設定する方法について説明します。

  1. watsonx.aiにログインします。IBM Cloudアカウントを使用します。

  2. watsonx.aiプロジェクトを作成します。

    プロジェクトIDはプロジェクト内から取得できます。「管理(Manage)」タブをクリックします。次に、「一般(General)」ページの「詳細(Details)」セクションからプロジェクトIDをコピーします。このチュートリアルではこのIDが必要になります。

  3. Jupyter Notebookを作成します。

    このステップでは、このチュートリアルのコードをコピーして独自にプロンプト・チューニングを実施できるノートブック環境を開きます。あるいは、このノートブックをローカル・システムにダウンロードし、watsonx.aiプロジェクトにアセットとしてアップロードすることもできます。このJupyter Notebookと使用されるデータセットはGitHubにあります。

ステップ2. watsonx.aiランタイム・インスタンスとAPIキーを設定する

  1. watsonx.aiランタイム・サービス・インスタンスを作成します(適切なリージョンを選択し、無料インスタンスであるLiteプランを選択)。

  2. APIキーを生成します。

  3. watsonx.aiランタイム・サービス・インスタンスを、watsonx.aiで作成したプロジェクトに関連付けます。

ステップ3. 関連ライブラリーをインストールしてインポートし、認証情報を設定する

このチュートリアルには、いくつかのライブラリーとモジュールが必要です。以下を必ずインポートしてください。それらがインストールされていない場合は、pipをクイックインストールすることで問題が解決されます。

#installations
%pip install ibm-watsonx-ai | tail -n 1
%pip install pandas | tail -n 1
%pip install wget | tail -n 1
%pip install scikit-learn | tail -n 1
%pip install matplotlib | tail -n 1 #imports
import wget
import pandas as pd

from ibm_watsonx_ai import APIClient
from ibm_watsonx_ai.foundation_models.utils.enums import ModelTypes
from ibm_watsonx_ai.experiment import TuneExperiment
from ibm_watsonx_ai.helpers import DataConnection
from ibm_watsonx_ai.foundation_models import ModelInference
from sklearn.metrics import accuracy_score, f1_score
from datetime import datetime

認証情報を設定します。APIキーとプロジェクトIDを入力します。

credentials = {
    "url": "https://us-south.ml.cloud.ibm.com",
    "apikey": "YOUR_API_KEY_HERE"
}

project_id = "YOUR_PROJECT_ID_HERE"

ステップ4. 環境を確立し、データセットをインポートする

環境を確立するための最初のステップとして、認証の詳細を使用してAPIClientのインスタンスを作成し、project_idを設定します。

client = APIClient(credentials)
client.set.default_project(project_id)

アウトプット: 

'SUCCESS'

このチュートリアルでは、犬のグルーミング用ビジネス・レビューで構成される合成データセットを使用します。適切なURLを使用して、データセットをAPIクライアントに接続できます。

データセットは自由に使用できます。HuggingFaceなどのプラットフォームでは、いくつかのオープンソースデータセットが利用可能です。

train_filename = 'dog_grooming_reviews_train_data.json'

url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + train_filename
wget.download(url)

asset_details = client.data_assets.create(name=train_filename, file_path=train_filename)
asset_id = client.data_assets.get_id(asset_details)

アウトプット

Creating data asset...

SUCCESS

print(asset_id)

アウトプット: 

3b1db894-8d9e-428d-8fee-d96f328c7726

これらのカスタマーレビューの形式について洞察を得るために、データをPandasデータフレームにロードし、肯定的レビューと否定的レビューの両方を示すいくつかの行を印刷しましょう。アウトプット「1」は肯定的なレビューを表し、「0」は否定的なレビューを表します。

pd.set_option('display.max_colwidth', None)
df = pd.read_json(train_filename)
df[5:10]

アウトプット

コメント例と関連する値1と0を含むトレーニングデータセットの画面(1は肯定的なコメント、0は否定的なコメント) トレーニング・データ・セット

ステップ5. モデルをチューニングする。

TuneExperimentクラスは、実験を作成し、チューニングをスケジュールするために使用されます。これを使用して実験を初期化し、基本の基盤モデル、トレーニングデータ、パラメーターを設定しましょう。このプロンプト・チューニング演習の目標は、データセットから抽出された顧客満足度の評価に従ってLLMに応答を調整させることです。レビューは肯定的(「1」)または否定的(「0」)のいずれかに分類できるので、これは分類タスクです。

このチュートリアルでは、同様の結果を得るために、大規模言語モデルとしてIBM Graniteモデルを使用することをお勧めします。

experiment = TuneExperiment(credentials,
    project_id=project_id
)

prompt_tuner = experiment.prompt_tuner(name="prompt tuning tutorial",
    task_id=experiment.Tasks.CLASSIFICATION,
    base_model="ibm/granite-3-8b-instruct",
    accumulate_steps=16,
    batch_size=8,
    learning_rate=0.001,
    max_input_tokens=128,
    max_output_tokens=2,
    num_epochs=12,
    tuning_type=experiment.PromptTuningTypes.PT,
    init_text="Extract the satisfaction from the comment. Return simple '1' for satisfied customer or '0' for unsatisfied. Comment:",
    init_method="text",
    verbalizer="classify {0, 1} {{input}}",
    auto_update_model=True
)

チューニングの実験を設定できたら、それをデータセットに接続する必要があります。これにはDataConnectionクラスを使用しましょう。APIクライアントでデータ資産を開始する際に、以前に作成したasset_idが必要です。

data_conn = DataConnection(data_asset_id=asset_id)

使用するAIモデルの選択は自由です。watsonxを通じてチューニングできる基盤モデルは、こちらまたは次のコマンドを実行して見つけることができます。

client.foundation_models.PromptTunableModels.show()

アウトプット

{'FLAN_T5_XL': 'google/flan-t5-xl', 'GRANITE_13B_INSTRUCT_V2': 'ibm/granite-13b-instruct-v2', 'LLAMA_2_13B_CHAT': 'meta-llama/llama-2-13b-chat'}

tuning_details = prompt_tuner.run(
    training_data_references=[data_conn],
    background_mode=False)

アウトプット

##############################################

Running '20671f17-ff53-470b-9bfe-04318ecb91d9'

##############################################


pending......
running....................................................................................................................................
completed
Training of '20671f17-ff53-470b-9bfe-04318ecb91d9' finished successfully.

ステップ6. チューニングの結果を評価します。

プロンプト・チューニングが完了したことを確認するため、ステータスを確認できます。印刷のステータスが「完了」以外の場合は、チューニングが完了するまで待ってから続行してください。

status = prompt_tuner.get_run_status()
print(status)

アウトプット: 

完了

これで、プロンプト・チューニング・サマリーを取得できます。このサマリーには、損失値が表示されます。トレーニングを実行するたびに、損失関数は予測の結果と実際の成果の差を測定します。したがって、損失値が低いことが望ましいです。

prompt_tuner.summary()

また、plot_learning_curve()関数を使用して、モデル・チューニングの学習曲線をプロットすることもできます。ゼロに近い下向きの曲線は、モデルが期待されるアウトプット生成を改善していることを示しています。損失関数グラフの解釈の詳細については、関連するIBM watsonxドキュメンテーションを参照してください。

prompt_tuner.plot_learning_curve()

アウトプット

学習曲線プロット 学習曲線プロット

ステップ7. チューニングしたモデルをデプロイします。

チューニングされたモデルをデプロイするこのステップは、チューニングされたモデルのパフォーマンスを事前チューニングされたモデルと比較する次のステップを完了するために重要です。

注:SERVING_NAMEは、一意の値でなければならないため、現在の日時が設定されます。

model_id = prompt_tuner.get_model_id()

meta_props = {
    client.deployments.ConfigurationMetaNames.NAME: "PROMP TUNE DEPLOYMENT",
    client.deployments.ConfigurationMetaNames.ONLINE: {},
    client.deployments.ConfigurationMetaNames.SERVING_NAME : datetime.now().strftime('%Y_%m_%d_%H%M%S')
}

deployment_details = client.deployments.create(model_id, meta_props)

アウトプット: 

######################################################################################

Synchronous deployment creation for id: '6aa5dd5c-0cc4-44e0-9730-18303e88e14a' started

######################################################################################


initializing.......................
ready

-----------------------------------------------------------------------------------------------
Successfully finished deployment creation, deployment_id='24a97b84-47d0-4490-9f5f-21ed2376fdd6'
-----------------------------------------------------------------------------------------------

ステップ8. チューニングされたモデルをテストする。

ここで、チューニングされたモデルと元の基盤モデルの両方のパフォーマンスをテストし、チューニングプロセスの影響を確認してみましょう。まず、テスト用のデータセットを読み込みましょう。このデータセットは、チューニング中には存在しなかったデータのサブセットである必要があります。多くの場合、テスト・セットはトレーニング・セットよりも小さいものです。さらに、テストデータセットの各インプットには、ユーザーのコメントの接頭語としてプロンプトがあります。

test_filename = 'dog_grooming_reviews_test_data.json'
url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + test_filename
wget.download(url)
data = pd.read_json(test_filename)

データセットの小さな部分を表示して、その構造をよりよく理解してみましょう。

data.head()

アウトプット

コメント例と関連する値1と0を含むトレーニングデータセットの画面(1は肯定的なコメント、0は否定的なコメント) テストデータセット

テストデータセットを読み取り、インプットとアウトプットを抽出しましょう。

prompts = list(data.input)
satisfaction = list(data.output)
prompts_batch = ["\n".join([prompt]) for prompt in prompts]

また、サンプルのテスト入力と出力を印刷して、データセットのコンテンツを抽出した方法をより深く理解することもできます。

prompts[0]

アウトプット

'Extract the satisfaction from the comment. Return simple 1 for satisfied customer or 0 for unsatisfied.\nComment: Long wait times.\nSatisfaction:\n'

この例では、プロンプトを取得し、その後、長い待ち時間に関する顧客のレビューを取得し、最後に満足度は否定的なレビューを意味する0となっています。

satisfaction[0]

アウトプット: 

0

テストデータセットが用意できたので、チューニングされたモデルの精度とF1スコアをテストしてみましょう。F1スコアは、モデルの精度と再現率の平均です。そのためにはdeployment_idが必要です。ただし、APIのレート制限に達しないようにするために、concurrency_limitは2に設定されています。これは、同時に送信されるリクエストの数です。

deployment_id = deployment_details['metadata']['id']

tuned_model = ModelInference(
    deployment_id=deployment_id,
    api_client=client
)

tuned_model_results = tuned_model.generate_text(prompt=prompts_batch, concurrency_limit=2)
print(f'accuracy_score: {accuracy_score(satisfaction, [int(float(x)) for x in tuned_model_results])}, f1_score: {f1_score(satisfaction, [int(float(x)) for x in tuned_model_results])}')

アウトプット

accuracy_score: 0.9827586206896551, f1_score: 0.9827586206896551

モデルの高い精度とF1スコアを考慮して、同じGraniteモデルのパフォーマンスをチューニングせずにテストしてみましょう。

base_model = ModelInference(
    model_id="ibm/granite-3-8b-instruct",
    api_client=client
)

base_model_results = base_model.generate_text(prompt=prompts_batch, concurrency_limit=2)

print(f'base model accuracy_score: {accuracy_score(satisfaction, [int(x) for x in base_model_results])}, base model f1_score: {f1_score(satisfaction, [int(x) for x in base_model_results])}')

アウトプット

base model accuracy_score: 0.9310344827586207, base model f1_score: 0.9298245614035088

チューニングされたモデルでは、事前に調整された基盤モデルよりも優れたパフォーマンスを発揮します。チューニングされたモデルは満足度スコアの抽出に特化しているため、他の満足度抽出タスクにも使用できます。お疲れさまでした。

まとめ

このチュートリアルでは、watsonx APIを使用してIBM Graniteモデルでプロンプト・チューニングを実行しました。チューニングされデプロイされたモデルでは、基盤モデルよりも約5%高い精度で優れたパフォーマンスを発揮することに成功しました。

関連ソリューション
IBM watsonx.ai

AI開発者向けの次世代エンタープライズ・スタジオであるIBM watsonx.aiを使用して、生成AI、基盤モデル、機械学習機能をトレーニング、検証、チューニング、導入しましょう。わずかなデータとわずかな時間でAIアプリケーションを構築できます。

watsonx.aiの詳細はこちら
人工知能ソリューション

IBMの業界をリードするAIの専門知識とソリューションのポートフォリオを活用して、AIをビジネスの業務に利用しましょう。

AIソリューションの詳細はこちら
人工知能(AI)コンサルティングおよびサービス

IBMコンサルティングAIサービスは、企業がAIをトランスフォーメーションに活用する方法を再考するのに役立ちます。

AIサービスの詳細はこちら
次のステップ

AIを使用することで、IBM Concertはお客様のオペレーションに関する重要な洞察を明らかにし、改善のためのアプリケーション固有の推奨事項を提供します。Concertがどのようにビジネスを前進させることができるかをご覧ください。

Concertの詳細はこちら ビジネス・プロセス自動化ソリューションの詳細はこちら