在當今的人工智慧和機器學習領域中,模型的效率和性能成為了研究和應用的重要焦點。隨著模型規模的不斷擴大,如何在保持預測精度的同時減少模型的資源消耗,已成為一項挑戰。這正是量化技術發揮作用的場景,特別是在需要將高階模型部署到有限資源的環境中時。本文將紀錄我如何使用 llama.cpp 工具將 LLaMa 模型轉換為 GGUF 格式,以及我在這一過程中的學習和發現。

什麼是模型量化?

有架設過深度學習模型經驗的人,一定會碰到 GPU 記憶體不夠用的狀況,由於現在模型規模越來越大,所需的 GPU 記憶體也會更多,以一個 7B 模型,所需 GPU 記憶體大約就需要 13 G 了,而以一片消費級的 GPU RTX 4070 也才 12 G 記憶體,當然您也可以選擇更貴的 RTX 4090,或 Tesla 系列。但如果要讓模型在消費級的 GPU 運行的話,勢必需要減少模型運行時所需記憶體,而這就是量化的功能了。

量化,簡而言之,就是將模型中的浮點數參數從高精度格式轉換為低精度格式的過程,例如從 32 位浮點數轉換成 8 位浮點數。這一過程能夠顯著減少模型的大小和推理時的計算需求,從而加快推理速度並減少能耗。大部分深度學習模型預設使用 bfloat16 或 bfloat32 來儲存權重值,通過降低這些參數的精度,可以有效減少記憶體的使用。

* bfloat16 跟 float16 還是有些許差異,但這不是本文討論的重點,您可以簡單理解都是浮點數。
* 除了量化之外,知識蒸餾 (Knowledge distillation, KD) 也是一種常件的模型壓縮技術。

什麼是 GGUF 格式?

GGUF 是一種著重在 CPU 執行的模型格式,其前身為 GGML 格式。GGML 格式目的是通過單一檔案來儲存模型,並且方便在 CPU 及 GPU 上運行,但後續遇到一些開發性問題,又推出了新格式 GGUF。在 HuggingFace 平台上,您仍然可以看到一些 GGML 格式的模型,但應該優先使用 GGUF 格式,新版的 llama.cpp 已不再支援 GGML 格式,且舊的 GGML 也沒辦法直接轉換為 GGUF 格式,這表示 GGML 可能會漸漸的被淘汰。

GPTQ 則是另一種量化模型格式,主要針對 GPU 優化。雖然 GGUF 及 GPTQ 著重點不同,但兩者都支援在 CPU 及 GPU 上運行。因此,根據執行環境的不同,可以選擇不同的格式:若主要在 GPU 上運行模型,則應選擇 GPTQ;若偏向於在 CPU 上運行,GGUF 則是更佳的選擇。

對於 macOS 使用者來說,如果希望在自己讀筆電上運行 llama 模型,GGUF 格式無疑是一個重要的選項。

實際進行量化操作

Step 1: 從 HuggingFace 下載 Model

首先在 HuggingFace 隨便找個 LLaMa 的模型下載下來測試,這裡假設使用 lmsys/vicuna-13b-v1.5。

安裝 huggingface_hub 套件。

                
                    pip install huggingface_hub
                
            

使用下方 Python 程式下載 lmsys/vicuna-13b-v1.5 模型。

                
                    from huggingface_hub import login, snapshot_download

                    # 如果您選擇的模型是需要登入才能下載的話,請使用 login()
                    # 並在 HuggingFace 設定 Access Tokens
                    # login()

                    # 下載模型
                    snapshot_download(
                        repo_id="lmsys/vicuna-13b-v1.5",
                        local_dir="model/lmsys_vicuna-13b-v1.5",
                        local_dir_use_symlinks=False
                    )
                
            

執行 download.py。

                
                    python download.py
                
            

Step 2: 安裝 llama.cpp

                
                    # 下載 llama.cpp
                    git clone https://github.com/ggerganov/llama.cpp.git

                    # 切換目錄
                    cd llama.cpp

                    # 編譯
                    make

                    # 安裝 Python 相依套件
                    pip install -r requirements.txt

                    # 以下是我們稍候會用到的三個程式,先檢查一下是否可以執行
                    python convert.py -h
                    ./quantize -h
                    ./perplexity -h
                
            

Step 3: 使用 llama.cpp 轉檔為 GGUF 格式

將 lmsys/vicuna-13b-v1.5 模型轉檔為 GGUF 格式。

                
                    python convert.py ../model/lmsys_vicuna-13b-v1.5 \
                      --outfile lmsys_vicuna-13b-v1.5-f16.gguf \
                      --outtype f16
                
            

--outtype 參數有 f32、f16、q8_0 可以使用,根據原始模型選擇 f32 或 f16 進行轉檔,雖然也可以選擇 q8_0 直接進行 8 bits 量化,但建議量化還是使用 quantize 程式。

執行完成後,檢查一下目錄有沒有 lmsys_vicuna-13b-v1.5-f16.gguf 檔案。這一步其實還沒有進行量化,但這個 GGUF 檔也已經可以拿來用了。

Step 4: 使用 llama.cpp 進行量化

llama.cpp 支援很多類型的量化,您可以執行以下指令,可以取得一張有用的表格來幫助您做選擇。

                
                    ./quantize -h

                    # 輸出
                    Allowed quantization types:
                       2  or  Q4_0    :  3.56G, +0.2166 ppl @ LLaMA-v1-7B
                       3  or  Q4_1    :  3.90G, +0.1585 ppl @ LLaMA-v1-7B
                       8  or  Q5_0    :  4.33G, +0.0683 ppl @ LLaMA-v1-7B
                       9  or  Q5_1    :  4.70G, +0.0349 ppl @ LLaMA-v1-7B
                      19  or  IQ2_XXS :  2.06 bpw quantization
                      20  or  IQ2_XS  :  2.31 bpw quantization
                      28  or  IQ2_S   :  2.5  bpw quantization
                      29  or  IQ2_M   :  2.7  bpw quantization
                      24  or  IQ1_S   :  1.56 bpw quantization
                      10  or  Q2_K    :  2.63G, +0.6717 ppl @ LLaMA-v1-7B
                      21  or  Q2_K_S  :  2.16G, +9.0634 ppl @ LLaMA-v1-7B
                      23  or  IQ3_XXS :  3.06 bpw quantization
                      26  or  IQ3_S   :  3.44 bpw quantization
                      27  or  IQ3_M   :  3.66 bpw quantization mix
                      12  or  Q3_K    : alias for Q3_K_M
                      22  or  IQ3_XS  :  3.3 bpw quantization
                      11  or  Q3_K_S  :  2.75G, +0.5551 ppl @ LLaMA-v1-7B
                      12  or  Q3_K_M  :  3.07G, +0.2496 ppl @ LLaMA-v1-7B
                      13  or  Q3_K_L  :  3.35G, +0.1764 ppl @ LLaMA-v1-7B
                      25  or  IQ4_NL  :  4.50 bpw non-linear quantization
                      30  or  IQ4_XS  :  4.25 bpw non-linear quantization
                      15  or  Q4_K    : alias for Q4_K_M
                      14  or  Q4_K_S  :  3.59G, +0.0992 ppl @ LLaMA-v1-7B
                      15  or  Q4_K_M  :  3.80G, +0.0532 ppl @ LLaMA-v1-7B
                      17  or  Q5_K    : alias for Q5_K_M
                      16  or  Q5_K_S  :  4.33G, +0.0400 ppl @ LLaMA-v1-7B
                      17  or  Q5_K_M  :  4.45G, +0.0122 ppl @ LLaMA-v1-7B
                      18  or  Q6_K    :  5.15G, +0.0008 ppl @ LLaMA-v1-7B
                       7  or  Q8_0    :  6.70G, +0.0004 ppl @ LLaMA-v1-7B
                       1  or  F16     : 13.00G              @ 7B
                       0  or  F32     : 26.00G              @ 7B
                
            

上表中的第三欄 Q4 表示 4 bits 量化;Q5 表示 5 bits 量化,依此類推。 隨著 bits 數的減少,量化後的模型檔案越小,執行時所需的記憶體也越少,同時導致了模型的困惑度(Perplexity, ppl)增加。 ppl (Perplexity) 是用來衡量模型品質的指標,數值越低表示品質越高。 從上表也可以觀察到,量化操作會對模型的品質造成一定程度的影響。

選擇完要量化的類型後,接下來就可以進行量化了,以下範例是將模型量化為 Q8_0。

                
                    ./quantize lmsys_vicuna-13b-v1.5-f16.gguf lmsys_vicuna-13b-v1.5-Q8_0.gguf Q8_0
                
            

Step 5: 執行量化後模型

量化後,可以先測試一下模型是否能正常執行。

                
                    ./main -m lmsys_vicuna-13b-v1.5-Q8_0.gguf -n 128
                
            

Step 6: 評估量化後模型

確定量化後模型可以執行後,可以進一步評估模型的品質。

                
                    # 下載測試集
                    wget https://huggingface.co/datasets/ggml-org/ci/resolve/main/wikitext-2-raw-v1.zip

                    # 解壓縮
                    unzip wikitext-2-raw-v1.zip

                    # 進行 Perplexity 評估
                    # 這個步驟可能需要跑好幾個小時
                    ./perplexity -m lmsys_vicuna-13b-v1.5-Q8_0.gguf -f ./wikitext-2-raw/wiki.test.raw
                
            

使用 llama-cpp-python 執行 GGUF 模型

先安裝 llama-cpp-python 套件,llama-cpp-python 支援多種硬體加速,詳細可以參考 GitHub 說明。

            
                CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install llama-cpp-python --force-reinstall --upgrade --no-cache-dir
            
        

撰寫 Python 程式碼,這是一段非常簡單的範例,實際應用上還需要考慮很多參數問題、Prompt template 及歷史對話問題。

            
                llama = Llama(model_path="lmsys_vicuna-13b-v1.5-Q8_0.gguf")
                stream = llama("您好", max_tokens=32, echo=False, stream=True)
                for output in stream:
                    print(output.get("choices", [])[0], end="", flush=True)
            
        

執行 main.py。

            
                python main.py
            
        

參考資料