記事検索

検索ワードを入力してください。
Sky Tech Blog
LLMの​推論を​スピードアップ!TensorRT Model Optimizerで​投機的デコードを​試してみよう

LLMの​推論を​スピードアップ!TensorRT Model Optimizerで​投機的デコードを​試してみよう

NVIDIAのTensorRT Model Optimizerを利用して、LLMの推論速度を向上させる「投機的デコード」を試す方法について解説します。EAGLEを用いた具体的な実装手順や、推論速度の比較結果などを客観的に紹介します。

「LLMの推論速度、もう少し速くならないかな…」
LLMの開発やサービス提供において、推論速度は常に気になるポイントですよね。

今回は、そんな課題を解決する選択肢の一つとして注目されている「投機的デコード」について、NVIDIAのTensorRT Model Optimizerを使って簡単に試す方法をまとめてみました。

TensorRT Model Optimizerって、​どんな​ツール?

TensorRT Model Optimizerは、NVIDIAが提供するAIモデル最適化のためのライブラリです。
量子化や枝刈りといった、モデルをより速く、より効率的に動かすための様々な機能が提供されています。そして名前の通り、TensorRT(NVIDIAが開発したAI向けの最適化ツール)で扱いやすい形にモデルを整えてくれます。

公式サイト

出典:TensorRT Model Optimizer

高速化の​キーポイント、​「投機的デコード」とは?

「投機的デコード」は、LLMの応答速度を上げるための一つのテクニックです。

まず、軽量な「ドラフトモデル」がトークンをいくつか先読みして生成します。その後ろから、賢くて精度の高い「ターゲットモデル」が予測が合っているかどうか答え合わせをしながらついていきます。

もし予測が間違っていたら、その地点でターゲットモデルが修正してくれるので、モデル本来の精度を保ったまま高速化が期待できます。

この仕組みは、Google Researchのブログにある動画がとてもわかりやすいです。
(ページの下の方に動画があります)

参考:Looking back at speculative decoding
出典:Looking back at speculative decoding

TensorRT Model Optimizerで​選べる​2つの​アプローチ

TensorRT Model Optimizerでは、現在2つの投機的デコード手法がサポートされています。

1. Medusa

Medusaは、ベースモデルの最後に小さな予測ヘッド(MLPヘッド)を複数追加して、未来のトークンを並行して予測する手法です。

  • ベースモデルの構造はそのままに、少しのパラメータを追加するだけ
  • ドラフトモデルを別で用意しなくてよい

2. EAGLE

EAGLEは、ベースモデルの中間層から得られる特徴量(隠れ状態)を使い、軽量なTransformerデコーダが次のトークン列を予測する手法です。

  • モデルの内部情報(特徴量)を使うため、より精度の高い予測が期待できる
  • ドラフトモデルは軽量なTransformerブロック

出典:Medusa
出典:EAGLE

やってみよう!​TensorRT Model Optimizerで​投機的デコード

では、実際にTensorRT Model Optimizerで投機的デコードを使ってみましょう。
今回は、より精度が期待できるEAGLEをTinyLlama-1.1Bに適用する手順を見ていきます。

※実行にはTensorRT Model OptimizerやTensorRT-LLMの環境構築が必要ですが、今回の記事では割愛します。

1. EAGLEモジュールの付与と学習

まず、ベースとなるモデルにEAGLEモジュールを追加します。

from copy import deepcopy
from transformers import AutoModelForCausalLM, AutoTokenizer
import modelopt.torch.speculative as mtsp

# ベースモデルを読み込み
model = AutoModelForCausalLM.from_pretrained(model_name, dtype=torch.bfloat16, device_map="cuda")

# EAGLEモジュールの設定をモデルに合わせて更新
eagle_config = deepcopy(mtsp.EAGLE1_DEFAULT_CFG)
eagle_config["config"]["eagle_architecture_config"].update({
    "hidden_size": model.config.hidden_size,
    "vocab_size": model.config.vocab_size,
    # ... その他モデルに合わせた設定
})
model = mtsp.convert(model, [("eagle", eagle_config["config"])])

次に、追加したEAGLE部分を学習させます。(今回は学習済みのEAGLEヘッドがなかったので、自分で学習させてみました)
学習するのはEAGLE部分だけなので、Hugging FaceのTrainerをそのまま活用できます。

import modelopt.torch.opt as mto
from transformers import Trainer, TrainingArguments

# EAGLEモジュールのみを学習対象に
for name, param in model.named_parameters():
    if "eagle" not in name:
        param.requires_grad = False

mto.enable_huggingface_checkpointing()

# 学習の実行
training_args = TrainingArguments(
    output_dir="eagle_tinyllama_v2",
    num_train_epochs=3,
    # ... その他学習パラメータ
)
trainer = Trainer(model=model, args=training_args, train_dataset=dataset)
trainer.train()
trainer.save_model("eagle_tinyllama_v2")

学習データには、ultrachat_200kの10,000サンプルを使用しています。

出典:ultrachat_200k

2. TensorRT-LLMエンジンのビルド

学習したモデルを、TensorRT-LLMで動く「エンジン」形式に変換します。
EAGLEを使ったモデルの場合、 --speculative_decoding_mode eagle というオプションを指定するのがポイントです。

# チェックポイントへの変換
python3 -m tensorrt_llm.commands.convert_checkpoint \
    --model_dir eagle_tinyllama_v2_hf \
    --output_dir trtllm_eagle_ckpt \
    --dtype float16 \
    --speculative_decoding_mode eagle

# エンジンのビルド
trtllm-build \
    --checkpoint_dir trtllm_eagle_ckpt \
    --output_dir trtllm_eagle_engine \
    --gemm_plugin float16 \
    --max_batch_size 1 \
    --speculative_decoding_mode eagle \
    --max_draft_len 63

3. 推論

推論は、TensorRT-LLMを使って行います。DecodingConfig に EagleConfig を渡す必要があるので注意です。

import tensorrt_llm.bindings.executor as tllm

# EAGLE用の設定を追加
eagle_config = tllm.EagleConfig(use_dynamic_tree=True, dynamic_tree_max_topK=10)
decoding_config = tllm.DecodingConfig(
    decoding_mode=tllm.DecodingMode.Eagle(),
    eagle_config=eagle_config,
)
executor_config = tllm.ExecutorConfig(max_beam_width=1, decoding_config=decoding_config)

# エンジンを読み込んで推論を実行
executor = tllm.Executor("trtllm_eagle_engine", tllm.ModelType.DECODER_ONLY, executor_config)
request = tllm.Request(input_ids, max_tokens=100, end_id=eos_id, pad_id=eos_id)
request_id = executor.enqueue_request(request)
responses = executor.await_responses(request_id)

結果​:速度は​どれくらい​変わった?

さて、気になる結果です。EAGLEを使った場合と使わなかった場合で、トークン生成の速度を比べてみました。

  • 使用GPU: NVIDIA GeForce RTX 4050 Laptop GPU (6GB)
  • プロンプト: "Sea otters is" (ラッコは…)

トークン生成速度[token/s]:

投機的デコードなし 投機的デコードあり 倍率
87.7 107.0 1.22x

他のプロンプトでも試したところ、約1.2~1.4倍の高速化を確認できました。

ただし、生成する文章が非常に短い場合など、シナリオによってはドラフト生成のオーバーヘッドで逆に遅くなるケースもありました。ある程度まとまった文章を生成する際に、特に効果を発揮する手法と言えそうです。

ちなみに生成された文章は下記でした。いい感じですね。

Sea otters is a fascinating and unique species that has adapted to 
life in the Pacific Northwest. They are known for their unique fur, 
which is a combination of brown and white, and their ability to live 
in the water for extended periods.

日本語訳

ラッコは、太平洋岸北西部の環境に適応した、魅力的でユニークな種です。
茶色と白が混ざり合った独特の毛皮と、長時間水中で生活できる能力で知られています。

最後に

いかがでしたでしょうか。
今回は、TensorRT Model Optimizerを使って投機的デコード(EAGLE)による推論の高速化を試してみました。

LLMの推論高速化には様々なアプローチがありますが、投機的デコードは非常に強力な選択肢の一つだと思います。
皆さんも、ぜひお手元のモデルで試してみてはいかがでしょうか。この記事が、参考になれば幸いです。


\シェアをお願いします!/
  • X
  • Facebook
  • LINE
キャリア採用募集中!

入社後にスキルアップを目指す若手の方も、ご自身の経験を幅広いフィールドで生かしたいベテランの方も、お一人おひとりの経験に応じたキャリア採用を行っています。

Sky株式会社のソフトウェア開発や製品、採用に関するお問い合わせについては、下記のリンクをご確認ください。
お問い合わせ
ホーム