vLLM
LLMの高速化手法。
5. vLLM
paged_attentionを用いた手法
OSの仮想メモリとページングの仕組みを参考
SDPAのkeyとvalueの値を分割してテーブルに保存しておくことで、同じトークンが再度呼び出されたときに、都度計算することなく呼び出しだけで計算を完了させる手法
vLLMはPagedAttentionの導入によりKVキャッシュのボトルネックを改善することで高速化を実現するライブラリです。本来のAttentionではキーとバリューをKVキャッシュとしてGPUメモリに保持しており、そのサイズは出力文章の長さに依存します。出力文章長は事前にはわからないため、事前に過剰にGPUメモリを先取りしてメモリ効率が悪くなります。vLLMでは、入力トークンを一定の長さごとに分割してGPUメモリをジャストインタイムに保持することでGPUメモリ効率を向上させるPagedAttentionを導入しています。他にもContinuous Batchingによりバッチ処理の効率を上げる工夫がなされています。
さらに、vLLMという推論ライブラリはサーバにAIモデルをデプロイして実際にサービスに使う事を念頭に置いて設計されてるらしい。プロ向けのライブラリといった所か。CUDAで動作するのだが、WindowsやMacはサポートされてない。Linuxだけだ。Windowsから使いたければWSLが必要になる。vLLMはレイテンシ的には特にLlama.cppよりも優れてるというものでも無いようなので、単にチャットするだけなら別にLlama.cppで十分だろうが、vLLMが本領を発揮するのはバッチ推論においてである。バッチ推論とはつまり大量のプロンプトをまとめて投げつけて、まとめて処理する事だ。まとめて推論できるので一個一個チマチマ推論するより当然効率的になる。vLLMではページドアテンションという仕組みでバッチ推論をものすごく効率化している。実際試してみたところ、60個くらいのプロンプトをまとめて投げると8Bモデルで1000tpsくらいの物凄い爆速のスループットが出る事もあった。Llama.cppではせいぜい100tpsくらいしか出ないのでその速度の差は圧倒的である。 バッチ推論できるしメチャ速い。LLMサービングに使える。
https://scrapbox.io/files/66afd89c531a06001c42b615.png
具体例として、13Bパラメータを持つLLMを考えましょう。このモデルを40GBのメモリ環境で動作させる場合、モデルパラメータを格納するために約26GBのVRAMが必要となり、残りの14GBがKVキャッシュ用に割り当てられます。図6では、この環境で推論を行った際のバッチサイズに対するメモリ使用量とスループットが示されています。従来のシステム(Existing systems)では、バッチサイズが小さい段階でVRAMの容量が限界に達し、スループットも低くなっていることがわかると思います。 この図からわかるように、バッチ処理ではKVキャッシュの保存に割り当てられるスペースがスループットに直接影響を与えます。つまり、LLMのスループットは、メモリ容量に大きく依存するということです。詳細は後述しますが、vLLMではこのKVキャッシュを効率的に運用することで、メモリ使用を最適化し、より大きなバッチを高速に処理することが可能になりました。 つまり、KVキャッシュは当然やるんだがメモリ効率が良くないとスループット上がらない。
-> デフォで使うようになっている?
---
code:py
for example_input in example_inputs:
tasks = []
for i in range(100):
tasks.append(asyncio.create_task(gen(engine, example_input, uuid.uuid4())))
つまりオフラインバッチ処理とリアルタイムバッチ処理がある。
「offline batch」という概念は、リクエストがリアルタイムで来るのではなく、事前に存在している複数のリクエストをまとめて処理する、という意味です。 code:py
outputs = llm.generate(prompts, sampling_params)
# Print the outputs.
for output in outputs:
prompt = output.prompt
generated_text = output.outputs0.text print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
vLLMでのリアルタイム推論の場合、OpenAI Compatible Server?
https://scrapbox.io/files/6708cb644c61d9001cc98fbe.png
おーーー!まさにキューにたまるようになっている。
If you set the max_num_batched_tokens or max_num_seqs with low value then the prefill batch size will be small (e.g., 1) which might not hurt performance, there is no one size fit all suggestion I guess, I think you can tweak the prefill batch size through these two knobs and use benchmark_serving.py in vLLM to determine what size leads to best performance.