本篇文章聊聊網上聊的比較少的具體量化操作,非常見整型位數的量化,來自讓各種開源模型能夠在 CPU 環境、CPU & GPU 環境混合推理的技術方案:llama.cpp 。
寫在前面
接下來,有計劃分享一些關于各種開源模型的實踐內容。為了能讓更多的同學能夠玩起來,降低入門的硬件門檻還是很有必要的。模型量化技術就是這樣一個“神奇、有效”的方案。
看過前兩篇文章《零一萬物模型折騰筆記:官方 Yi-34B 模型基礎使用》、《本地運行“李開復”的零一萬物 34B 大模型》的同學知道,類似 34B 的模型,如果想不怎么量化直接跑起來,大概需要 76~85GB 的顯存。如果我們進行效果損失比較小的 8 位量化,那么也需要 46GB 左右,如果是 4 位量化模型,那么也需要 21GB 左右的顯存。
雖然模型能跑了,但是有可能模型效果“打了骨折”。
是的,模型的量化其實就是這樣的一個,把類似我們相機拍攝照片(RAW),轉換成“PNG”,再轉換成“JPG”,最后甚至轉換成“GIF”的過程。我們追求的是盡量省錢,在我們的設備上保持最好效果的將模型跑起來。盡量整個接近 “PNG” 的 “JPG”,而不是一定要折騰個 “GIF” 。
尤其是一般情況下,許多同學會使用八位(INT8)或者 四位(INT4)位量化,但是我們很容易會遇到兩個尷尬的情況:
- 有的模型量化成四位(INT4)效果變的不是很好,但是量化成八位(INT8)效果還行。可是八位(INT8)尺寸又太大,運行不太方便,希望模型尺寸能夠小一些。
- 有的模型量化成四位(INT4),模型還是太大,硬件跑不起來或者跑起來太費力,希望模型變的更小巧一些。
在今年早些時候的幾篇文章和對外分享里,我曾經多次提到了幾種不同的模型量化方案,包括 Transformers、GGML 等,感興趣的同學可以自行翻閱,就不多贅述了。
本篇文章,我們主要來聊聊非常見整型位數的模型量化方案。用自己制作的量化程序,將原本在本地用游戲顯卡跑不起來的 YI 34B 模型跑起來。
準備材料
關于模型量化需要準備兩個素材,一個是模型,另外一個是量化使用的計算設備。
模型程序文件
任意參數量的模型,可以是 7B、13B、14B、20B、33B、34B、68B、70B …的模型,也可以是更小參數量的小尺寸的模型。
我這里使用的是零一萬物開源的 YI-34B 的社區 finetune 微調訓練的版本,通常情況下,社區可能有熱門模型的量化版本,經常看到一些同學說“等個量化版本”。
但其實自己動手,豐衣足食。況且,即使是從社區下載量化版本,模型體積也很大,需要來來回回測試模型是否合適,重復下載也非常消耗時間和寬帶成本,遠不如自己量化來的方便。
關于模型程序下載,方法很多。如果你想要從 HuggingFace 相對快速下載模型,可以參考這篇文章中的 “模型程序下載” 來解決問題。
量化使用的硬件
而量化模型使用的硬件,需要 CPU 計算能力相對強一些的機器,如果你有 GPU,那么將會極大的提升模型量化速度,如果沒有也沒有關系。
至于量化后的產物,則是各種設備通用的,你可以在 Windows 量化后給 Linux 或者 macOS 設備使用。你也可以使用有 CPU 和 GPU 的設備,量化后給只有 CPU 的設備使用。
唯一有一些差異的,只有運行這個通用模型格式程序的啟動程序,是需要和你當前的運行環境和操作系統有些關聯的,比如需要構建,或者安裝時需要一些初始化。
相比較模型,程序這個真的就是小意思啦。
模型的 GGUF (GGML Universal File)格式量化準備
GGUF 是 GGML 的全新替代型,被稱為 GGML 通用文件格式。
GGUF 支持的模型量化格式非常多,刨除“幾種跨開源生態模型轉換的場景外”,主要依賴兩個程序:convert.py
和 quantize
程序。前者以 Python 腳本的形態存在于 llama.cpp 項目的目錄中,后者需要我們進行項目的構建。
下載 llama.cpp 的代碼,然后就能夠進行構建操作啦:
# 下載代碼
git clone https://github.com/ggerganov/llama.cpp.git
# 切換工作目錄到項目文件夾內
cd llama.cpp
# 構建項目可執行文件(有顯卡)
make -j LLAMA_CUBLAS=1
# 構建項目執行文件 (沒有顯卡)
make -j
等待程序構建完畢,所有的準備工作就都完成啦。
預轉換:Convert.py 轉換腳本
這個腳本能夠將非 GGML 格式的文件轉換為 GGML,以 GGUF 后綴進行保存。程序默認支持轉換下面幾類格式的模型:*.pth
、*.pt
、*.bin
、*.safetensors
。
是我們進行后續非常見整型模型量化的基礎操作步驟。
如果我們只追求使用 8 位量化的,可以使用 CPU 和 GPU 混合推理的模型,那么我們可以參考這篇文章中的“嘗試對模型進行幾種不同的量化操作”的方法中的命令行參數,將模型轉換為 GGML 的 q8_0
模型。
但如果,我們希望制作更多其他的不同的類型的模型,比如 2 位量化~ 6 位量化,那么我非常建議大家使用 convert.py
腳本制作和轉換一個 f16
類型的 GGML 模型。
雖然程序的命令行參數看起來很麻煩,但是我們需要使用到的轉換命令其實非常簡單,使用 Python 調用程序,命令中攜帶“模型路徑”和“輸出的模型類型”即可:
python ./convert.py 【模型的路徑】 --outtype f16
我這里以 YI-34B 的社區 finetune 模型 brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties
為例子,調整為我自己的模型存放路徑:
python ./convert.py ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ --outtype f16
執行命令后,機器將會火力全開的進行程序編譯,輸出大量日志:
Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00001-of-00008.safetensors
Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00001-of-00008.safetensors
Loading model file ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/model-00002-of-00008.safetensors
...params = Params(n_vocab=64000, n_embd=7168, n_layer=60, n_ctx=200000, n_ff=20480, n_head=56, n_head_kv=8, f_norm_eps=1e-05, rope_scaling_type=None, f_rope_freq_base=5000000.0, f_rope_scale=None, n_orig_ctx=None, rope_finetuned=None, ftype=<GGMLFileType.MostlyF16: 1>, path_model=PosixPath('../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties'))
Loading vocab file '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/tokenizer.model', type 'spm'
Permuting layer 0
Permuting layer 1
Permuting layer 2
...model.embed_tokens.weight -> token_embd.weight | BF16 | [64000, 7168]
model.layers.0.input_layernorm.weight -> blk.0.attn_norm.weight | BF16 | [7168]
...Writing ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf, format 1
gguf: This GGUF file is for Little Endian only
gguf: Setting special token type bos to 1
gguf: Setting special token type eos to 2
gguf: Setting special token type unk to 0
gguf: Setting special token type pad to 0
[ 1/543] Writing tensor token_embd.weight | size 64000 x 7168 | type F16 | T+ 1
[ 2/543] Writing tensor blk.0.attn_norm.weight | size 7168 | type F32 | T+ 2
[ 3/543] Writing tensor blk.0.ffn_down.weight | size 7168 x 20480 | type F16 | T+ 2
...Wrote ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf
當一切都結束后,我們能夠看到類似上面日志的最后一行提示,告訴我們轉換好的模型名字和存放到機器的什么位置了。默認會存放于你指定要轉換模型的目錄,并以 .gguf
后綴保存文件。
最終轉換:quantize 量化程序
當我們使用上面的方法,將模型轉換為了相對高精度的模型文件后,我們就可以進行下一步量化了。
執行 ./quantize --help
,除了程序的執行命令格式參考外,我們還能夠看到量化程序支持的所有類型:
Allowed quantization types:2 or Q4_0 : 3.56G, +0.2166 ppl @ LLaMA-v1-7B3 or Q4_1 : 3.90G, +0.1585 ppl @ LLaMA-v1-7B8 or Q5_0 : 4.33G, +0.0683 ppl @ LLaMA-v1-7B9 or Q5_1 : 4.70G, +0.0349 ppl @ LLaMA-v1-7B10 or Q2_K : 2.63G, +0.6717 ppl @ LLaMA-v1-7B12 or Q3_K : alias for Q3_K_M11 or Q3_K_S : 2.75G, +0.5551 ppl @ LLaMA-v1-7B12 or Q3_K_M : 3.07G, +0.2496 ppl @ LLaMA-v1-7B13 or Q3_K_L : 3.35G, +0.1764 ppl @ LLaMA-v1-7B15 or Q4_K : alias for Q4_K_M14 or Q4_K_S : 3.59G, +0.0992 ppl @ LLaMA-v1-7B15 or Q4_K_M : 3.80G, +0.0532 ppl @ LLaMA-v1-7B17 or Q5_K : alias for Q5_K_M16 or Q5_K_S : 4.33G, +0.0400 ppl @ LLaMA-v1-7B17 or Q5_K_M : 4.45G, +0.0122 ppl @ LLaMA-v1-7B18 or Q6_K : 5.15G, -0.0008 ppl @ LLaMA-v1-7B7 or Q8_0 : 6.70G, +0.0004 ppl @ LLaMA-v1-7B1 or F16 : 13.00G @ 7B0 or F32 : 26.00G @ 7BCOPY : only copy tensors, no quantizing
這里,我建議始終使用 Q4_K
、Q5_K
這類代指名稱來進行模型轉換,并且在進行轉換之前,偶爾執行 ./quantize --help
看看有沒有新的、更適合你的量化方案。名稱中的 Q數字
中的數字就是對應的量化的位數啦。
一般來說,位數越高,需要的內存和顯存就越多,運行起來越慢,但是效果和精度就越接近原始版本。反之,我們雖然得到了省資源的版本,但是效果會有明顯的降低。不過,如果你模型跑不起來,效果是零,這種情況下能夠量化跑起來的模型,總歸是比沒有強,某種程度來說,也是不得已而為之。
幫助信息中展示的如何使用命令行的演示信息,同樣是內容比較多比較復雜的。但是同樣的,我們實際只需要非常簡單的使用方法,記住下面的調用方式就足夠了:
./quantize 【模型地址】【模型類型名稱】
如果我們將命令中的“變量”進行替換,改成本文中我使用的模型和我選擇的量化方案,命令行如下:
./quantize ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf Q5_K_M
命令執行過程中,我們將看到滾動的日志:
ggml_init_cublas: GGML_CUDA_FORCE_MMQ: no
ggml_init_cublas: CUDA_USE_TENSOR_CORES: yes
ggml_init_cublas: found 1 CUDA devices:Device 0: NVIDIA GeForce RTX 4090, compute capability 8.9
main: build = 1622 (8a7b2fa)
main: built with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu
main: quantizing '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf' to '../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-Q5_K_M.gguf' as Q5_K_M
llama_model_loader: loaded meta data with 20 key-value pairs and 543 tensors from ../brucethemoose/CapyTessBorosYi-34B-200K-DARE-Ties/ggml-model-f16.gguf (version GGUF V3 (latest))
llama_model_loader: - tensor 0: token_embd.weight f16 [ 7168, 64000, 1, 1 ]
llama_model_loader: - tensor 1: blk.0.attn_norm.weight f32 [ 7168, 1, 1, 1 ]
...
llama_model_loader: - tensor 542: output_norm.weight f32 [ 7168, 1, 1, 1 ]
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv 0: general.architecture str = llama
llama_model_loader: - kv 1: general.name str = brucethemoose
llama_model_loader: - kv 2: llama.context_length u32 = 200000
llama_model_loader: - kv 3: llama.embedding_length u32 = 7168
...
[ 541/ 543] blk.59.ffn_down.weight - [20480, 7168, 1, 1], type = f16, quantizing to q6_K .. size = 280.00 MiB -> 114.84 MiB | hist:
[ 542/ 543] blk.59.ffn_norm.weight - [ 7168, 1, 1, 1], type = f32, size = 0.027 MB
[ 543/ 543] output_norm.weight - [ 7168, 1, 1, 1], type = f32, size = 0.027 MB
llama_model_quantize_internal: model size = 65593.31 MB
llama_model_quantize_internal: quant size = 23193.68 MBmain: quantize time = 99803.07 ms
main: total time = 99803.07 ms
轉換完畢,我們前往模型的目錄,查看文件大小,能夠看到非常明顯的尺寸縮減:
# du -hs *
23G ggml-model-Q5_K_M.gguf
65G ggml-model-f16.gguf
至于模型的使用,就太簡單啦。
我們可以使用 llama.cpp 項目中的 main
和 server
來運行模型,前者會在命令行中啟動一個交互式的終端,后者則會啟動一個簡潔的 Web UI,我們在瀏覽器中就可以輕松的調節模型的調用參數。
在前兩篇相關的文章中有提到過,這里我們再聊一次,順便聊聊不同的參數的選擇和調整策略。
我一般的“起手式”是這樣:
./server --ctx-size 2048 --host 0.0.0.0 --n-gpu-layers 50 --model ../playground/01-ai/Yi-34B/ggml-model-q8_0.gguf
上面的命令中,分別包含了:
- “
--ctx-size
” 指定模型會話窗口大小,所能容納和使用的 Token 數量,這里如果想省點顯存和內存,就設置小一些,能夠滿足你的任務需要就好。如果資源比較多,可以開到模型的上限,比如最近的默認模型都是4k
的,就設置 4096,8K 就設置 8192,200K 就設置個 200000,以此類推。 - “
--host
” 默認其實可以不添加,但是如果你在局域網,或者你的服務運行在容器里,那么你需要分享或者在容器外訪問,設置--host 0.0.0.0
就很有必要啦。 - “
--n-gpu-layers
” 這個參數需要配合顯卡一起使用,如果你有顯卡,但是顯卡裝不下模型,或者裝下模型后快滿了,可以考慮適當調整下數值,根據自己的需求,將合適的模型層數扔到顯卡里,稍微給顯卡留點富余量。扔到顯卡里的模型層數越多,推理速度越快。 - “
--model
” 這個參數沒有什么特別的,指定我們下載或者轉換好的 GGML 模型文件就好。
好啦,當這個命令執行后,我們就能夠快樂的和模型一起玩耍啦。
是不是很有趣,后面有機會我們聊聊上面這個交互體驗是如何實現的。
最后
這篇內容就先寫到這里,接下來的相關文章,我們來聊聊社區里不同優化方向和模型的模型們。
希望大家玩模型,都能玩的開心。感謝所有為開源模型辛苦工作的模型創作者團隊,和所有為開源社區搖旗吶喊,將好的東西分享給更多的人的朋友們。
–EOF
本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或重新修改使用,但需要注明來源。 署名 4.0 國際 (CC BY 4.0)
本文作者: 蘇洋
創建時間: 2023年12月12日
統計字數: 8528字
閱讀時間: 18分鐘閱讀
本文鏈接: https://soulteary.com/2023/12/12/cpu-hybrid-inference-unusual-large-language-model-quantization-2-3-5-6-bit-quantization.html