はじめに

ChatGPTやGPT-4をはじめとする大規模言語モデルの能力が大幅に向上し、自然言語処理の分野で多くの注目を集めています。これらのモデルを使うことで、今までは複雑な処理が必要だった質問応答や要約などのアプリを以前と比べて簡単に作り始められるようになりました。その使い方の例としては、社内にあるFAQや回答事例集、商品の説明書などに対し、単に検索するだけでなく、質問に対する回答や要約を生成して提示するようなことが考えられます。

質問応答や要約などのアプリを作る場合、Retriever-Reader、Retriever-Generatorと呼ばれるアーキテクチャがよく使われています。Retriever-Readerでは検索した文書(コンテキストと呼ぶこともある)から回答を抽出するのに対し、Retriever-Generatorでは検索した文書から回答や要約を生成します。いずれにせよ、ユーザーの与えたクエリに対して何らかの方法で文書を検索し、検索した文書をモデルに与えることで、応答を得ることになります。

これらのアーキテクチャでは、文書を検索するために、クエリや検索対象の文書を埋め込み(embedding)と呼ばれる手法を用いて数値ベクトルに変換してから関連度を計算することがよく行われています。この埋め込みを使った検索では、単なるキーワード検索とは違い、単語や文書の意味を考慮できるという利点があります。このようなことができるのは、埋め込み用のモデルが、似た意味の単語やテキストを似たようなベクトルに変換してくれるからです。

最近では、OpenAI APIを使ってアプリを開発できるフレームワークがいくつか存在するため、OpenAIの提供する埋め込みモデル(以下、OpenAI Embedding)を使ってテキストをベクトルに変換することも多いですが、OpenAI Embeddingは汎用的なモデルであるため、変換して得られた埋め込みが特定のドメインに適しているとは限りません。たとえば、医療や法律などの分野では、特有の用語や表現が多く、OpenAI Embeddingをそのまま使用するとうまく検索できない場合があると考えられます。

そこで本記事では、OpenAIの提供している埋め込みモデルから得たベクトルを特定のドメインに適した形式にチューニングする方法を紹介します。記事中では医療向けにチューニングしますが、同じ方法を他のドメイン向けに使うこともできます。まず、OpenAIの埋め込みモデルについて説明したあと、得られるベクトルをチューニングする方法を紹介します。これにより、医療ドメインにおいてより正確な質問応答や要約が作成できるようになることが期待されます。

OpenAIの埋め込みモデル

OpenAIのモデルはAPIを通じて提供されていますが、その中の1つに埋め込み用のモデルを提供しているエンドポイント(https://api.openai.com/v1/embeddings)があります。このエンドポイントに対してテキスト(input)と埋め込みに使うモデル名(model)を送ることで、指定したモデルを使って変換されたテキストの数値表現(embedding)を取得できます。具体的には、以下のようなリクエストとレスポンスになります。

リクエスト:

curl https://api.openai.com/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "input": "Your text string goes here",
    "model": "text-embedding-ada-002"
  }'

レスポンス:

{
  "data": [
    {
      "embedding": [
        -0.006929283495992422,
        -0.005336422007530928,
        ...
        -4.547132266452536e-05,
        -0.024047505110502243
      ],
      "index": 0,
      "object": "embedding"
    }
  ],
  "model": "text-embedding-ada-002",
  "object": "list",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5
  }
}

モデルとしては、いくつかの中から指定できますが、基本的にはtext-embedding-ada-002を指定しておけば問題ありません。モデルは大きく分けると第1世代と第2世代に分けられるのですが、本記事執筆時点では埋め込み用の第2世代のモデルはtext-embedding-ada-002だけです。このモデルは第1世代のモデルと比べて安く使うことができ、またテキストやコードの検索、類似度計算といったタスクでも高い性能が出ると報告されています(テキスト分類ではtext-similarity-davinci-001のほうが良い性能になる可能性があります)。

注意点として、モデルの入力長には最大値があるので、あまりにも長いテキストをそのまま与えることはできません。実用的には、テキストを一定の長さで分割した後、それぞれの埋め込みを作成して使うことになります。ちなみに、text-embedding-ada-002の最大入力長は8191トークンとなっています。トークン数について事前に調べたい場合は、tiktokenトークナイザーのデモを使うといいでしょう。

OpenAI APIから得られるベクトルのチューニング

本節では、OpenAI APIから得られたベクトルを特定のドメインに適した形式にチューニングする方法を紹介します。今回は医療向けにチューニングしますが、同じ方法を他のドメイン向けに使うこともできます。はじめに、チューニング用のモデルについて説明した後、チューニングに使うデータセットと評価方法について説明します。チューニングの観点は以下の2つです。

  • チューニングでどの程度性能が向上するのか
  • チューニング用データセットのサイズと性能の関係

今回、チューニングに使うモデルは以下の図に示すアーキテクチャをしています。まず、入力したテキストをOpenAI APIが提供する埋め込み用のモデルを使ってベクトルに変換します。この変換は事前に済ませておきます。次に、ベクトルに対して変換用の行列を乗算することで変換します。最後に類似度を計算し、正解と比較することで損失関数の値を計算します。そして、得られた勾配を使って、変換用の行列を更新します。学習が終われば、この行列を使ってベクトルを変換できるというわけです。

モデルの学習と評価をするためのデータセットとしては、Japanese-Clinical-STS(以下、臨床STS)[3]を使います。このデータセットは、臨床テキストの意味的な類似性の度合いを捉えるために使われます。以下にデータセットの例を示します。データセットには、2つの文とその類似度スコアが格納されています。類似度スコアは0から5までの整数値であり、5に近いほど2つの文が似ていることを表しています。この類似度スコアを正解データとしてモデルを学習します。評価は、正解のスコアと類似度予測モデルが予測したスコアのピアソン相関またはスピアマン相関で行います。

以下の表に、学習前後の埋め込みを評価した結果を示します。OpenAI APIから得られた埋め込み(OpenAI Embedding)との比較のために、事前学習済み言語モデル[4](JMedRoBERTa)をSiameseアーキテクチャ[5]でファインチューニングした場合の結果も示します。結果としては、学習前と比べて、学習後は臨床テキストの意味的な類似性をより捉えられているという結果となりました。ただし、学習後でもJMedRoBERTaをファインチューニングした場合には及んでいません。

モデル Pearson Spearman
OpenAI Embedding(学習前) 0.8162 0.8275
OpenAI Embedding(学習後) 0.8517 0.8495
JMedRoBERTa 0.8739 0.8710

次に、学習データセットのサイズと性能の関係を示します。学習データセットが0件の場合は、学習前の性能と一致するようになっています。結果を見ると、学習データセットのサイズが大きくなると性能が上がる傾向を確認できますが、100件程度でもまずまずの改善が見られます。

おわりに

本記事では、医療ドメインを対象として、OpenAIが提供する埋め込みをチューニングする方法を紹介しました。結果として、学習前と比べると学習後のほうが意味的な類似性をより捉えられるという結果になりました。とはいえ、意味的類似性タスクの性能向上が、関連文検索などの後段タスクの性能向上に必ずしもつながるわけではないという報告もあります[6][7]。そのため、後段タスクの性能改善につながっているかを定量的に確認する必要があります。

また、今回は意味的類似性のデータセットを使ってチューニングしましたが、分類などのデータセットを使ってチューニングすることもできます。たとえば、同じクラスのテキストからペアを作成した場合を正例、異なるクラスの場合は負例とすればいいでしょう。さらに、日本語のデータセットがない場合、他言語の同じような分野のデータセットを使ってチューニングした場合に、日本語での性能が向上するかも気になるところです。その検証については、また別の機会にします。

参考文献

  1. New and improved embedding model | OpenAI
  2. Embeddings | OpenAI Documentation
  3. Semantic Textual Similarity in Japanese Clinical Domain Texts Using BERT
  4. JMedRoBERTa: 日本語の医学論文にもとづいた事前学習済み言語モデルの構築と評価
  5. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks
  6. 文間意味的類似度のベンチマークタスクと実応用タスクの乖離
  7. Why is sentence similarity benchmark not predictive of application-oriented task performance?