見出し画像

LLM APIの安定したレスポンスを求めて - Azure OpenAI Service PTUの速度検証 -

こんにちは。PKSHA Technology の AI Solution 事業本部にてアルゴリズムエンジニアを務めている古川と申します。本記事では、Azure OpenAI Service を使用する上で購入可能な PTU(provisioned throughput units)について、レスポンスの速度検証を行なった結果についてご紹介します。

古川 拓磨|AI Solution 事業本部 アルゴリズムエンジニア
東京大学大学院 工学系研究科 修士課程を修了。大学院では、微細加工技術を用いた神経回路網の研究に従事。新卒として PKSHA Technology へ参画し、金融業や製造業関連のプロジェクトにおいて、時系列予測や自然言語処理などの技術を用いたアルゴリズムの社会実装に従事。


PTU の概要

LLM アプリケーションでは、多くの場合 LLM API の呼び出しがレスポンス時間のボトルネックとなります。例えば、チャットアプリケーションで LLM を使うケースでは、LLM のレスポンスを待つ間、ユーザーは画面上に待機することになるため、遅いレスポンスは UX を悪化させ、ユーザーの離脱リスクを高めます。また、音声対話においては、自然な会話速度を実現するための速度要求はさらに厳しいものになります。

Microsoft の公式ドキュメントによれば、LLM のレイテンシは主に (1)モデル、(2)プロンプトのトークン数、(3)生成トークン数、(4)デプロイとシステムの全体的な負荷 に左右されます。
手っ取り早いレイテンシ改善策としては (1)モデルの切り替えを行い、軽量で高速なモデル(GPT 3.5 Turbo, GPT-4o miniなど)を使用することが挙げられます。しかし、複雑なタスクでは、より高度なモデルが必要になることがあります。また、(2)(3)トークン数もタスクによってはコントロールが難しいことがあります。例えば、LLM を用いた代表的な技術である RAG(検索拡張生成)では、プロンプトに参照資料の情報を含める必要があり、入力トークン数を減らすアプローチには限界があります。(4)は唯一タスクと独立にレイテンシをコントロール可能なアプローチであり、オンプレミスやクラウドインスタンスにモデルを自力でデプロイする場合、マシンスペックの向上が有効な選択肢となります。一方、Azure OpenAI Service のようなクラウドサービスで API として提供される LLM の場合、異なるアプローチが必要です。この点について調査を進めたところ、Provisioned Throughput Units (PTU)というオプションの存在を知り、その詳細について調べることにしました。

Microsoft の公式ドキュメントには、PTU の特徴として下記の 3 つが記載されています。

予測可能なパフォーマンス:均一なワークロードに対して安定した最大待ち時間とスループット。
予約済み処理機能:デプロイでスループット量が構成されます。 デプロイされると、スループットは、使用の有無にかかわらず利用できます。
コスト削減:高スループットワークロードは、トークンベースの使用と比較したときのコスト削減につながる場合があります。

UX の観点で重要なのは、1 つ目の「予測可能なパフォーマンス」です。
標準デプロイではサービス利用率が高い時間帯にレイテンシが大幅に増加することがありますが、「最大待ち時間」と記載の通り、レイテンシが極端に増加するケースを PTU では抑制できることがポイントです。

参照:Azure OpenAI Service のプロビジョニング スループット|Azure OpenAI services

本記事では、レイテンシが UX に大きな影響を与えるユースケースの一つである、チャットを想定したシンプルな文章生成タスクと、プロンプトトークン長の増大によるレイテンシの増加が課題となりがちな RAG のタスクの 2 種類を実験として設定し、標準デプロイと PTU  のそれぞれについてレイテンシを比較しました。

実験条件

検証対象となるデプロイとして、以下の二つを比較しました。

  • GPT-4-Turbo 標準デプロイ EastUS-2(以降、4-Turbo Standard と表記)

  • GPT-4-Turbo PTU EastUS-2(以降、4-Turbo Provisioned と表記)

計測の指標としては、下記の 2 つになります。

  • 指標 1:リクエスト送信時刻から、最初のチャンクが返ってくるまでの経過時間

  • 指標 2:1 トークンあたりの生成時間

    • 本実験においては、$${k}$$番目のチャンクについて、到達時刻を$${t_k}$$、生成トークン長$${N_k}$$として、下記と定義しました。

$${ (t_k - t_{k-1}) / N_k }$$

実験の前提条件

今回はすべての実験において stream = True とすることで、文章全体ではなく、チャンクを検証の単位としました。生成トークン数が多いほど生成に時間がかかるため、時間にばらつきがある場合に、生成されるトークン数の増減によるものなのか、計算リソースの問題なのかを区別することが目的です。
stream = True の条件下では、最初に空文字 “” のチャンクが返ってきて、その次に 1 トークン以上の長さを持つ実体のチャンクが返ってくる仕様になっているようです。今回は、1 トークン以上の長さを持つ初めての実体のチャンクを「First Chunk」と定義しました。
また、サービスの利用率が時間帯によって異なることから、レイテンシも時間帯によって変動することが想定されます。下記の 2 つの目的により、実験は複数の異なる時間帯で実施しました。

  • リクエスト時間の偏りによる比較上のバイアスを減らす

  • PTU と標準デプロイのそれぞれについて、時間帯によるレイテンシの変動を比較する

実験の詳細

レイテンシを計測するにあたって実施した実験は以下の 2 種類です。

実験 1:一般的な文章生成

- 目的:時間帯ごとのレイテンシ傾向を観察する
- プロンプト
 - System:You are a helpful AI assistant.
 - User:What is the meaning of life?
- 試行回数
 - 8 つの異なる時間帯(3 時間おき)で実験を実施。
 - それぞれの時間帯で 1 デプロイあたり 100 回のリクエストを投げる(10 個ずつ並列に送信 × バッチごとに 10 秒のインターバルを設置)
 - 片方のデプロイに時間的な偏りが生まれないように、PTU と標準デプロイは交互にリクエストを送信

実験 2:RAG(検索拡張生成)

- 目的:入力トークン長が変動する際のレイテンシ傾向を観察する
- プロンプト
 - System: You are a helpful AI assistant.
 - User:
  - 固定部分(テンプレート)

## 指示
あなたの仕事は、提供された参照資料の情報のみを使用して質問に答えることです。
参照資料として、質問に関連する複数のWikipediaの記事についてタイトルとテキストを提供します。

参照資料の情報をもとに、質問に対する回答を次のJSONフォーマットで作成してください。
JSON以外の項目は出力しないでください。
```json
{{
    "answer": ["answer_1", "answer_2", ...],
    "thought_process": "describe thought process",
}}
```

## 参照資料
{context}

## 質問
{question}

  - 変数部分:JAQKET:クイズを題材にした日本語 QA データセットを用いて、5 種類の QA を対象に RAG プロンプトを作成。
   - 質問(question):質問を入力。
   - 参照資料(context):正例となるcontextを必ず1つ以上含めた上で、負例のcontextの個数を変動させ、入力トークン長を増減。

- 試行回数
 - 4 つの異なる時間帯(6 時間おき)で実験を実施。
 - それぞれの QA(5 種類)について、正例の個数 1・2、負例の個数 1・2・4・8・16 のそれぞれについて 5 回ずつ試行(計 $${5\times2\times5\times5=250}$$回)。
 - 片方のデプロイに時間的な偏りが生まれないように、PTU と標準デプロイは交互にリクエストを送信

実験結果

比較 1:レイテンシの全体的な傾向

まず、実験 1:一般的な文章生成 において収集した全てのリクエスト(各デプロイについて $${N=800}$$ )を対象に、指標 1:リクエスト送信時刻から、最初のチャンクが返ってくるまでの経過時間 をヒストグラムにしたのが下記です。縦軸が各ビンごとのリクエスト数、横軸が経過時間を表します。また、経過時間は裾の重い分布を持つため、横軸は対数スケールにしました。

PTU では最初のチャンクまでのレイテンシが、平均・最大値ともに大幅に抑えられています。標準デプロイでは 2.0 秒以内の返答は全体の 54 %しかありませんが、PTU では 91 %が 2 秒以内に返ってきています。また、5 秒以上の返答も、標準デプロイでは 800 回中 21 回と 2 %以上発生しているのに対し、PTU ではたったの 3 回(0.3 %)に収まっています。

比較 2:レイテンシの時間的傾向の違い

2.1 最初のチャンクが返ってくるまでの経過時間

実験 1:一般的な文章生成について、指標 1:最初のチャンクが返ってくるまでの経過時間 を時間帯ごとに、箱ひげ図としてプロットしたグラフが下記です。横軸がリクエストした時間帯、縦軸が最初のチャンクまでの経過時間です。赤い三角は時間帯ごとのレイテンシの平均値を表します。

8 つすべての時間帯において、PTU のレイテンシは平均して標準デプロイより小さいです。
標準デプロイでは、レスポンスが平均して最速であった 9:00 の 1.83 秒と比較して、サービス利用率が高いと考えられる日本時間 18:00 あたりで、レイテンシが平均して 1.59 倍の 2.93 秒に増加しました。一方で PTU のレイテンシは、最速であった 3:00 の 1.40 秒と比較して、最大の平均レイテンシは 15:00 の 1.69 秒にとどまり、レイテンシの増加は 1.20 倍に抑えられました。このことから、PTU の方が時間帯ごとのレイテンシの変動が抑えられていることがわかります。

2.2 1 トークンあたりの生成時間の平均

同じく実験 1 について、指標 2:1 トークンあたりの生成時間 の平均を時間帯ごとに観察したのが下記のグラフです。各データポイントの縦線は平均値の標準誤差を指しています。

標準デプロイでは、1 トークンあたりの生成時間の平均が最小であった 9:00 の 33 msと比較して、最大の 18:00 では 59 msとなり、約 1.76 倍に増加しています。一方で PTU では、最速であった 9:00 の 25 msと比較して、最大をとった 21:00 は 29 msであり、差は 1.19 倍にとどまっています。このことから、最初のチャンク到達までの経過時間だけではなく、チャンク間の平均的なインターバルも、標準デプロイと比較してPTUでは安定していることがわかります。

比較 3:入力トークン長とレイテンシの傾向

3.1 最初のチャンク到達までのレイテンシと、入力トークン長の関係

次に、実験 2:RAG について、指標 1:最初のチャンクが返ってくるまでの経過時間 を入力トークン長ごとにプロットしたのが下記になります。なお、入力トークン長は、pandas の round 関数で 3 桁に偶数丸めを行った値ごとに統計量を算出しています。

PTU においてレイテンシが平均的に小さく、外れ値も少ないという傾向はこれまでの実験と同様に見られました。
また、入力トークン長とレイテンシの関係は次のようになりました。まず、標準デプロイでは、経過時間の平均が最小である 500 トークン以下のリクエストについて 6.01 秒をとり、最大である 4000 トークンの周辺で平均 7.16 秒かかりました。一方で PTU については、平均の最小が 4.36 秒、最大が 5.34 秒でした。

3.2 最後のチャンク到達までのレイテンシと、入力トークン長の関係

これまでの結果により、最初のチャンク到達までの時間や、1 トークンあたりの生成時間については PTU の速さを確認できました。一方で実務上はストリーミングを有効にせず、全てのチャンク生成が終了するまで待機することも多いと思います。そこで、最後のチャンク到達までのレイテンシを RAG について比較しました。
最後のチャンク到達までのレイテンシは、最終的に生成されたトークン数にしたがって増加しますが、PTU と標準デプロイの速度を比較するという目的においては、下記三つの理由で大きな差は生まれないと考えました。

  • 同じ 4-turbo モデルを対象としていること

  • 各プロンプト条件について、5 回× 4 つの時間帯= 20 個ずつのサンプルを取得していること

  • 正例を必ず 1 つ以上含めた上で、負例の個数を変動させて入力トークン長を増減しているため、生成トークン数そのものの増減は少ないと想定

実際に、今回の RAG の実験において最終的に生成されたトークン数の分布をプロットすると下記のようになります。標準デプロイと PTU を比較して、生成トークン数の平均値には大きな差がないことを確認できました。

横軸にプロンプトのトークン長(3 桁に偶数丸め)をとり、縦軸に最後のチャンク到達までのレイテンシをとったものが下記のグラフになります。

実務上ではよく使われると想定される、stream を使用しない場合のレイテンシについて、下記の二つのことがわかりました。

  • どのプロンプトトークン長においても、PTU のレイテンシが平均して小さく、大きなレイテンシを取る外れ値の個数が少ない

  • 3 桁に丸めを行った際のプロンプトトークン長が 0 の場合と比較して、レイテンシが最大であるトークン長 4000 の場合では、標準デプロイ・PTU ともに 1.4〜1.5 倍程度であった

考察

PTU デプロイの大きな特徴として、レスポンスが標準デプロイより定常的に早いことが挙げられます。
実験 1 で行った 800 回のリクエストについて、PTU は平均して最初のチャンクまで 1.54 秒であったのに対し、標準デプロイでは 2.31 秒かかるため、平均すると 1.5 倍程度レスポンスが早くなっています。また、時間帯ごとの変動という観点で見ると、サービス利用率が高かった 18:00 時点では、その差は 2.1 倍になります。
また、最初のチャンクが到達するまで 5 秒以上かかるリクエストが、標準デプロイでは 2 %以上発生しているのに対し、PTU では 0.4 %以内に抑えられることは、平均値だけではなく、レイテンシの大きな外れ値の発生頻度を PTU で大幅に抑制できることを示しています。特にユーザーが LLM の応答時間の間、画面を見ながら待機する UX では最大レイテンシは致命的になり得るので、PTU の活用が期待できるユースケースの一つであると考えられます。

大量にリクエストを送れば、プロビジョニングされた処理容量を一時的に使い切ってしまうこともあります。その際は、PTU から 429 のステータスコードが返されるので、下記に挙げられるような方法によりアプリケーションに合わせたアクセス制御を行うことが可能です。

  • レスポンスに含まれる retry-after-ms ヘッダー(下記に一部を抜粋)を見て、リトライの方針を決める。max_retries パラメータを指定すると、公式の SDK はデフォルトでこの値を利用した Exponential Backoff に基づくリトライポリシーを実装してくれているので、速度要求が厳しくない場合はこれをそのまま使用すれば良いでしょう。また、標準デプロイなど他のデプロイへの迂回をするのがより高速である場合があります。

"retry-after": "5", 
"retry-after-ms": "4442", 
"ms-azureml-model-error-reason": "too_many_tokens", 
"azure-openai-deployment-utilization": "101.75%",
  • 429 エラーが頻発する場合、待機やリトライによって標準デプロイ以上に遅くなりうるため、PTUの性能を最大限活用するためには十分なPTUを確保することが重要であると考えられます。

参照:Azure OpenAI Service でプロビジョニングされたデプロイの使用を開始する|Azure OpenAI Services

まとめ

今回は、Azure OpenAI ServiceのProvisioned Throughput Units(PTU)について、GPT-4-Turbo モデルを対象にレスポンスの速度検証を行いました。結果、PTU では実際にレイテンシの最大値が大きく抑えられ、時間帯によらず安定したスループットを持つことが示されました。
一方で、PTU は従量課金とは異なる料金体系を持つため、PTU の採用を検討する際は、予想されるリクエスト量が十分に大きいことが前提となります。リクエスト量が少ない場合や変動が大きい場合は、従量課金が適している可能性があります。
音声対話などリアルタイム性が求められる LLM アプリケーションや、素早いレスポンスを提供することが利益に直結しているようなサービスにおいて、比較的大規模に使われることがあらかじめ判明している場合、PTU は大きな価値を発揮すると考えられます。

―INFORMATION―
PKSHA Technology では、共に働く仲間を募集しています。このような技術に興味を持っていただけた場合は、採用サイトや Wantedly から応募やカジュアル面談が可能ですので、是非ご覧ください!

▼ 【26 年新卒】アルゴリズムエンジニア

【中途採用】アルゴリズムエンジニア

▼ カジュアル面談も受付中です!Wantedly はこちら