MEGAnnoの活用: 人間とLLMの協働アノテーション

MEGAnnoは、大規模言語モデル(LLM)の力と人間の専門知識を組み合わせたデータアノテーションフレームワークで、データラベリングの効率化と精度向上を実現します。本記事では、MEGAnnoの機能を詳しく紹介し、具体的なコードスニペットとともに解説します。

ンプロセスを効率化し、強化するデータアノテーションフレームワークです。本記事では、MEGAnnoの機能を詳しく紹介し、以下の手順を実際のコードスニペットとともに解説します。

  • LLMを活用したアノテーションの実行
  • 信頼度を考慮した人間による検証
  • モデルの選択とプロンプトの調整を反復的に実施
  • 異なるLLMエージェントの結果を比較・統合

MEGAnnoを初めて使用する方へ、MEGAnnoによる人間とLLMの協働アノテーションの概要については、以前のブログ記事をご覧ください。また、基本的な使い方については公式ドキュメントを参照してください。

それでは、はじめましょう

こちらの手順に従って進めるか、事前にデータとスキーマが設定されたColabデモプロジェクトに接続することで実践できます(管理者権限なしでアクセス可能)。以前のノートブックの例と同様に、本デモではTwitter US Airline Sentimentデータセットを使用します。

セットアップ

まず、MEGAnnoをインストールし、MEGAnnoクライアントモジュールをインポートします。

				
					!pip install "meganno_client[ui] @ git+https://github.com/megagonlabs/meganno-client.git" -q
from meganno_client import Service, Authentication, Controller, PromptTemplate
				
			

次に、MEGAnnoのアクセストークン(こちらからリクエスト)、OpenAI APIキーを設定し、ホストされているMEGAnnoサービスに接続します。

				
					import os
token = # token shared through email, request at https://meganno.github.io/#request_form
# openai key, we don't collect or store openAI keys
os.environ['OPENAI_API_KEY']= 'sk-...'
# optional
# os.environ['OPENAI_ORGANIZATION'] = 'your_organization_key'

auth = Authentication(project='blog_post', token=token)
demo = Service(project='blog_post',auth=auth)

controller = Controller(demo, auth)
				
			

初期LLMアノテーション

LLMによるアノテーションを実行するには、エージェントを指定する必要があります。エージェントは、使用するLLMの設定とプロンプトによって定義されます。MEGAnnoはOpenAIのモデルをサポートしており、プロンプトの作成を簡単にする視覚的なインターフェースを提供しています。

モデルとプロンプトの設定

まず、基本的な組み込みプロンプトテンプレートを使用します。このテンプレートはラベルスキーマを基にシステム指示を構築し、指定されたデータエントリの内容を連結する形になっています。
ユーザーは、提供されたサンプル入力を使って連結の結果をプレビューし、必要に応じてテンプレートを修正できます。また、テンプレートにはget_template関数があり、プロンプトの内容を確認することが可能です。

				
					schema = demo.get_schemas().value(active=True)
label_name= 'sentiment'
prompt_template = PromptTemplate(label_schema=schema[0]["schemas"]["label_schema"], label_names=[label_name])
prompt_template.preview(records=["Sample Airline tweets1", "Sample Airline tweets1"])
				
			
Meganno prompt editor demo
				
					prompt_template.get_template()
				
			

次に、モデルを設定する必要があります。(必須項目はモデルフィールドのみです。)

				
					model_config = {
"model": "gpt-3.5-turbo",
"temperature": 0}
				
			

サブセットに対するLLMアノテーションジョブの実行

サブセットに対してLLMアノテーションジョブを実行するには、まずエージェントを登録する必要があります。人間によるアノテーションと同様に、LLMアノテーションもサブセット単位で管理されます。LLMジョブは、エージェントをサブセット上で実行するプロセスです。エージェントを登録すると、一意の識別子が付与され、実行管理が容易になります。これにより、同じサブセットや異なるサブセットに対してエージェントを再利用することが可能になります。

既存のエージェントを一覧表示したり、詳細を確認したりするための追加APIについては、AppendixのA2を参照してください。

				
					# register agent.
agent_gpt_3p5 = controller.create_agent(model_config, prompt_template, provider_api="openai:chat")
				
			

ここでは、「good」というキーワードで検索したサブセットを使用します。主にポジティブな例が含まれることを想定していますが、中立的な例や皮肉的なネガティブな例も含まれる可能性があります。

				
					# selecting subset to run the job with
subset = demo.search(keyword="good")
subset.show({"view": "table"})
				
			

次に、GPT-3.5を使用した基本的なエージェントと最小限のプロンプトを用いて、run_job関数を呼び出し、サブセットのラベリングを実行します。その後の人間による検証を適切に設定するため、モデルの予測に対する信頼度の指標としてmetadata confを収集します。この値は、OpenAIのレスポンスから取得したlogprobに基づいて計算されます。
ジョブの実行が成功すると、一意の識別子job_uuidが返され、実行の参照として利用できます。既存のジョブを一覧表示したり、詳細を確認したりするための追加APIについては、AppendixのA2を参照してください。

				
					job_uuid = controller.run_job(agent_gpt_3p5, subset, label_name, label_meta_names=["conf"])
				
			

最終的なジョブがデータベースに保存される前に、自動ラベリングの各ステップに関する統計情報も出力されます。これには、構築された有効なプロンプトの数、成功したOpenAIコールの回数、有効な結果を含むレスポンスの数とその分布などが含まれます。これらの情報を確認することで、ラベリングの品質に関する初期的な評価を行うことができます。

検証

人間による検証

次に、LLMの出力を確認し、予測を検証し、必要に応じて修正します。基本的な検証を実行するには、job_uuidを使用してジョブを参照します。
検証の際には、各予測に関連付けられたconfメタデータ(信頼度)を基にソートし、最も不確実な予測から確認を開始することができます。

				
					verf_subset = demo.search_by_job(job_id=job_uuid)
verf_subset.show({"mode": "verifying",
                  "label_meta_names": ["conf"]})
				
			

この場合、皮肉的なものと無関係なものの2つの誤分類を修正し、残りの予測を確認します。保存ボタンをクリックすると、検証結果がデータおよびアノテーションとともにバックエンドに保存されます。

Meganno Verification demo

MEGAnno gives you control over the data entries you’d like to verify through finer-grained searches. For example, the scripts below search for all the unverified predictions from a certain job with a confidence score lower than 0.99:

				
					args = {
    "job_id": job_uuid,
    "label_metadata_condition": {
        "label_name": "sentiment",
        "name": "conf",
        "operator": "<",
        "value": 0.99,
    },
    "verification_condition": {
        "label_name": label_name,
        "search_mode": "UNVERIFIED",  # "ALL"|"UNVERIFIED"|"VERIFIED"
    },
}
verf_subset2 = demo.search_by_job(**args)
verf_subset2.show({"mode": "verifying",
                  "label_meta_names": ["conf"]})
				
			

検証結果は、さまざまな条件(プリディケート)を使用して取得できます。例えば以下のスクリプトでは、人間の検証者がエージェントの予測に異議を唱え、ラベルを修正したすべてのケースを表示します。

				
					# further filter by type of verification(CONFIRMS|CORRECTS)
# CONFIRMS:  where the verification confirms the original label
# CORRECTS: where the verification is different from the original label
verf_subset.get_verification_annotations(
    label_name="sentiment",
    label_level="record",
    annotator=job_uuid,
    verified_status="CORRECTS",  # CONFIRMS|CORRECTS
)
				
			

自動検証

人間による検証の代替手段として、より高性能な別のモデルを用いた「セカンドオピニオン」を導入することも可能です。ここでは、同じサブセットをGPT-4モデルで処理し、予測結果が異なるデータポイントを収集します。

				
					model_config2 = {'model': 'gpt-4',
                'temperature': 1}

agent_gpt_4 = controller.create_agent(model_config2, prompt_template, provider_api='openai:chat')
job_uuid2 = controller.run_job(agent_gpt_4,
                              subset,
                              label_name,
                              label_meta_names = ["conf"],
                              fuzzy_extraction=True)
				
			
				
					s_conflict = demo.search(annotator_list=[job_uuid,job_uuid2],
                         label_condition={'name':label_name,
                                         'operator':'conflicts'})
s_conflict.show({'mode':'reconciling'})
				
			

上記のスクリプトを使用することで、人間による検証が最も必要なデータエントリを特定することも可能になりました。

Meganno

修正

初回のアノテーションと人間による検証の結果、モデルが皮肉的なツイートや、対象(航空会社)に対する中立的な感情の識別に苦戦していることが判明しました。そこで、プロンプトを修正し、明示的な指示と具体的な例を追加します。

				
					# building new prompt
prompt_template2 = PromptTemplate(label_schema=schema[0]['schemas']['label_schema'], label_names=[label_name])
# preview templates with sample intput, switchable with the "input" drop down
prompt_template2.preview(records=[ 'Sample Airline tweets1', 'Sample Airline tweets2'])
				
			

これを行うには、修正したプロンプトを「Task Inst」フィールドに追加し、プロンプト更新ウィジェットで保存します。

Meganno Updated prompt sample
				
					# Results:
agent_gpt_3p5_revised = controller.create_agent(model_config, prompt_template2 , provider_api='openai:chat')
				
			

修正後のモデルの性能を初期評価するため、1,000件のツイートのうち、データIDでソートされた最後の30件の予測精度を比較します。これは包括的な評価ではありませんが、初期的な洞察を得るとともに、次の改善の方向性を示唆する目的で実施します。

次のセルでは、ラベル付きのサンプルテストデータを読み込み、GPT-3.5エージェントを使用して、初期プロンプトと修正後のプロンプトで実験を実行し、それぞれの予測精度を比較します。

				
					test_subset = demo.search(skip=970, limit=30)
test_subset.show()
test_job_3p5 = controller.run_job(agent_gpt_3p5,
                              test_subset,
                              label_name,
                              label_meta_names = ["conf"],
                              fuzzy_extraction=True)
test_job_3p5_revised = controller.run_job(agent_gpt_3p5_revised,
                              test_subset,
                              label_name,
                              label_meta_names = ["conf"],
                              fuzzy_extraction=True)
				
			
				
					def evaluate(results, label_name, job_uuid):
    total, match = 0, 0
    for item in results:
        groud_truth = list(filter(lambda x: x['name']== 'pseudo_label', item['record_metadata']))[0]['value']
        prediction = list(filter(lambda x: x['annotator']== job_uuid, item['annotation_list']))[0]
        predicted_label = list(filter(lambda x: x['label_name']==label_name, prediction['labels_record']))[0]['label_value'][0]
        total += 1
        match += 1 if groud_truth == predicted_label else 0
    return f"{match} out of {total} correct."

print("Before: ", evaluate(demo.search_by_job(job_id=test_job_3p5, limit=100).value(), label_name, test_job_3p5) )

print("After: ", evaluate(demo.search_by_job(job_id=test_job_3p5_revised, limit=100).value(), label_name, test_job_3p5_revised))
# Output
# Before:  22 out of 30 correct.
# After:  24 out of 30 correct.
				
			

まとめ

このチュートリアルを通じて、MEGAnnoの活用方法について理解を深めていただけたことを願っています。プラットフォームの利用方法や詳細な情報については、公式ドキュメントページをご参照ください。高度な機能、APIクライアントドキュメント、LLMとの統合に関する詳細情報を確認できます。

また、MEGAnnoの開発経緯について詳しく知りたい方は、関連する研究論文ブログ記事をご覧ください。

Appendix

本デモに加えて、さらなる活用のための追加情報を紹介します。

A1. ローカル環境でのプロジェクトセットアップ

事前定義されたプロジェクトを当社のインフラ上でホストする代わりに、独自のプロジェクトをデプロイする手順をこちらで確認できます。JupyterやColabなどの好みのノートブック環境に接続し、カスタマイズしたデータやタスクスキーマを使用できる完全なアクセス権を活用してください。

以下のコードブロックは、本Colabノートブックのセットアップに使用したものです。このノートブックでは、3つの候補ラベルを持つ感情分析タスクを指定し、サンプルツイートデータセットからデータをインポートしています。

				
					demo.get_schemas().set_schemas({
    'label_schema': [
        {
            "name": "sentiment",
            "level": "record",
            "options": [
                { "value": "pos", "text": "positive" },
                { "value": "neg", "text": "negative" },
                { "value": "neu", "text": "neutral" },

            ]
        }
    ]
})
demo.get_schemas().value(active=True)
				
			
				
					import from dataframe
import pandas as pd

df = pd.read_csv("tweets.csv").loc[:1000]
demo.import_data_df(df, column_mapping={
    'id':'id',
    'content':'content',
    "metadata":'pseudo_label' # optional metadata
})
				
			

A2. エージェントとジョブの一覧表示

パイプラインの任意のタイミングで、コントローラーに対して、既存のエージェントやジョブを一覧表示するよう要求できます。この際、各エージェントやジョブの詳細な設定情報を確認できるほか、特定の条件(プリディケート)を適用してフィルタリングすることも可能です(現在、プロバイダーによるフィルタリングをサポート)。

				
					# list agents
controller.list_my_agents()
# job_list = controller.list_jobs('agent_uuid', [agent_uuid])
				
			
				
					# filter over agent properties and get jobs
ret = controller.list_agents(provider_filter="openai", show_job_list=True)
job_list = [val for sublist in ret for val in sublist["job_list"]]
job_list
				
			

執筆者:Dan Zhang、Megagon Labs

[原文へ – 2024/7/31]

(翻訳:Megagon Labs 東京オフィス

この記事をシェアする
1 Min Read
February 5, 2025
MCRankベンチマークとEXSIR手法を用いることで、構造化された推論によりLLMの性能がこれらの難解なタスクで大幅に向上することを示しました。
1 Min Read
December 16, 2024
複合AIシステムの最適化フレームワークは、精度・コスト・遅延などの多目的最適化や複数プランの最適化、特に予算などの制約管理を含む幅広い目標を達成すべきであると述べています。これらの最適化目標は決して網羅的ではありませんが、エンタープライズ環境において重要な要素です。
4 Min Read
November 7, 2024
AmbigNLG は、NLG の指示における曖昧な仕様を特定し、それを改善することで出力品質を向上させる手法 です。本チュートリアルでは、AmbigNLG を活用する方法について解説します。このチュートリアルでは、以下のステップを順に説明します。 ・指示の中に含まれる曖昧な要素を特定する ・曖昧な指示を明確化し、より効果的なテキスト生成を実現する ・指示の明確化の有無による出力テキストの比較を行う ・インタラクティブな曖昧性軽減を活用し、下流タスクの改善を図る