TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

LoRAアダプターのサービングを実際に計測してみる:スループットコスト、アダプタースロット、実行時ロード

ステータス:ドラフト(2026-10-07)、実測記事です。 アダプターは性能テスト用に作成した ランダムな重みなので出力品質には意味がなく、速度とリソースの挙動のみを測定しました。計算したものは「計算」、測定できなかったものは「未実測」と表記しました。 作成ルール:実測データを基本とし、測定できなかったものは「未実測」と表記します。

目次

1. なぜLoRAをサービングするのか

用途ごとにモデルを微調整(ファインチューニング)すると、その分モデル全体をメモリにロードする必要があります。LoRAはベースの重みWをそのままにし、低次元の行列2つ(B、A)を学習して W + (α/r)·B·A に変更する方式であるため、 1つのベースモデルに小さなアダプターを複数アタッチし 、リクエストごとに異なるアダプターを使用できます。顧客別・業務別のモデルを1枚のGPUでサービス提供したい理由がここにあります。vLLMのドキュメントでは、アダプターをリクエスト単位で少ないオーバーヘッドでサービングできると説明されています。この記事では、その「少ない」がこの環境において何パーセントなのかを計測します。

2. 環境と方法

項目 値
GPU 8GBクラスのノートPC用GPU 1枚、他の作業なし
サーバー vLLM 0.31.0、Qwen3-1.7B(bf16)、 --max-model-len 4096, --max-num-seqs 64, --max-lora-rank 16
アダプター PEFTで作成したLoRA 3つ(a、b、c)。ランク8、対象はアテンションのq、k、v、oプロジェクション、 lora_B をシード値が異なるランダムな値(標準偏差0.02)で初期化
アダプターのサイズ 学習可能なパラメータ3,211,264個で、ベースモデル1,720,574,976個の 0.19%(測定)。bf16であれば約6.4MB(計算)
リクエスト 入力 Write a long story about a robot.、出力128トークン、温度0、 ignore_eos、リクエストごとにサーバーのモデル名でアダプターを選択
繰り返し 同じリクエストの束をまとめて送信し、総スループット(出力トークン数 ÷ かかった時間)を計算

同時リクエスト数にご注意ください。 この記事の表には「一斉に送信したリクエスト数」を記載しています(3個、18個、48個)。テストツールの引数名のせいで当初は「同時1、16」と呼んでいましたが、実際には3倍のリクエストを送信していることを確認し、修正しました。

アダプターがランダムなため、出力には意味がありません。アダプター行列のサイズと演算量は学習の有無とは無関係であるため、 速度とメモリの挙動は学習済みアダプターと同じであるとみなしますが、学習済みアダプターで確認はしていません(未実測)。

3. スループットのコスト

ベースサーバー(LoRAオフ)とLoRAを有効にしたサーバーに同じリクエストを送信しました。

一斉に送信したリクエスト数 サーバー リクエストが使用するモデル 総スループット ベース比 ITL中央値
3 LoRAオフ ベース 199 tok/s 基準 15ms
3 LoRAオン ベース(アダプターなし) 200 tok/s +0.5% 15ms
3 LoRAオン アダプター a 182 tok/s −8.5% 16ms
48 LoRAオフ ベース 2,667 tok/s 基準 17ms
48 LoRAオン ベース(アダプターなし) 2,664 tok/s −0.1% 17ms
48 LoRAオン アダプター a 2,190 tok/s −17.9% 19ms
48 LoRAオン a と b を交互に 2,323 tok/s −12.9% 20ms
48 LoRAオン a、b、アダプターなしを交互に 2,346 tok/s −12.0% 20ms

繰り返しテスト(各5回、同一サーバー)。 リクエスト48個(同時16の3倍)を、アダプターなし、アダプターa、アダプターaとbを交互に、の3つの条件で順序をシャッフルしながら5回ずつ送信しました(--max-loras 2).

条件 スループット(tok/s)、5回 中央値 ベース比
アダプターなし 2,647, 2,658, 2,669, 2,663, 2,667 2,663 基準
アダプター a 2,183, 2,398, 2,390, 2,391, 2,390 2,390 -10.3%
アダプター a と b を交互に 2,329, 2,330, 2,332, 2,329, 2,332 2,330 -12.5%

4. アダプタースロット:アダプター数が --max-loras を超えた場合

--max-loras は、 1つのバッチ内に含めることができる異なるLoRAの数です(デフォルトは1)。当初は「GPU上に同時にロードしておけるアダプターの数」と記載していましたが、この記事で使用したvLLM 0.31.0イメージのソース(vllm/config/lora.py)を直接確認したところ、説明文は「Max number of LoRAs in a single batch」となっており、CPU側に配置するアダプター数は別の --max-cpu-loras(デフォルトは max_loras と同じ値)でした。アダプター3個でリクエスト18個を同時に送信しました(各設定2回繰り返し。2回の値がほぼ同じであることが多かったですが、スロット2つのアダプターa、bは886と984で異なっていました)。

サーバー設定 アダプターなし アダプター a、b アダプター a、b、c
--max-loras 2 1,120 tok/s 886〜984 tok/s 529 tok/s
--max-loras 4 1,131 tok/s 986〜987 tok/s 950 tok/s

4-1. 同じテストをSGLangで行うと

同じモデルと、同じランダムなアダプター3個(rank 16、パラメータの0.19%)を使用して、SGLang 0.5.21のLoRA(--enable-lora --max-loras-per-batch N)を測定しました。

テスト SGLang vLLM(上記第3節、第4節)
同時16(リクエスト48個)、アダプターなし 2,544 tok/s(サーバー3回の中心値、2,533〜2,552) 2,664(LoRA有効サーバーのアダプターなしリクエスト)
同負荷、アダプター a 2,515 tok/s(-1.1%、サーバー3回の中心値、2,509〜2,518) 2,390 tok/s(-10.3%、5回の中央値)
リクエスト18個、アダプター2個を混合、スロット2 1,045 tok/s(アダプターなし 1,027) 886〜984 tok/s(アダプターなし 1,120)
リクエスト18個、アダプター3個を混合、スロット2 558 tok/s 529 tok/s
同テスト、スロット4 1,034 tok/s(サーバー3回の中心値、1,030〜1,038、初回テスト 1,045) 950 tok/s

5. 実行中にアダプターを適用するのにかかる時間

VLLM_ALLOW_RUNTIME_LORA_UPDATING=True でサーバーを立ち上げた後、 /v1/load_lora_adapter でアダプターcを追加しました。

項目 結果
ロードリクエストの応答 LoRA adapter 'c' added successfully、呼び出し全体0.18秒(リモートコマンド実行オーバーヘッドを含む)
ロード直後の最初のリクエスト 3つのリクエスト 182 tok/s、アダプターaと同じ速度

6. 本番環境への持ち帰り

  1. アダプターを使用するリクエストのスループットコストを事前に測定します。 この環境では8〜18%であり、モデルと同時実行性によって異なります。
  2. --max-loras を同時に登場するアダプターの数に合わせます。 スロットが不足すると半分程度の水準に低下します。
  3. アダプターのデプロイは軽量ですが、無制限のロードは危険です。 パイプラインで制御し、検証済みのものだけを適用します。
  4. LoRAを有効にしたままにしておくことのコストはありませんでした。 アダプターを使用しないリクエストには影響がありませんでした。
  5. 学習されたアダプターやより大きなモデルでは再度測定する必要があります。 この記事の数値は、小型モデル(1.7B)と4B-FP8の1点、ランダムアダプターから得られたものです。

7. 面接で聞かれそうな質問

外部の根拠:論文と公式資料で確認した内容

外部の数値はモデル、GPU、アダプターの構成が異なるため直接比較せず、傾向と桁数の一致のみを判定しました。

トピック 資料と確認した場所 確認した内容と条件 この記事との関係
LoRAのサイズ Hu他, 「LoRA: Low-Rank Adaptation of Large Language Models」, arXiv 2106.09685(ICLR 2022), 概要および4.2節 GPT-3 175Bで学習パラメータを最大10,000倍、チェックポイントを350GBから35MBに削減(ランク4、クエリとバリューの投影のみ適用)。推論遅延が増加しないということは W0 + BA で統合された単一のアダプターに対してのみ成立し、異なるアダプターを1つのバッチに混在させることは統合された状態では困難であると論文の限界に記載されている 支持。 我々のアダプターはベースモデルの0.19%(3,211,264個、モデル設定から計算して一致)。第3節の8.5〜17.9%の減少は、統合せずにリクエストごとに選択する方式のコスト
マルチアダプターサービングのスループット Chen他, Punica, MLSys 2024, arXiv 2310.18547, 第7節 図11。Sheng他, S-LoRA, MLSys 2024, arXiv 2311.03285, 第7.2節 表3 Punica: A100 80GB 1枚、Llama-2 7B・13B、ランク16。同じアダプターのみを使用する場合、バックボーン専用のvLLMよりも7Bが約8.4%、13Bが約12.2%低い(論文の数値から計算)かつトークンあたり約2msの追加遅延。S-LoRA: アダプターをホストメモリに置き、実行中のリクエストの分だけGPUに持ち込むことで、アダプターが5個から100個に増えてもスループットを維持、わずかな減少 限定的な支持。 アダプターを使用するリクエストのスループット減少と桁数が同じ。「スロット超過時の半分」に対応する外部数値はなく、S-LoRAはアクティブなアダプター数がコストを決定すると説明しており、この現象がvLLMの max_loras 構成に特有のものである可能性を示唆
--max-loras の意味 vLLM 0.31.0 ソース config/lora.py, v1/core/sched/scheduler.py(この記事で使用した画像から直接読み取り) 1つのバッチ内の異なるLoRAの数(デフォルト1)。制限に達すると他のアダプターのリクエストをスキップする。 max_cpu_loras は別個(デフォルトは max_lorasと同じ) 最初の記述を訂正。 上記第4節
オーバーヘッドとランタイムロード vLLMドキュメント 「LoRA Adapters」(2026-09-28表記) アダプターをリクエスト単位で少ないオーバーヘッドでサービングすると記載されており、定量的数値はない。 VLLM_ALLOW_RUNTIME_LORA_UPDATING は隔離された信頼できる環境でない限り本番環境で使用しないよう警告があり、具体的な理由は記載されていない 限定的な支持。 「少ないオーバーヘッド」はこの環境では8.5〜17.9%と小さくなかった

確認できなかったこと

参考資料

確認したバージョンと日付

2026-10-07基準。vLLM 0.31.0、PEFT 0.21.2、accelerate 1.15.0、Qwen3-1.7B(bf16)。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます