Upgrade to Pro — share decks privately, control downloads, hide ads and more …

テンポ感よく会話するために - Romi の応答高速化の技術 (MIXI Tech Design Conference 2024)

HAL
March 21, 2024

テンポ感よく会話するために - Romi の応答高速化の技術 (MIXI Tech Design Conference 2024)

MIXI Tech Design Conference 2024 での登壇資料です。
会話 AI ロボット Romi の応答の高速化の技術として、App サーバー・インフラと、 AI の高速化について書いています。

HAL

March 21, 2024
Tweet

More Decks by HAL

Other Decks in Technology

Transcript

  1. ©MIXI 2 自己紹介 • 信田 春満(のぶた はるみつ) @halhorn
 • 大学


    ◦ 〜2012: 京都大学大学院情報学研究科
 ▪ 認知発達ロボティクス
 ▪ X(Twitter) 会話 bot 「にせほるん」 
 • MIXI
 ◦ 2013〜2016: SNS mixi
 ◦ 2017〜: Romi - 雑談対話ロボットの新規事業
 ▪ Romi 最初のエンジニア
 ▪ 現エンジニアリングマネージャー
 • 趣味
 ◦ ホルン
 ◦ クライミング
 ◦ 写真
 ◦ 鳥

  2. ©MIXI 7 全体構成 お は よ う 会話 Server おはよう

    元気ー? App Server AI Server App Server Selector Priority Group AskAgain Priority Group ScenarioGraph (汎用ルール ) Priority Group しりとり しりとり しりとり しりとり しりとり Priority Group ChatRomi (AI) AI Server
  3. ©MIXI 13 プロファイリング • プロファイリング:実行時間の解析を行うこと ◦ あるコードが呼び出された回数 ◦ あるコードの実行時間 •

    python なら cProfile など • 解析のコツ ◦ 解析のログを残す ▪ cProfile なら Jupyter Notebook 上で解析するなど ◦ 初回の実行ではなく2回目以降の実行をプロファイリング ▪ 初回実行はキャッシュが効かない ▪ ほとんどのユーザー体験に関わるのは 2回目以降のアクセス速度 ◦ 同じリクエストを毎回送る
  4. ©MIXI 14 Romi で実際遅かったところ • データソースアクセス ◦ Neptune ◦ DynamoDB

    ◦ RDS ◦ etc… • AI 処理 • その他 インフラ・Appサーバー編 AI編
  5. ©MIXI 16 高速化の方針 • 機能を犠牲にしない ◦ 「高速化する関係で XX はできなくなります・・」はできるだけしない ◦

    高速化のかわりにたまにバグりますをしない • 保守性を犠牲にしない ◦ コードの可読性を犠牲にしない ▪ 高速化のために何らかの状態を持ち回してクラス間が密結合・・とかしない ◦ 直感的じゃない挙動を極力さける ◦ ビジネスロジックを書くときに高速化の詳細を考えなくても良くする ▪ データソース層を扱うライブラリに高速化を隠蔽する
  6. ©MIXI 17 時間がかかる部分の構造 • ほとんどが「繰り返し呼ばれる」こと ◦ ユーザープロフィール ◦ 記憶 ◦

    実機の状態 ◦ etc… Bot Selector Priority Group AskAgain Priority Group ScenarioGraph (汎用ルール ) Priority Group しりとり しりとり しりとり しりとり しりとり Priority Group ChatRomi (AI) Romi の中身は独立した多数の bot それぞれがデータソースにアクセス ルールベースエンジン ScenarioGraph は 独立したルールの集合体
  7. ©MIXI 18 時間がかかる部分の構造 • ほとんどが「繰り返し呼ばれる」こと ◦ ユーザープロフィール ◦ 記憶 ◦

    実機の状態 ◦ etc… Bot Selector Priority Group AskAgain Priority Group ScenarioGraph (汎用ルール ) Priority Group しりとり しりとり しりとり しりとり しりとり Priority Group ChatRomi (AI) Romi の中身は独立した多数の bot それぞれがデータソースにアクセス ルールベースエンジン ScenarioGraph は 独立したルールの集合体 独立性を保ったまま高速化したい
  8. ©MIXI 20 キャッシュ • データソース層へのアクセスをメモ • 次回同じリクエストが来たときにメモを返す ◦ 低速なデータソース層へのアクセスが減らせる •

    データソース更新時にキャッシュクリアするのが重要 DB App キャッシュ DB App キャッシュ 遅い! 遅い! 初回 二回目 メモ! メモを返す
  9. ©MIXI 22 キャッシュの場所1:プロセス • サーバーのプロセス内にキャッシュ ◦ 単に変数にキャッシュ ◦ python なら

    functools.lru_cache など • メリット ◦ 手軽。超高速。 • デメリット ◦ キャッシュクリアは実質不可 ▪ 複数のサーバーに複数のプロセスでサーバーは稼働 ▪ すべてのサーバーでキャッシュクリアはできない ◦ プロセス毎に初回アクセスはキャッシュが効かない • 使い所:サーバーデプロイ後は変わらないデータ ◦ 設定ファイル ◦ DB データのなかで一度作られたら変更が無いもの ◦ 天気予報など一度出たら基本かわらないもの ▪ ただしリクエスト(キャッシュキー)に日付を入れておく必要あり App Server App Server App Server Process1 Process2 Process3 Process4 Cache
  10. ©MIXI 23 キャッシュの場所2:キャッシュサーバー • キャッシュ専用サーバー ◦ AWS ElastiCache (Memcached) など

    ◦ 安全のためデプロイ時は全キャッシュクリアする • メリット ◦ キャッシュクリアできる ◦ 1度キャッシュしたものがプロセス関係なくキャッシュが効く • デメリット ◦ キャッシュクリアをちゃんと面倒みる必要あり ▪ 「クラスAでキャッシュ貼ってたけどクラス Bが DB 更新しちゃった」とかで事故 ◦ プロセスキャッシュなどに比べるとちょっとだけ遅い • 使い所:キャッシュクリアが簡単でユーザー共通で使われるデータ ◦ 管理ツールで変更できる設定 ▪ 多くが KVS で設定値を管理 ◦ 大量には呼ばれない場所 App Server App Server App Server Cache Server Cache
  11. ©MIXI 24 キャッシュの場所3:リクエスト • リクエストコンテキストにキャッシュを保存 ◦ リクエストコンテキスト:1回の API リクエストの処理の間だけ有効な値 ◦

    サーバーならそのリクエスト、 JobQueue なら1つの Job の間 etc. • メリット ◦ リクエスト中しか残らないので、キャッシュクリアをあまり考えなくていい ◦ プロセスキャッシュと同じで超高速 • デメリット ◦ リクエストの中の最初のアクセスではキャッシュが効かない • 使い所:1リクエスト内で何度も呼ばれる場所 ◦ 会話ロジックでは1会話リクエストで数十回呼ばれるデータなども ◦ DB コネクションなどもリクエストコンテキストにキャッシュ ▪ リクエストの間は同じコネクションを使い回す ▪ ほんとはプロセスキャッシュでも良いかも Romi で特徴 的! App Server Request Context Cache
  12. ©MIXI 25 キャッシュの場所:まとめ キャッシュの置き場所と使い所 • プロセス ◦ データが変更されないもの • キャッシュサーバー

    ◦ 管理ツールなどの変更される全体設定 • リクエスト ◦ 1リクエストで何度も呼ばれるもの App Server App Server App Server Process1 Process2 Process3 Process4 Cache App Server App Server App Server Cache Server Cache App Server Request Context Cache
  13. ©MIXI 26 その他の高速化もろもろ • 解析用メトリクスなどは一括送信 ◦ リクエストコンテキストを抜けるときに一括送信 ◦ ビジネスロジック書いてる人は何も気にしないで Metrics.send()

    とかを叩けば OK なしくみ • 同期的に実行しなくて良いものは JobQueue で遅延実行 ◦ 発話内容の解析とか • AWS 関係のクライアントはキャッシュしておくのが吉 ◦ AWS IoT Data のクライアントなど ▪ クライアント作るのは早いのに、その後の初回リクエストだけ遅い・・ • コールスタックの取得 ◦ inspect.stack() が数msかかる ▪ 100回呼ばれると 0.x秒かかる ◦ 呼び出し元がほしいだけなら inspect.currentframe() から親を取得 • 正規表現 ◦ 大量に呼ばれると時間がかかる(会話ルールは正規表現を多用) ◦ 正規表現を事前コンパイルする ◦ それでも遅い場合、単純な文字列比較で足切りしたり • 条件の処理順序 ◦ 複数の条件の AND の場合、遅い処理ほどあとに 会話が0.1秒速くなるならやる それ未満なら気が向いたら・・
  14. ©MIXI 28 去年からのアップデート:ChatRomi • パブリックな LLM をベースとして Romi 独自の会話データでファイン チューン

    ◦ 2024/03 現在は StableLM をベースにファインチューン ▪ 様々な LLM を試したが Romi の雑談会話と最もマッチするのは StableLM ▪ インストラクションに従う度合いは Llama2 が良いなど一長一短な面も ▪ 現在は Llama2 ベースで東工大などが学習させたの Swallow も検証中 ◦ データは Romi の理想の性格を考え人手で作られた会話データ ▪ チームのコントロール下で作られているため高品質 ◦ より具体的な会話、内容を理解した会話をするように!
  15. ©MIXI 31 LLM の高速化 • より強い GPU インスタンスを使う ◦ 最新の推論用

    GPU インスタンスを使う ◦ AWS で g4 -> g5 にすると2倍弱は速くなった • 推論モデルを変換する ◦ fp16 ◦ ONNX or TorchScript or vLLM etc. ▪ Romi チームでは現在 TorchScript を使用 • モデル構造の工夫 ◦ Medusa Head ◦ Speculative Sampling
  16. ©MIXI 32 LLM の高速化 • より強い GPU インスタンスを使う ◦ 最新の推論用

    GPU インスタンスを使う ◦ AWS で g4 -> g5 にすると2倍弱は速くなった • 推論モデルを変換する ◦ fp16 ◦ ONNX or TorchScript or vLLM etc. ▪ Romi チームでは現在 TorchScript を使用 • モデル構造の工夫 ◦ Medusa Head ◦ Speculative Sampling
  17. ©MIXI 33 高速化の工夫: Medusa Head 通常 1トークンずつ生成 LLM (Stable LM)

    バナナ cost: 1 1回トークン生成プロセスを回すのを cost: 1 とする
  18. ©MIXI 34 高速化の工夫: Medusa Head 通常 1トークンずつ生成 LLM (Stable LM)

    バナナ 食べ cost: 1 cost: 1 1回トークン生成プロセスを回すのを cost: 1 とする
  19. ©MIXI 35 高速化の工夫: Medusa Head 通常 1トークンずつ生成 LLM (Stable LM)

    バナナ 食べ よう cost: 1 cost: 1 cost: 1 1トークンずつ生成するの で時間がかかる
  20. ©MIXI 36 Medusa Head 続きの文章を先読みで予測することで高速化 高速化の工夫: Medusa Head LLM (Stable

    LM) バナナ Medusa Head 通常 1トークンずつ生成 LLM (Stable LM) バナナ 食べ cost: 1 cost: 1
  21. ©MIXI 37 Medusa Head 続きの文章を先読みで予測することで高速化 高速化の工夫: Medusa Head LLM (Stable

    LM) バナナ Medusa Head 通常 1トークンずつ生成 LLM (Stable LM) バナナ 食べ よう よ cost: 1 cost: 1 cost: 1
  22. ©MIXI 38 Medusa Head 続きの文章を先読みで予測することで高速化 高速化の工夫: Medusa Head LLM (Stable

    LM) バナナ Medusa Head 通常 1トークンずつ生成 LLM (Stable LM) バナナ 食べ よう よ 早いけど 精度低 cost: 1 cost: 1 cost: 1
  23. ©MIXI 39 高速化の工夫: Speculative Sampling Speculative Sampling (正確ではないがざっくりしたイメージ ) 遅くて高精度なモデルと速くて低精度なモデルを組み合わせ高速化

    Target Model (遅いけど高精度) StableLM Draft Model (速いけど低精度) Stable LM + MedusaHead cost: 1 バナナ を食べ Medusa Head Medusa Head で 並列生成
  24. ©MIXI 40 高速化の工夫: Speculative Sampling Speculative Sampling (正確ではないがざっくりしたイメージ ) 遅くて高精度なモデルと速くて低精度なモデルを組み合わせ高速化

    Target Model (遅いけど高精度) StableLM Draft Model (速いけど低精度) Stable LM + MedusaHead Draft Model の結果から 並列生成 バナナ を食べ Medusa Head を食べ たい cost: 1 cost: 1 Medusa Head で 並列生成
  25. ©MIXI 41 高速化の工夫: Speculative Sampling Speculative Sampling (正確ではないがざっくりしたイメージ ) 遅くて高精度なモデルと速くて低精度なモデルを組み合わせ高速化

    Target Model (遅いけど高精度) StableLM Draft Model (速いけど低精度) Stable LM + MedusaHead Draft Model の結果から 並列生成 バナナ を食べ Medusa Head を食べ たい cost: 1 cost: 1 Medusa Head で 並列生成 合計 cost 2 で 3 トークン生成
  26. ©MIXI 42 高速化の工夫: Speculative Sampling Speculative Sampling (正確ではないがざっくりしたイメージ ) 遅くて高精度なモデルと速くて低精度なモデルを組み合わせ高速化

    Target Model (遅いけど高精度) StableLM Draft Model (速いけど低精度) Stable LM + MedusaHead Draft Model の結果から 並列生成 バナナ いちご Medusa Head を食べ みかん cost: 1 cost: 1 Medusa Head で 並列生成
  27. ©MIXI 43 高速化の工夫: Speculative Sampling Speculative Sampling (正確ではないがざっくりしたイメージ ) 遅くて高精度なモデルと速くて低精度なモデルを組み合わせ高速化

    Target Model (遅いけど高精度) StableLM Draft Model (速いけど低精度) Stable LM + MedusaHead Draft Model の結果から 並列生成 バナナ いちご Medusa Head を食べ みかん cost: 1 cost: 1 Medusa Head で 並列生成 合計 cost 2 で 2 トークン生成
  28. ©MIXI 44 高速化の工夫:結果 • Medusa Head + Speculative Sampling で精度維持しつつ約20%高速化

    • その他 TorchScript 化や g5 インスタンスの採用などでも高速化
  29. ©MIXI 45 まとめ • インフラ・Appサーバー ◦ ボトルネック調査:プロファイリング ◦ キャッシュ ▪

    キャッシュ on プロセス ▪ キャッシュ on キャッシュサーバー ▪ キャッシュ on リクエストコンテキスト ◦ 一括送信、JobQueue による遅延実行、その他細々したもの • AI サーバー・モデル ◦ より強い推論 GPU インスタンスを使う ◦ モデルを TorchScript などに変換 ◦ Medusa Head ◦ Speculative Sampling