一個檔案直接跑起大型語言模型的 llamafile

llamafile 是昨天很紅的一個專案,由 Mozilla Internet Ecosystem (MIECO) 弄出來的專案,可以使用一個檔案直接跑起大型語言模型的 HTTP server,讓你可以在瀏覽器裡面直接使用。

直接看官方的 README.md 就可以蠻簡單的跑起來,不過 Simon Willison 也有寫一篇文章介紹一下,可以看看:「llamafile is the new best way to run a LLM on your own computer」。

這邊說的「一個檔案」是指同一個檔案同時可以在 WindowsmacOSLinuxFreeBSDOpenBSD 以及 NetBSD 上面跑,而且這個檔案也把大型語言模型 (LLM) 的 model 檔案包進去,所以檔案會蠻大的,但畢竟就是方便讓人使用:

下載下來直接執行,預設就會在 port 8080 跑起來,可以直接連到 http://127.0.0.1:8080/ 連進去使用。

llamafile 用到的技術是 Cosmopolitan 專案,可以把多個平台的執行檔包在同一個檔案裡面使用。

另外用到的專案是 llama.cpp,這個蠻多人都用過了,可以很方便的用 CPU 或是 GPU 跑 LLM。

我在 Linux 上面跑剛好遇到幾個問題,都是在 README.md 上面有提到的。

第一個是 zsh 無法直接跑 llamafile (Ubuntu 22.04 內建 zsh 的是 5.8.1),這邊官方的建議是用 sh -c ./llamafile 避開:

If you use zsh and have trouble running llamafile, try saying sh -c ./llamafile. This is due to a bug that was fixed in zsh 5.9+. The same is the case for Python subprocess, old versions of Fish, etc.

另外一個對是 GPU 的支援,這邊跟你說加上 --n-gpu-layers 35 就可以用,所以一開始先用 sh -c ./llamafile --n-gpu-layers 35 試著跑:

On Linux, Nvidia cuBLAS GPU support will be compiled on the fly if (1) you have the cc compiler installed, (2) you pass the --n-gpu-layers 35 flag (or whatever value is appropriate) to enable GPU, and (3) the CUDA developer toolkit is installed on your machine and the nvcc compiler is on your path.

但可以看到沒有被 offload 到 GPU 上面:

llm_load_tensors: ggml ctx size =    0.11 MB
llm_load_tensors: using CUDA for GPU acceleration
llm_load_tensors: mem required  = 4165.47 MB
llm_load_tensors: offloading 0 repeating layers to GPU
llm_load_tensors: offloaded 0/35 layers to GPU
llm_load_tensors: VRAM used: 0.00 MB

嘗試了不同的方法,發現要跑 sh -c "./llamafile --n-gpu-layers 35",也就是把參數一起包進去,這樣就會出現對應的 offload 資訊,而且輸出也快很多:

llm_load_tensors: ggml ctx size =    0.11 MB
llm_load_tensors: using CUDA for GPU acceleration
llm_load_tensors: mem required  =   70.42 MB
llm_load_tensors: offloading 32 repeating layers to GPU
llm_load_tensors: offloading non-repeating layers to GPU
llm_load_tensors: offloaded 35/35 layers to GPU
llm_load_tensors: VRAM used: 4095.05 MB

玩了一下像是這樣:

Georgi Gerganov 給了在 AWS 上面用 GPU instance 跑 llama.cpp 的說明

Georgi Gerganov 寫了一篇怎麼在 AWS 上面用 GPU instance 跑 llama.cpp 的說明:「Using llama.cpp with AWS instances #4225」。

先跳到最後面的懶人套件,直接提供了 shell script 幫你弄完:

bash -c "$(curl -s https://ggml.ai/server-llm.sh)"

回到開頭的部分,機器的選擇上面,他選了一台最便宜的 4 vCPU + 16GB RAM + 16GB VRAM 的機器來跑。

然後他提到了 OpenHermes-2.5-Mistral-7B 這個模型最近很紅,也許有機會看一下:

We have just 16GB VRAM to work with, so we likely want to choose a 7B model. Lately, the OpenHermes-2.5-Mistral-7B model is getting some traction so let's go with it.

用 llama.cpp 裡面的 server 跑起 API server:

./server -m models/openhermes-7b-v2.5/ggml-model-q4_k.gguf --port 8888 --host 0.0.0.0 --ctx-size 10240 --parallel 4 -ngl 99 -n 512

接著就可以用 cURL 測試:

curl -s http://XXX.XXX.XXX.XXX:8888/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer no-key" \
    -d '{
        "model": "gpt-3.5-turbo",
        "messages": [
            {
                "role": "system",
                "content": "You are ChatGPT, an AI assistant. Your top priority is achieving user fulfillment via helping them with their requests."
            },
            {
                "role": "user",
                "content": "Write a limerick about python exceptions"
            }
        ]
    }' | jq

都包好了...

用 llama.cpp 玩 Mistral 7B Instruct,補一下 llama.cpp 的發展

看到「Workers AI Update: Hello Mistral 7B」這篇想到的,先前有提到「號稱目前最強的 Mistral 7B」,加上有一陣子沒看 llama.cpp 最近的發展,跳下去重新測試時發現有不少進展。

一個比較大的進展是 llama.cpp 推出 gguf 格式,取代之前的 ggml 格式。

新的格式可以想像是在檔案裡面放了通用性的 feature flag,就不會遇到新的 model 用到新的方法,沒辦法在 ggml 裡面指定 + 新增 feature,就得把 llama.cpp 整包 fork 拉出出去大改。

這差不多是三個月前的事情,蠻多 model 都已經支援了,像是 maddes8cht 這邊就整理了很多 OSL model (open source license) 可以直接下載下來用,不需要自己轉檔。

像是 Falcon 40B 與標題提到的 Mistral 7B,以及對應的 Instruct 版本 Mistral 7B Instruct 都有轉好的檔案可以下載。

另外一個有趣的功能是 llama.cpp 有了輸出 embedding 的能力,在編完後會多了一個 embedding 執行檔可以用;原來的主程式 main 也還在。

往 git repository 裡面看了一下記錄,差不多是在今年三月就已經有的功能,然後九月加到 README.md 裡面說明。

在蠻多情況下 embedding 輸出 vector 會比輸出 string 好用很多,像是相似度、推薦、語意分析這些計算;拿到 vector 後就算沒有專門的系統處理,用個 PostgreSQL 搭個能進行 vector 計算的 plugin 也就可以弄出不少東西了 (像是 pgvector)。

不過會用 embedding 的人應該早就用 PyTorch 或是其他工具,直接拉出來用了,llama.cpp 支援輸出 embedding 算是有趣但沒有到重要?

然後是支援 OpenCL,這個功能讓不少非 Nvidia 的平台可以利用 GPU 資源加速,像是 AMD 的顯卡,以及一些嵌入式系統,這點對於 llama.cpp 當初的目標就蠻有幫助的...

回到 Mistral 7B Instruct,其實小模型還是小模型,我問個演算法的題目:

./main -m models/7B/mistral-7b-instruct-v0.1.Q8_0.gguf -t 1 -ngl 32 -p '請給出一個 python 寫的 fibonacci sequence 演算法,需要 O(log(n)) 的時間複雜度。'

輸出長這樣:

 請給出一個 python 寫的 fibonacci sequence 演算法,需要 O(log(n)) 的時間複雜度。

```python
def fib_seq(n):
    return get_fibonacci(n, 0, 1)


def get_fibonacci(n, a=0, b=1):
    if n == 0:
        return []
    if n == 1:
        return [a]
    fib_seq = [a]
    for i in range(1, n):
        fib_seq.append(get_fibonacci(i, b, a + b)[0])
    return fib_seq
``` [end of text]

ChatGPT 的話可以給出一個正確的演算法,這邊只需要 ChatGPT-3.5 的 model 就可以了:

llama.cpp 官方支援 Falcon

先前有提過採用 Apache License 2.0Falcon 40B,少數能跟 LLaMA (第一代) 打對台的版本,而且是真正的 open source license:「Falcon 40B 超越 LLaMA 65B 成為目前 Open LLM 的領頭」,當時有提到 llama.cpp 還沒有支援。

過了一陣子,社群自己先 fork 了一版,想辦法支援 Falcon 40B:「cmp-nct/ggllm.cpp」,但這也導致沒有跟到很多 llama.cpp 的新功能 (尤其是各種透過硬體加速的支援)。

剛剛刷了一下,發現前幾天 llama.cpp 官方支援 Falcon 的 model 了:「llm : add Falcon support」。

看起來是個開始,可以看到還有列出一些項目要實作的,但看起來可以跑了。

llama.cpp 有全 GPU 版本了

Hacker News 首頁上看到「Llama.cpp: Full CUDA GPU Acceleration (github.com/ggerganov)」,對應得原頁面在「CUDA full GPU acceleration, KV cache in VRAM #1827」這邊。

裡面是在講 llama.cpp 之前的 GPU 加速還是有不少事情是在 CPU 上面做,這次是把目前 ggml 支援的操作都實作 GPU 版本了:

This PR adds GPU acceleration for all remaining ggml tensors that didn't yet have it. Especially for long generations this makes a large difference because the KV cache is still CPU only on master and gets larger as the context fills up.

蠻多人有不同測試的結果,要注意這次不是把 CPU 搬到 GPU 上面做,而是把本來因為比較 light 而還沒搬上 GPU 的部分搬上去,所以不會是數量級的加速,但看起來改善也已經很不賴了:

Early attempt this morning we're getting ~2.5-2.8x perf increase on 4090s and about 1.8-2x on 3090Ti.

然後 Falcon... 目前看起來還沒有必較好的進展 XD

llama.cpp 開始支援 GPU 了

前陣子因為重灌桌機,所以在重建許多環境... 其中一個就是 llama.cpp,連到專案頁面上時意外發現這兩個新的 feature:

OpenBLAS support
cuBLAS and CLBlast support

這代表可以用 GPU 加速了,所以就照著說明試著編一個版本測試。

編好後就跑了 7B 的 model,看起來快不少,然後改跑 13B 的 model,也可以把完整 40 個 layer 都丟進 3060 (12GB 版本) 的 GPU 上:

./main -m models/13B/ggml-model-q4_0.bin -p "Building a website can be done in 10 simple steps:" -n 512 -ngl 40

從 log 可以看到 40 layers 到都 GPU 上面,吃了 7.5GB 左右:

llama.cpp: loading model from models/13B/ggml-model-q4_0.bin
llama_model_load_internal: format     = ggjt v2 (latest)
llama_model_load_internal: n_vocab    = 32000
llama_model_load_internal: n_ctx      = 512
llama_model_load_internal: n_embd     = 5120
llama_model_load_internal: n_mult     = 256
llama_model_load_internal: n_head     = 40
llama_model_load_internal: n_layer    = 40
llama_model_load_internal: n_rot      = 128
llama_model_load_internal: ftype      = 2 (mostly Q4_0)
llama_model_load_internal: n_ff       = 13824
llama_model_load_internal: n_parts    = 1
llama_model_load_internal: model size = 13B
llama_model_load_internal: ggml ctx size =  90.75 KB
llama_model_load_internal: mem required  = 9807.48 MB (+ 1608.00 MB per state)
llama_model_load_internal: [cublas] offloading 40 layers to GPU
llama_model_load_internal: [cublas] total VRAM used: 7562 MB
llama_init_from_file: kv self size  =  400.00 MB

30B 的 model 我也試著丟上去跑,但只能丟 28 layers 上去 (全部是 60 layers),再多 GPU 的記憶體就撐不住了。

但能用 GPU 算是一個很大的進展,現在這版只快了一半的時間,不知道後面還有沒有 tune 的空間...

Stanford Alpaca 與 Alpaca.cpp

先前提到的「玩最近 Facebook Research (Meta) 放出來的 LLaMA」,在 2/24 公佈後,過沒多久 Stanford CRFM 團隊就丟出 fine-tuned 過的版本:「Alpaca: A Strong, Replicable Instruction-Following Model」,對應的討論在「Alpaca: A strong open-source instruction-following model (stanford.edu)」。

這個 tuning 是基於 LLaMA-7B:

We are releasing our findings about an instruction-following language model, dubbed Alpaca, which is fine-tuned from Meta’s LLaMA 7B model. We train the Alpaca model on 52K instruction-following demonstrations generated in the style of self-instruct using text-davinci-003. On the self-instruct evaluation set, Alpaca shows many behaviors similar to OpenAI’s text-davinci-003, but is also surprisingly small and easy/cheap to reproduce.

後來就再被包成一個專案 (改自 llama.cpp),讓大家可以很方便的跑:「Alpaca.cpp」。

剛好可以比較,用 llama.cpp 跑的話是:

$ ./main -m ./models/7B/ggml-model-q4_0.bin -t 12 -n 128 -p 'Explain FAANG. '

Explain FAANG. 🙂
The acronym “FAAN” is used for the five tech giants (Facebook, Apple, Amazon and Netflix) that are
 taking over our lives:
15 November 2018 / by Amaraksha S [end of text]

而用 alpaca.cpp 跑的話回答品質好不少:

> Explain FAANG.
FAANG (or FANNG) refers to five technology companies, Facebook Inc., Apple Inc., Amazon.com Inc., Netflix Inc and Alphabet's Google division that have become some of the most influential in recent years due to their rapid growth rates as well as their market capitalization values: 
Facebook (FB), $596 billion; Apple (AAPL) ,$1,084.72 billion; Amazon (AMZN), $394.5 billion ; Netflix( NFLX ), $154.8 billion and Google's parent company Alphabet Inc., ($GOOG,$GOOGL).
These companies have become some of the most influential in recent years due to their rapid growth rates as well as their market capitalization values:  Facebook (FB),$307.15 billion; Apple(AAPL) , $924.86 billion ; Amazon (AMZN ), $783.

可以看到 instruction-following 後的差異,很像是 GPT-3.5 API 與 ChatGPT API 的輸出結果差異。

而這只是 LLaMA-7B 的成果,好像可以期待有人對 LLaMA-65B 做些事情?