昨天的教學中,已經學會設定基本的OpenAI-Compatible Server方法了。
簡單回顧一下,若是什麼也沒設定,預設會是使用一個GPU。 🎮
筆者拿了一個閱讀測驗QA問答集測試 📚,一筆一筆發,請vLLM生成回應,一共跑了16分鐘。 ⏱️
(時間僅供參考用,每個人的電腦設備和設定都不同)
- 但是......電腦有兩個GPU耶! 🖥️
- 說好的分散式計算在哪裡? 🔀
- 現在跑的速度,應該還可以再更快、更快對吧! 🚀
- 還想跑更長context length的模型欸! 📜
- 量化的模型怎麼跑? 🧮
這一章就要來看這些可以手動設定、調整的部分,也就是進階篇章。 ✨
回顧一下 Day11 提過的兩種模型平行化設定方式。而官方文件的解說在這裡。
如果要使用多個GPU,數量設定公式是:你有幾張GPU = tensor-parallel-size * pipeline-parallel-size
首先,如果VRAM夠大,並且想要推理速度快一些的話,可以設定--tensor-parallel-size
。
因為筆者的GPU只有2,所以一次只能開一個示範。
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B-Instruct \
--port 8503 \
--tensor-parallel-size 2
如果把GPU開好開滿,他也會用好用滿,速度上明顯有變快,筆者的QA資料集從16分鐘變成8分鐘,直接快兩倍!
因為Tensor Parallelism是將模型的計算部分分散到多個GPU上,變快兩倍都是合理的,但是當模型大到一個VRAM不夠用的時候就需要用到Pipeline parallelism。
使用Pipeline Parallelism的話,可以設定--pipeline-parallel-size
。
之前看的時候還不支援Multiprocessing,當時要將預設會是mp的distributed-executor-backend,改成是ray,不過現在看起來是兩種都可以了。
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B-Instruct \
--port 8503 \
--pipeline-parallel-size 2
🔀 或是使用Ray:
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B-Instruct \
--port 8503 \
--pipeline-parallel-size 2
--distributed-executor-backend ray
在推論中可以看到,這次兩張GPU不是都用好用滿了,其中一張維持在38-41,另一張則是在83-89左右,而速度上同樣跑筆者的QA資料集,執行時間是18分鐘,反而變慢了。
變慢的原因如下,也可以從 Day11 回顧 📅:
- 因為Pipeline Parallelism需要在所有的GPU之間傳輸資料 🔄,所以傳輸時間也變長了。 ⏳
- 如果模型每個階段的計算量不平衡 ⚖️,可能會導致有GPU閒置,在等其他GPU計算完畢,導致GPU使用率低下。 📉
現在vLLM有支援Speculative decoding,可以選擇兩種方法進行推理:一種是使用較小的draft model,另一種則是使用ngram進行推理,這兩種都必須要打開use-v2-block-manager
。如果要精確一點的答案,num_speculative_token
可以調小;如果速度比較重要,則是調大。
⚠️ Please note that speculative decoding in vLLM is not yet optimized and does not usually yield inter-token latency reductions for all prompt datasets or sampling parameters. The work to optimize it is ongoing and can be followed in this issue.
雖然官方有警告說Speculative decoding還沒有到最佳化,不過看到今年8月的進度已經幾乎完成了,延遲甚至減少了45%。
🔬 秉持著實驗精神,如果使用相同的draft model的話,因為要同時跑兩個的模型,也不是用小的模型當draft model,這些額外的計算讓筆者的QA資料集跑了大約12分鐘,並沒有比較划算。
這邊官方的範例是 model="facebook/opt-6.7b" 和 speculative_model="facebook/opt-125m"。
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B-Instruct \
--port 8503 \
--tensor-parallel-size 2 \
--speculative-model meta-llama/Meta-Llama-3-8B-Instruct \
--num-speculative-tokens 5 \
--use-v2-block-manager
如果要使用不同的draft model,需要確認兩個模型的詞彙表大小(vocab size)一致,可以先檢查兩個model的tokenizer大小,BY GPT-4o:
from transformers import AutoTokenizer
final_model_tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")
final_model_vocab_size = final_model_tokenizer.vocab_size
draft_model_tokenizer = AutoTokenizer.from_pretrained("facebook/opt-125m")
draft_model_vocab_size = draft_model_tokenizer.vocab_size
print(f"Final model vocab size: {final_model_vocab_size}")
print(f"Draft model vocab size: {draft_model_vocab_size}")
📊 如果是用ngram的話,速度上筆者的QA資料集變成只要5分鐘!是目前最快的速度!
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B-Instruct \
--port 8503 \
--tensor-parallel-size 2 \
--speculative-model [ngram] \
--num-speculative-tokens 5 \
--ngram-prompt-lookup-max 4 \
--use-v2-block-manager
注意這邊如果是用vLLM開API的方法,在不同版本中要注意 - 和 _ 的寫法,像是
use_v2_block_manager=True
這一行會是 - 的寫法而不是 _ 的寫法。
因為在比較舊的版本中,有些沒有被統一到XD
請參考:https://docs.vllm.ai/en/latest/models/engine_args.html#engine-args
假設筆者想要跑yentinglin/Llama-3-Taiwan-8B-Instruct-128k,但設備用的是只有32GB的電腦,而昨天提到預設的--gpu-memory-utilization
是0.9,正是在 Day12 中提到的VRAM預留的一個記憶體大小,如果記憶體不夠的話就會出現下方的警告。
ValueError: The model's max seq len (131072) is larger than the maximum number of tokens that can be stored in KV cache (88528). Try increasing `gpu_memory_utilization` or decreasing `max_model_len` when initializing the engine.
這時有兩個選擇,一個是增加--gpu-memory-utilization
,調到0.95用好用滿看裝不裝得下 💪;又或是減少--max-model-len
,從原本131072減少到88528以下 📉,至少就可以執行大context length模型囉。
筆者調整了之後,雖然像是23910 tokens這種長度是可以跑的,但還是沒辦法跑88528那麼長的context length,原因推測還是KV cache的記憶體占用問題 💾,不過至少比原本8000 tokens還要多很多了XD?
- 補充一下long context length model的使用心得:
一定要記得設定max_tokens=512
,不然很容易鬼打牆就一直卡著直到最大context length,API都timeout了還生成不完QQ
詳細請見官方文件。
--host 0.0.0.0 如果可以將vLLM API對外被任何其他電腦訪問時可以設定。
--dtype auto 一般會是預設'auto',可以在API啟動後某一行看到他的選擇是什麼,也可自行設定 'float16'、'bfloat16'、'float32'。
--quantization awq 可以指定量化方法 🧮,目前支援'awq'、'gptq'、 'squeezellm'、'fp8' (experimental)。
--gpu-memory-utilization 0.75 可以設定一個0-1之間的浮點數,調整GPU的記憶體使用比例,增加的話可以預先提供更多的KV快取空間。
--max_seq_len 4096 可以控制模型的context length長度。
如果想指定GPU,可以在指令最前面加上: CUDA_VISIBLE_DEVICES=0
我們學會了如Tensor Parallelism與Pipeline Parallelism的差異,並且體驗了Speculative decoding更加速了local LLM的生成速度 📚。目前vLLM量化模型的使用沒有支援跑GGUF的量化模型,而同樣的官方文件表示目前AWQ支援還為最佳化,筆者跑起來AWQ跟vLLM (bfloat16) + Speculative decoding的速度差不多,因此可以看出vLLM真的很快!
明天來繼續在vLLM的文件中尋寶! 🧭🗺️✨
(圖源: codecademy)