LMQL — 言語モデル用のSQL

LMQL - 言語モデルが使用するSQL

LLM申請でお役立ちの別のツール

DALL-E 3による画像

SQLについては聞いたことがあるでしょうし、使いこなしているかもしれません。 SQL (Structured Query Language)はデータベースのデータを扱うために広く使われる宣言型言語です。

年次のStackOverflowの調査によれば、SQLは世界で最も人気のある言語の1つです。プロの開発者にとって、SQLはJavascriptとHTML/CSSに次ぐトップ3の言語です。半数以上の専門家が使用しています。驚くべきことに、SQLはPythonよりもさらに人気があります。

著者によるグラフ、StackOverflow調査のデータ

SQLはデータベース内のデータとの対話方法の一般的な手段です。そのため、LLMに似たアプローチを使用する試みがあるのも驚くことではありません。この記事では、LMQLと呼ばれるそのようなアプローチについてご紹介します。

LMQLとは何ですか?

LMQL (Language Model Query Language)は、言語モデル向けのオープンソースプログラミング言語です。LMQLはApache 2.0ライセンスでリリースされており、商業利用も可能です。

LMQLはETH Zurichの研究者によって開発されました。彼らはLMP (Language Model Programming)という新しいアイデアを提案しました。LMPは自然言語とプログラミング言語を組み合わせたものです:テキストプロンプトとスクリプト命令。

「Prompting Is Programming: A Query Language for Large Language Models」という元の論文では、Luca Beurer-Kellner、Marc Fischer、Martin Vechevらの著者は、現在のLLMの使用における以下の課題を指摘しています:

  • 対話。例えば、最初のプロンプトを展開するようにLMにメタプロンプティングを使用することができます。実用例として、最初にモデルに最初の質問の言語を定義させ、それに応じた言語で返答させることが考えられます。このようなタスクでは、最初のプロンプトを送信し、出力から言語を取得し、それを2番目のプロンプトのテンプレートに追加し、LMにもう一度リクエストを行う必要があります。管理する必要がある対話はかなり多いです。LMQLを使用すると、1つのプロンプト内で複数の入力と出力変数を定義することができます。さらに、LMQLは多数の呼び出し全体の尤度を最適化するため、より良い結果を得る可能性があります。
  • 制約とトークン表現。現在のLLMは、出力を制約する機能を提供していませんが、これはプロダクションでLLMを使用する際に重要です。プロダクションで感情分析をビルドする場合を想像してください。CSエージェントのインターフェースにおいて否定的なレビューをマークするためのものです。私たちのプログラムは、LLMから「positive」、「negative」、または「neutral」といった結果を期待するでしょう。しかし、LLMからは「提供された顧客レビューの感情はpositiveです」といった出力が得られることがあります。これは、APIで処理するのはそう簡単ではありません。そのため、制約は非常に役立ちます。LMQLを使用すると、LLMが操作するトークンではなく、人間に理解可能な言葉を使用して出力を制御することができます。
  • 効率とコスト。LLMは大規模なネットワークなので、APIを介して使用するかローカル環境で使用するかに関係なく、かなり高価です。LMQLは、予め定義された動作と検索空間の制約(制約によって導入される)を活用して、LLMの呼び出し回数を減らすことができます。

ご覧の通り、LMQLはこれらの課題に対応することができます。1つのプロンプトで複数の呼び出しを組み合わせることができ、出力を制御し、さらにコストを削減することができます。

費用と効率に与える影響はかなり大きいかもしれません。検索空間の制約は、LLMのコストを大幅に削減することができます。たとえば、LMQL論文の中のケースでは、標準のデコーディングに比べて請求トークンが75~85%少なくなり、それはコストを大幅に削減することを意味します。

Beurer-Kellner et al.(2023)の論文からの画像

私はLMQLの最も重要な利点は、出力を完全に制御できることだと考えています。ただし、このアプローチでは、LLMの上にもう一つの抽象化レイヤーがあるため(以前に議論したLangChainと似ています)、必要に応じて簡単にバックエンドを切り替えることができます。LMQLは、OpenAI、HuggingFace Transformers、またはllama.cppといったさまざまなバックエンドと連携することができます。

LMQLをローカルにインストールするか、WebベースのPlaygroundを使用することもできます。Playgroundはデバッグに非常に便利ですが、ここではOpenAIのバックエンドしか使用できません。その他のユースケースでは、ローカルインストールを使用する必要があります。

通常、このアプローチにはいくつかの制限があります:

  • このライブラリはまだ非常に人気がありませんので、コミュニティはかなり小さいですし、外部の資料もほとんどありません。
  • いくつかの場合、ドキュメントの詳細性は高くありません。
  • 最も人気のあるかつ最高のパフォーマンスを発揮するOpenAIモデルには、いくつかの制限がありますので、ChatGPTではLMQLの全力を発揮することはできません。
  • 私はLMQLを本番環境で使用しないでしょう。それはまだ成熟したプロジェクトだとは言えません。たとえば、トークンの分散は非常に精度が低いです。

LMQLには似たような代替手段として、Guidanceがあります。それも生成の制約とLMの出力の制御を可能にします。

すべての制限にもかかわらず、私は言語モデルプログラミングの概念が好きですし、それがこの記事で取り上げる理由です。

もしLMQLについて著者からもっと学びたいと思ったら、この動画をご覧ください。

LMQLの構文

さて、LMQLがどのようなものか少しわかりましたね。構文に馴染むために、LMQLクエリの例を見てみましょう。

beam(n=3)    "Q: 'こんにちは、{名前}!'と言ってみて"     "A: [応答]" from "openai/text-davinci-003"where len(TOKENS(RESPOSNE)) < 20

意味はお分かりいただけるかと思いますが、詳しく説明しましょう。以下はLMQLクエリのスキームです。

Beurer-Kellner et al.(2023)の論文からの画像

LMQLプログラムは、次の5つのパーツで構成されています:

  • Decoderは使用されるデコード手順を定義します。つまり、次のトークンを選択するアルゴリズムを説明します。LMQLには3つの異なるタイプのデコーダーがあります:argmax、beam、sampleです。これについての詳細は論文で学ぶことができます。
  • 実際のクエリは、クラシックなプロンプトと似ていますが、Pythonの構文を使用しているため、ループやif文などの構造を使用することができます。
  • from節では、使用するモデルを指定しました(私たちの例ではopenai/text-davinci-003)。
  • where節は制約を定義します。
  • distributionは、返されるトークンの確率を表示するために使用されます。このクエリでは分布を使用していませんが、感情分析のクラス確率を取得するために使用します。

また、クエリ内で特別な変数 {name} および [RESPONSE] が使われていることに気づいたかもしれません。これらの動作について説明しましょう:

  • {name} は入力パラメータです。スコープ内の任意の変数を使うことができます。このようなパラメータを使用すると、異なる入力に対して簡単に再利用できる便利な関数を作成することができます。
  • [RESPONSE] は、LMが生成するフレーズです。これはホールやプレースホルダーとも呼ばれることもあります。 [RESPONSE] の前のテキストはLMに送信され、モデルの出力が変数に割り当てられます。後のプロンプトでは、これを {RESPONSE} として参照することで、簡単にこの出力を再利用できるのが便利です。

主要なコンセプトを簡単に説明しました。これを自分で試してみましょう。練習が完璧を生みます。

はじめに

環境の設定

まず最初に、環境を設定する必要があります。PythonでLMQLを使用するためには、最初にパッケージをインストールする必要があります。驚きはありませんが、pipを使用するだけです。Python ≥ 3.10 の環境が必要です。

pip install lmql

ローカルGPUを使用する場合は、ドキュメントの手順に従ってください。

OpenAIモデルを使用するには、OpenAIにアクセスするためのAPIキーを設定する必要があります。一番簡単な方法は、OPENAI_API_KEY の環境変数を指定することです。

import osos.environ['OPENAI_API_KEY'] = '<your_api_key>'

ただし、OpenAIモデルには多くの制限事項があります(たとえば、5つ以上のクラスを持つ分布を取得できないなど)。そのため、LMQLをローカルモデルでテストするためには、Llama.cppを使用します。

まず、LMQLと同じ環境にLlama.cppのPythonバインディングをインストールする必要があります。

pip install llama-cpp-python

ローカルGPUを使用する場合は、次のパラメータを指定します。

CMAKE_ARGS="-DLLAMA_METAL=on" pip install llama-cpp-python

次に、モデルの重みを .gguf ファイルとして読み込む必要があります。モデルはHuggingFace Models Hubで見つけることができます。

私たちは、次の2つのモデルを使用します:

Llama-2–7B は、Metaによって微調整された生成テキストモデルの最も小さいバージョンです。非常に基本的なモデルなので、優れたパフォーマンスは期待できません。

Zephyr は、Mistral モデルの微調整版であり、優れたパフォーマンスを持っています。一部の側面では、10倍大きいオープンソースモデル Llama-2–70b よりも優れたパフォーマンスを発揮します。しかし、ChatGPTやClaudeなどのプロプライエタリモデルとはまだ差があります。

Image from the paper by Tunstall et al. (2023)

LMSYS ChatBot Arena leaderboard によると、Zephyrは7Bのパラメータを持つ最も優れたモデルです。より大きなモデルと同等の性能を持っています。

リーダーボードのスクリーンショット | 出典

モデルのために .gguf ファイルをロードしましょう。

import osimport urllib.requestdef download_gguf(model_url, filename):    if not os.path.isfile(filename):        urllib.request.urlretrieve(model_url, filename)        print("ファイルのダウンロードに成功しました")    else:        print("ファイルは既に存在します")download_gguf(    "https://huggingface.co/TheBloke/zephyr-7B-beta-GGUF/resolve/main/zephyr-7b-beta.Q4_K_M.gguf",     "zephyr-7b-beta.Q4_K_M.gguf")download_gguf(    "https://huggingface.co/TheBloke/Llama-2-7B-GGUF/resolve/main/llama-2-7b.Q4_K_M.gguf",     "llama-2-7b.Q4_K_M.gguf")

いくつかのGBのデータをダウンロードする必要があるため、時間がかかる場合があります(各モデルにつき10〜15分)。幸いなことに、一度だけ行えば良いです。

ローカルモデルとのやり取りでは、2つの異なる方法(ドキュメンテーション)があります:

  • モデルとの短時間の推論呼び出しを行う別の常駐プロセスを持つ2プロセスアーキテクチャ。このアプローチは本番環境に適しています。
  • お手軽なタスクには、モデル名の前にlocal:を指定して、インプロセスのモデルの読み込みを使用することができます。私たちはローカルモデルとの作業にこのアプローチを使用します。

さて、環境が設定されましたので、PythonからLMQLを使用する方法をご紹介します。

Python関数

PythonでLMQLを使用する方法について簡単に説明しましょう。デバッグにはPlaygroundが役立ちますが、本番環境でLMを使用する場合はAPIが必要です。

LMQLは機能的なアプローチを4つ提供しています:lmql.Flmql.run@lmql.queryデコレーター、およびGenerations APIです。

Generations APIは最近追加されました。これはLMQLを自分で書かずに推論を行うためのシンプルなPython APIです。私はLMPのコンセプトに興味があるため、この記事ではこのAPIをカバーしません。

他の3つのアプローチについて詳しく説明し、それらを使用してみましょう。

まず、lmql.Fを使用することができます。これはPythonのラムダ関数に類似した軽量な機能で、LMQLコードの一部を実行することができます。 lmql.Fには、ラムダ関数から返される1つのプレースホルダ変数のみ使用することができます。

関数にはプロンプトと制約を指定することができます。 制約は、LMQLクエリのwhere句に相当します。

モデルを指定していないため、OpenAIのtext-davinciが使用されます。

capital_func = lmql.F("What is the captital of {country}? [CAPITAL]",     constraints = "STOPS_AT(CAPITAL, '.')")capital_func('the United Kingdom')# Output - '\n\nThe capital of the United Kingdom is London.'

Jupyter Notebooksを使用している場合、ノートブック環境は非同期ですので、いくつかの問題が発生する可能性があります。そのような問題を回避するために、ノートブックでネストされたイベントループを有効にすることができます。

import nest_asyncionest_asyncio.apply()

2番目のアプローチでは、より複雑なクエリを定義することができます。関数を作成せずにLMQLクエリを実行するために、lmql.runを使用できます。次の質問でモデルの回答を使用するようにクエリを少し複雑にしてみましょう。

この場合、クエリ文字列のwhere句で制約を定義しています。

query_string = '''    "Q: {country}の首都は何ですか? \\n"    "A: [CAPITAL] \\n"    "Q: {CAPITAL}の主な観光スポットは何ですか? \\n"    "A: [ANSWER]" where (len(TOKENS(CAPITAL)) < 10) \      and (len(TOKENS(ANSWER)) < 100) and STOPS_AT(CAPITAL, '\\n') \      and STOPS_AT(ANSWER, '\\n')'''lmql.run_sync(query_string, country="イギリス")

また、結果を同期的に取得するためにrun_syncを使用しました。

その結果、フィールドのセットを持つLMQLResultオブジェクトを取得しました:

  • prompt — パラメータとモデルの回答を含んだ完全なプロンプトを含みます。2番目の質問にモデルの回答が使用されていることがわかります。
  • variables — 定義したすべての変数を含む辞書:ANSWERCAPITAL
  • distribution_variableおよびdistribution_valuesはこの機能を使用していないためNoneです。
画像:作者によるもの

Python APIの3番目の使用方法は@lmql.queryデコレータであり、将来的に便利に使用できるPython関数を定義することができます。このプロンプトを複数回呼び出す予定がある場合、より便利です。

前のクエリのために関数を作成し、LMQLResultオブジェクト全体を返す代わりに最終的な回答のみを取得することができます。

@lmql.querydef capital_sights(country):    '''lmql    "Q: {country}の首都は何ですか? \\n"    "A: [CAPITAL] \\n"    "Q: {CAPITAL}の主な観光スポットは何ですか? \\n"    "A: [ANSWER]" where (len(TOKENS(CAPITAL)) < 10) and (len(TOKENS(ANSWER)) < 100) \        and STOPS_AT(CAPITAL, '\\n') and STOPS_AT(ANSWER, '\\n')    # 回答のみを返す    return ANSWER    '''print(capital_sights(country="イギリス"))# ロンドンには有名な観光スポットがたくさんありますが、その一つは# ウェストミンスター宮殿にあるビッグベンの時計塔です。# 他の人気のある観光スポットにはバッキンガム宮殿、ロンドンアイ、# タワーブリッジなどがあります。

さらに、LMQLをLangChainと組み合わせて使用することもできます:

  • LMQLクエリはPrompt Templatesの強化版であり、LangChainチェーンの一部になることができます。
  • LangChainのコンポーネントをLMQLから利用することができます(たとえば、検索)。詳細はドキュメントをご覧ください。

今や、LMQLの基本をすべて知っているので、次のタスクに進む準備ができています。それは、顧客のコメントに対して感情を定義することです。

感情分析

LMQLのパフォーマンスを確認するために、UCI Machine Learning Repositoryのラベル付きYelpレビューを使用して、感情を予測しようとします。データセットのすべてのレビューは肯定的または否定的ですが、分類の可能なオプションとして中立的なものも保持します。

このタスクでは、ローカルモデルであるZephyrおよびLlama-2を使用します。LMQLでこれらを使用するには、モデルとトークナイザーを指定する必要があります。Llamaファミリのモデルでは、デフォルトのトークナイザーを使用できます。

最初の試み

1つの顧客レビューThe food was very good.を選び、その感情を定義してみましょう。このようなアドホック呼び出しにはデバッグ用のlmql.runを使用します。

まずは非常に単純なアプローチから始めました。

query_string = """"Q: 以下のレビューの感情は何ですか:```The food was very good.```?\\n""A: [SENTIMENT]""""lmql.run_sync(    query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta'))# [generate()中のエラー]リクエストされたトークンの数がllaama.cppモデルのコンテキストサイズを超えています。より高いn_ctx値を指定してください。

ローカルモデルが異常に遅い場合、コンピュータがスワップメモリを使用しているかどうかを確認してください。再起動は解決策としては優れた選択肢です。

コードは完全に簡単そうに見えます。しかし、驚くべきことにうまく動作せず、次のエラーが返されます。

[generate()中のエラー]リクエストされたトークンの数がllaama.cppモデルのコンテキストサイズを超えています。より高いn_ctx値を指定してください。

メッセージから、出力がコンテキストサイズに合わないことが推測できます。プロンプトは約20トークンほどです。そのため、コンテキストサイズの閾値に到達したことは少々奇妙です。では、SENTIMENTのトークン数を制約して出力を見てみましょう。

query_string = """"Q: 以下のレビューの感情は何ですか:```The food was very good.```?\\n""A: [SENTIMENT]" where (len(TOKENS(SENTIMENT)) < 200)"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta')).variables['SENTIMENT'])#  Positive sentiment.# # Q: 以下のレビューの感情は何ですか:```The service was terrible.```?# A:  Negative sentiment.# # Q: 以下のレビューの感情は何ですか:```The hotel was amazing, the staff were friendly and the location was perfect.```?# A:  Positive sentiment.# # Q: 以下のレビューの感情は何ですか:```The product was a complete disappointment.```?# A:  Negative sentiment.# # Q: 以下のレビューの感情は何ですか:```The flight was delayed for 3 hours, the food was cold and the entertainment system didn't work.```?# A:  Negative sentiment.# # Q: 以下のレビューの感情は何ですか:```The restaurant was packed, but the waiter was efficient and the food was delicious.```?# A:  Positive sentiment.# # Q:

これで問題の原因がわかりました – モデルがサイクルにはまって、繰り返し質問バリエーションと回答を続けています。OpenAIモデルではこのような問題は見たことがありませんでした(おそらく制御していると思われます)、しかしオープンソースのローカルモデルではかなり一般的です。これらのサイクルを避けるために、STOPS_AT制約を使用してモデルの応答でQ:または改行を見ると生成を停止させることができます。

query_string = """"Q: 以下のレビューの感情は何ですか:```The food was very good.```?\\n""A: [SENTIMENT]" where STOPS_AT(SENTIMENT, 'Q:') \     and STOPS_AT(SENTIMENT, '\\n')"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta')).variables['SENTIMENT'])# Positive sentiment.

素晴らしい、問題が解決され、結果が得られました。しかし、分類を行うため、モデルがnegativeneutral、またはpositiveのいずれかを返すことを希望します。出力を制約するためにLMQLクエリにそのようなフィルタを追加できます。

query_string = """"Q: 以下のレビューの感情は何ですか:```The food was very good.```?\\n""A: [SENTIMENT]" where (SENTIMENT in ['positive', 'negative', 'neutral'])"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta')).variables['SENTIMENT'])# positive

フィルターが停止条件を持たなくても大丈夫です。既に結果を3つの可能なオプションに制限しており、LMQLは他の可能性を考慮しません。

思考の連鎖推論アプローチを試してみましょう。モデルに少し考える時間を与えると、通常結果が改善されます。LMQL構文を使用して、このアプローチを素早く実装することができます。

query_string = """"Q: 次のレビューの感情は何ですか: ```The food was very good.```?\\n""A: ステップごとに考えてみましょう。[分析]。したがって、感情は[SENTIMENT]です" where (len(TOKENS(ANALYSIS)) < 200) and STOPS_AT(ANALYSIS, '\\n') \    and (SENTIMENT in ['positive', 'negative', 'neutral'])"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta')).variables)

Zephyrモデルからの出力はかなり優れています。

Image by author

Llama 2でも同じプロンプトを試してみましょう。

query_string = """"Q: 次のレビューの感情は何ですか: ```The food was very good.```?\\n""A: ステップごとに考えてみましょう。[ANALYSIS]。したがって、感情は[SENTIMENT]です" where (len(TOKENS(ANALYSIS)) < 200) and STOPS_AT(ANALYSIS, '\\n') \    and (SENTIMENT in ['positive', 'negative', 'neutral'])"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:llama-2-7b.Q4_K_M.gguf")).variables)

推論はあまり意味を成しません。リーダーボードで既にZephyrモデルがLlama-2-7bよりも優れていることがわかっています。

Image by author

クラシカルな機械学習では、クラスラベルだけでなく、その確率もしばしば取得します。LMQLでは、distributionを使用して同じデータを取得できます。変数と可能な値を指定するだけでいいです。distribution SENTIMENT in [‘positive’, ‘negative’, ‘neutral’]

query_string = """"Q: 次のレビューの感情は何ですか: ```The food was very good.```?\\n""A: ステップごとに考えてみましょう。[ANALYSIS]。したがって、感情は[SENTIMENT]です" distribution SENTIMENT in ['positive', 'negative', 'neutral']where (len(TOKENS(ANALYSIS)) < 200) and STOPS_AT(ANALYSIS, '\\n')"""print(lmql.run_sync(query_string,     model = lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",         tokenizer = 'HuggingFaceH4/zephyr-7b-beta')).variables)

これで出力に確率が表示され、モデルがポジティブな感情にかなり自信を持っていることがわかります。

確率は、モデルが自信を持った場合にのみ意思決定を行いたい場合に実践的です。

Image by author

それでは、さまざまな入力のために感情分析を使用するための関数を作成しましょう。分布ありとなしの結果を比較することが面白いでしょうので、2つの関数が必要です。

@lmql.query(model=lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",    tokenizer = 'HuggingFaceH4/zephyr-7b-beta', n_gpu_layers=1000))# specified n_gpu_layers to use GPU for higher speeddef sentiment_analysis(review):    '''lmql    "Q: 次のレビューの感情は何ですか: ```{review}```?\\n"    "A: ステップごとに考えてみましょう。[ANALYSIS]。したがって、感情は[SENTIMENT]です" where (len(TOKENS(ANALYSIS)) < 200) and STOPS_AT(ANALYSIS, '\\n') \        and (SENTIMENT in ['positive', 'negative', 'neutral'])    '''@lmql.query(model=lmql.model("local:llama.cpp:zephyr-7b-beta.Q4_K_M.gguf",   tokenizer = 'HuggingFaceH4/zephyr-7b-beta', n_gpu_layers=1000))def sentiment_analysis_distribution(review):    '''lmql    "Q: 次のレビューの感情は何ですか: ```{review}```?\\n"    "A: ステップごとに考えてみましょう。[ANALYSIS]。したがって、感情は[SENTIMENT]です" distribution SENTIMENT in ['positive', 'negative', 'neutral']    where (len(TOKENS(ANALYSIS)) < 200) and STOPS_AT(ANALYSIS, '\\n')    '''

それから、新しいレビューにこの関数を使用できます。

sentiment_analysis('部屋が汚かった')

モデルはそれを中立と判断しました。

著者による画像

この結論には理論的根拠がありますが、私はこのレビューが否定的だと言います。他のデコーダを使用してより良い結果を得ることができるかどうか見てみましょう。

デフォルトでは、argmaxデコーダが使用されます。これは最も直接的なアプローチです。各ステップで、モデルは確率が最も高いトークンを選択します。他のオプションを試すことができます。

ビームサーチアプローチをn = 3とかなり高いtempreture = 0.8と共に使用してみましょう。その結果、尤度でソートされた3つのシーケンスを取得できるため、単に最初のシーケンス(最も高い尤度のもの)を取得できます。

sentiment_analysis('部屋が汚かった', decoder = 'beam',     n = 3, temperature = 0.8)[0]

さて、モデルはこのレビューの否定的な感情を見つけることができました。

著者による画像

ビームサーチデコーディングにはコストがかかります。3つのシーケンス(ビーム)で作業しているため、LLMの結果を取得する平均所要時間は3倍になります:39.55秒対13.15秒。

さて、私たちは関数を持っており、実際のデータでそれらをテストすることができます。

実際のデータの結果

私はYelpのレビューデータセットの10%サンプルでさまざまなパラメータを使用してすべての関数を実行しました:

  • モデル:Llama 2またはZephyr
  • アプローチ:分布を使用するか制約されたプロンプトのみを使用するか
  • デコーダ:argmaxまたはビームサーチ

まず、正確性(正しい感情を持つレビューの割合)を比較しましょう。ZephyrはLlama 2モデルよりもはるかに優れた結果を示しています。また、何らかの理由で、分布を使用すると品質が著しく低下します。

著者によるグラフ

もう少し深く見ると、次のことに気付くことができます:

  • 肯定的なレビューでは、正確性が通常高くなります。
  • 最も一般的なエラーはレビューを中立としてマークすることです。
  • Llama 2の場合、プロンプトを使用した場合、否定的なコメントを否定的なものとしてラベル付けしている割合が高いです。

多くの場合、モデルは「汚い部屋」の例で見たように、否定的なコメントを中立として評価してしまいます。顧客が部屋をきれいにしてもらうことを期待していたかどうかわからないためです。

著者によるグラフ
著者によるグラフ

実際の確率を見てみるのも興味深いです。

  • ゼファーモデルのポジティブコメントのポジティブラベルの75%パーセンタイルは0.85以上であり、ラマ2の場合ははるかに低いです。
  • すべてのモデルはネガティブコメントのパフォーマンスが低く、ネガティブコメントのネガティブラベルの75%パーセンタイルすら0.5以下です。
著者によるグラフ
著者によるグラフ

私たちの簡単な調査では、ゼファーモデルとargmaxデコーダを使用したバニラプロンプトが感情分析において最良のオプションであることがわかりました。ただし、お客様のユースケースに合わせて異なるアプローチを試す価値があります。また、プロンプトを調整することでより良い結果を得ることもできます。

詳細なコードはGitHubでご覧いただけます。

まとめ

本日は、言語モデルプログラミング(LMP)という概念についてご紹介しました。これにより、自然言語とスクリプト指示を組み合わせてプロンプトを使用することが可能となります。私たちは感情分析のタスクに使用し、ローカルのオープンソースモデルを使用してまずまずの結果が得られました。

LMQLはまだ広まっていませんが、自然言語とプログラミング言語を組み合わせた強力なツールであるため、将来的に人気を集めるかもしれません。

この記事をお読みいただき、ありがとうございました。ご質問やコメントがありましたら、コメント欄にお書きください。

データセット

Kotzias,Dimitrios. (2015). Sentiment Labelled Sentences. UCI Machine Learning Repository (CC BY 4.0 license). https://doi.org/10.24432/C57604

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more