大規模言語モデル(LLM)が複雑化し、スケールアップするにつれて、そのパフォーマンス、実験、デプロイを追跡することがますます困難になってきます。これは、MLflowが登場する場面です。MLflowは、機械学習モデルの全ライフサイクルを管理するための包括的なプラットフォームを提供し、LLMも含みます。
この詳細ガイドでは、LLMを追跡、評価、デプロイするためにMLflowを利用する方法を探ります。環境の設定から高度な評価テクニックまで、コードの例とベストプラクティスを含めて、すべてを網羅します。
MLflowのLLMにおける機能
MLflow は、機械学習とデータサイエンスのコミュニティで重要なツールとなりました。特に、機械学習モデルのライフサイクルを管理するためにです。LLMの場合、MLflowはこれらのモデルを開発、追跡、評価、デプロイするための強力なツールセットを提供します。ここでは、LLM空間におけるMLflowの機能と利点について概要を説明します。
LLMの追跡と管理
MLflowのLLM追跡システムは、LLMのユニークなニーズに合わせて設計された、既存の追跡機能の強化版です。モデルとのやり取りを包括的に追跡することができます。以下の重要な側面が含まれます:
パラメータ : LLMの入力パラメータを詳細にするキーと値のペアをログします。例えば、モデル固有のパラメータであるtop_kやtemperatureなどです。これにより、各実行のすべての側面がキャプチャされます。
メトリック : LLMのパフォーマンスと精度に関する定量的な尺度です。これらは実行の進行に合わせて動的に更新できます。リアルタイムまたは事後分析のための洞察を提供します。
予測 : LLMに入力された入力と対応する出力をキャプチャし、構造化された形式でアーティファクトとして保存します。後で簡単に検索および分析することができます。
アーティファクト : 予測の他にも、MLflowは視覚化、シリアライズされたモデル、構造化されたデータファイルなどのさまざまな出力ファイルを保存できます。モデルパフォーマンスの詳細なドキュメントと分析が可能になります。
この構造化されたアプローチにより、LLMとのすべてのやり取りが徹底的に記録され、テキスト生成モデルに対する包括的な血統と品質追跡が実現します。
LLMの評価
LLMの評価は、その生成的な性質と、単一の基準となる真実の欠如により、独自の課題を提起します。MLflowは、LLM用に特別に設計された評価ツールを提供し、これらの課題を解決します。主な機能は以下のとおりです:
多様なモデル評価 : MLflowのPyFuncモデル、登録されたMLflowモデルを指すURI、またはPythonで表現されたモデルなど、さまざまなタイプのLLMを評価することをサポートします。
包括的なメトリック : LLM評価に特化した幅広いメトリックを提供します。SaaSモデル依存メトリック(例:回答の関連性)と関数ベースメトリック(例:ROUGE、Flesch Kincaid)があります。
事前定義されたメトリックコレクション : 依存するユースケース(例:質問回答やテキスト要約)に応じて、MLflowは評価プロセスを簡素化するために事前定義されたメトリックを提供します。
カスタムメトリックの作成 : ユーザーは特定の評価ニーズに合わせてカスタムメトリックを定義および実装できます。モデル評価の柔軟性と深度を高めます。
静的データセットを使用した評価 : モデルを指定せずに静的データセットを評価することができます。モデル推論を再実行せずに迅速な評価を行うのに役立ちます。
デプロイと統合
MLflowはまた、LLMのデプロイと統合をサポートします:
MLflowデプロイメントサーバー : 複数のLLMプロバイダーとのやり取りのための統一されたインターフェイスとして機能します。統合を簡素化し、資格情報を安全に管理し、一貫したAPIエクスペリエンスを提供します。このサーバーは、人気のSaaSベンダーの基礎モデルとセルフホストモデルをサポートします。
統一エンドポイント : プロバイダー間の切り替えをコードの変更なしで容易にします。ダウンタイムを最小限に抑え、柔軟性を高めます。
統合結果ビュー : 包括的な評価結果を提供し、コード内またはMLflow UIを介して詳細な分析が可能です。
MLflowのツールと統合のセットは、LLMを扱うエンジニアやデータサイエンティストにとって、貴重な資産となります。
環境の設定
LLMをMLflowで追跡する前に、開発環境を設定しましょう。MLflowと他の重要なライブラリをインストールする必要があります:
pip install mlflow>=2.8.1
pip install openai
pip install chromadb==0.4.15
pip install langchain==0.0.348
pip install tiktoken
pip install 'mlflow[genai]'
pip install databricks-sdk --upgrade
インストール後は、Python環境を再起動して、すべてのライブラリが適切にロードされていることを確認するのがよい習慣です。Jupyterノートブックでは、以下を使用できます:
import mlflow
import chromadb
<p>print(f"MLflow version: {mlflow.__version__}")
print(f"ChromaDB version: {chromadb.__version__}")
これにより、使用する主要なライブラリのバージョンが確認できます。
MLflowのLLM追跡機能の理解
MLflowのLLM追跡システムは、既存の追跡機能を基盤にして、LLMのユニークな側面に特化した機能を追加しています。主なコンポーネントを詳しく見てみましょう:
実行と実験
MLflowでは、「実行」はモデルコードの単一の実行を表し、「実験」は関連する実行のコレクションです。LLMの場合、実行は単一のクエリまたはモデルが処理する一連のプロンプトを表すかもしれません。
主な追跡コンポーネント
パラメータ : これらはLLMの入力構成です。温度、top_k、max_tokensなどです。mlflow.log_param()またはmlflow.log_params()を使用してログできます。
メトリック : これらはLLMのパフォーマンスの定量的な尺度です。精度、待機時間、またはカスタムスコアなどです。mlflow.log_metric()またはmlflow.log_metrics()を使用して追跡します。
予測 : LLMの場合、入力プロンプトとモデルの出力をログすることが重要です。MLflowはこれらをCSV形式のアーティファクトとして保存します。mlflow.log_table()を使用します。
アーティファクト : 実行に関連するファイルやデータです。モデルチェックポイント、視覚化、またはデータセットサンプルなどです。mlflow.log_artifact()を使用して保存します。
LLM実行の例を見てみましょう:
この例では、パラメータ、メトリック、入力/出力をテーブルアーティファクトとしてログします。
import mlflow
import openai
<p>def query_llm(prompt, max_tokens=100):
response = openai.Completion.create(
engine="text-davinci-002",
prompt=prompt,
max_tokens=max_tokens
)
return response.choices[0].text.strip()</p>
<p>with mlflow.start_run():
prompt = "機械学習の概念を簡単に説明してください。"</p>
<p># パラメータをログ
mlflow.log_param("model", "text-davinci-002")
mlflow.log_param("max_tokens", 100)</p>
<p># LLMにクエリを送り、結果をログ
result = query_llm(prompt)
mlflow.log_metric("response_length", len(result))</p>
<p># プロンプトとレスポンスをログ
mlflow.log_table("prompt_responses", {"prompt": [prompt], "response": [result]})</p>
<p>print(f"レスポンス: {result}")
MLflowを使用したLLMのデプロイ
MLflowは、LLMをプロダクション環境で提供するための強力な機能を提供します。MLflowのデプロイ機能を使用してLLMをデプロイする方法を見てみましょう。
エンドポイントの作成
まず、MLflowのデプロイメントクライアントを使用してLLMのエンドポイントを作成します:
import mlflow
from mlflow.deployments import get_deploy_client
<p># デプロイメントクライアントの初期化
client = get_deploy_client("databricks")</p>
<p># エンドポイント構成の定義
endpoint_name = "llm-endpoint"
endpoint_config = {
"served_entities": [{
"name": "gpt-model",
"external_model": {
"name": "gpt-3.5-turbo",
"provider": "openai",
"task": "llm/v1/completions",
"openai_config": {
"openai_api_type": "azure",
"openai_api_key": "{{secrets/scope/openai_api_key}}",
"openai_api_base": "{{secrets/scope/openai_api_base}}",
"openai_deployment_name": "gpt-35-turbo",
"openai_api_version": "2023-05-15",
},
},
}],
}</p>
<p># エンドポイントの作成
client.create_endpoint(name=endpoint_name, config=endpoint_config)
このコードは、Azure OpenAIを使用したGPT-3.5-turboモデル用のエンドポイントを設定します。Databricksのシークレットを使用したAPIキー管理に注意してください。
エンドポイントのテスト
エンドポイントを作成したら、テストできます:
<div class="relative flex flex-col rounded-lg">
<p>response = client.predict(
endpoint=endpoint_name,
inputs={"prompt": "ニューラルネットワークの概念を簡潔に説明してください。", "max_tokens": 100,},)</p>
print(response)
これにより、デプロイされたモデルにプロンプトが送信され、生成されたレスポンスが返されます。
MLflowを使用したLLMの評価
評価は、LLMのパフォーマンスと動作を理解する上で非常に重要です。MLflowは、LLMを評価するための包括的なツールを提供します。ビルトインメトリックとカスタムメトリックの両方を含みます。
LLMの評価の準備
LLMをmlflow.evaluate()で評価するには、モデルが以下の形式である必要があります:
MLflowのPyFuncモデルインスタンスまたはログされたMLflowモデルのURI。
入力文字列を受け取り、単一の文字列を出力するPython関数。
MLflowデプロイメントエンドポイントのURI。
モデルをNoneに設定し、評価データにモデル出力を含めます。
ログされたMLflowモデルを使用する例を見てみましょう:
import mlflow
import openai
<p>with mlflow.start_run():
system_prompt = "次の質問に簡潔に答えてください。"
logged_model_info = mlflow.openai.log_model(
model="gpt-3.5-turbo",
task=openai.chat.completions,
artifact_path="model",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": "{question}"},
],
)</p>
<p># 評価データの準備
eval_data = pd.DataFrame({
"question": ["機械学習とは何か?", "ニューラルネットワークを説明してください。"],
"ground_truth": [
"機械学習は、システムが経験から学び、改善することを可能にするAIのサブセットです。",
"ニューラルネットワークは、生物のニューラルネットワークに着想を得た計算システムで、相互に接続されたノードが情報を処理し、伝達します。",
]
})</p>
<p># モデルの評価
results = mlflow.evaluate(
logged_model_info.model_uri,
eval_data,
targets="ground_truth",
model_type="question-answering",
)</p>
<p>print(f"評価メトリック: {results.metrics}")
この例では、OpenAIモデルをログし、評価データを準備し、MLflowのビルトインメトリックを使用してモデルを評価します。
カスタム評価メトリック
MLflowでは、LLM評価用にカスタムメトリックを定義することができます。レスポンスの専門性を評価するカスタムメトリックの作成例を見てみましょう:
from mlflow.metrics.genai import EvaluationExample, make_genai_metric
<p>professionalism = make_genai_metric(
name="professionalism",
definition="正式で適切なコミュニケーションスタイルの尺度。",
grading_prompt=(
"回答の専門性を0から4のスケールで評価してください。\n"
"0: 非常にカジュアルまたは不適切\n"
"1: カジュアルだが敬意を持って\n"
"2: 中程度のフォーマル\n"
"3: 専門的で適切\n"
"4: 非常にフォーマルで熟練者向け"
),
examples=[
EvaluationExample(
input="機械学習とは何か?",
output="機械学習は、システムが経験から学び、改善することを可能にするAIのサブセットです。",
score=4,
justification="回答は正式で簡潔です。",
),
EvaluationExample(
input="ニューラルネットワークを説明してください。",
output="ニューラルネットワークは、生物のニューラルネットワークに着想を得た計算システムで、相互に接続されたノードが情報を処理し、伝達します。",
score=4,
justification="回答は正式で簡潔です。",
)
],
model="openai:/gpt-3.5-turbo-16k",
parameters={"temperature": 0.0},
aggregations=["mean", "variance"],
greater_is_better=True,
)</p>
<p># カスタムメトリックを評価に使用
results = mlflow.evaluate(
logged_model_info.model_uri,
eval_data,
targets="ground_truth",
model_type="question-answering",
extra_metrics=[professionalism]
)</p>
<p>print(f"専門性スコア: {results.metrics['professionalism_mean']}")
このカスタムメトリックは、GPT-3.5-turboを使用してレスポンスの専門性をスコア付けし、LLM自体を評価に利用する方法を示しています。
高度なLLM評価テクニック
LLMがより洗練されると、評価方法も進化します。MLflowを使用した高度な評価方法を見てみましょう。
リトリーバル増強生成(RAG)評価
RAGシステムは、リトリーバルベースのモデルと生成モデルを組み合わせたものです。RAGシステムの評価には、リトリーバルコンポーネントと生成コンポーネントの両方を評価する必要があります。ここでは、RAGシステムを設定し、MLflowを使用して評価する方法を説明します:
from langchain.document_loaders import WebBaseLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
<p># ドキュメントの読み込みと前処理
loader = WebBaseLoader(["https://mlflow.org/docs/latest/index.html"])
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)</p>
<p># ベクターストアの作成
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(texts, embeddings)</p>
<p># RAGチェーンの作成
llm = OpenAI(temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever(),
return_source_documents=True
)</p>
<p># 評価関数
def evaluate_rag(question):
result = qa_chain({"query": question})
return result["result"], [doc.page_content for doc in result["source_documents"]]</p>
<p># 評価データの準備
eval_questions = [
"機械学習とは何か?",
"ニューラルネットワークを説明してください。",
"MLflowの主なコンポーネントは何か?",
]</p>
<p># MLflowを使用した評価
with mlflow.start_run():
for question in eval_questions:
answer, sources = evaluate_rag(question)</p>
<p>mlflow.log_param(f"question", question)
mlflow.log_metric("num_sources", len(sources))
mlflow.log_text(answer, f"answer_{question}.txt")</p>
<p>for i, source in enumerate(sources):
mlflow.log_text(source, f"source_{question}_{i}.txt")</p>
<p># カスタムメトリックのログ
mlflow.log_metric("avg_sources_per_question", sum(len(evaluate_rag(q)[1]) for q in eval_questions) / len(eval_questions))
この例では、LangChainとChromaを使用してRAGシステムを設定し、MLflowを使用して評価し、質問、回答、取得したソース、およびカスタムメトリックをログします。
import mlflow
from langchain.text_splitter import CharacterTextSplitter, TokenTextSplitter
<p>def evaluate_chunking_strategy(documents, chunk_size, chunk_overlap, splitter_class):
splitter = splitter_class(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
chunks = splitter.split_documents(documents)</p>
<p>with mlflow.start_run():
mlflow.log_param("chunk_size", chunk_size)
mlflow.log_param("chunk_overlap", chunk_overlap)
mlflow.log_param("splitter_class", splitter_class.__name__)</p>
<p>mlflow.log_metric("num_chunks", len(chunks))
mlflow.log_metric("avg_chunk_length", sum(len(chunk.page_content) for chunk in chunks) / len(chunks))</p>
<p># リトリーバルのパフォーマンスを評価(簡略化)
correct_retrievals = sum(1 for _ in range(100) if simulate_retrieval(chunks))
mlflow.log_metric("retrieval_accuracy", correct_retrievals / 100)</p>
<p># 戦略を評価
for chunk_size in [500, 1000, 1500]:
for chunk_overlap in [0, 50, 100]:
for splitter_class in [CharacterTextSplitter, TokenTextSplitter]:
evaluate_chunking_strategy(documents, chunk_size, chunk_overlap, splitter_class)</p>
<p># 結果を比較
best_run = mlflow.search_runs(order_by=["metrics.retrieval_accuracy DESC"]).iloc[0]
print(f"ベストなチャンキング戦略: {best_run['params.splitter_class']} with size {best_run['params.chunk_size']} and overlap {best_run['params.chunk_overlap']}")