# Llama 3.2 Instruct Model 移植 iOS
- 移植到 Executorch CoreML Backend 對話會重複輸入文字,在 iPhone 16 pro 上無法輸入較長 >100 文字,記憶體不足。
- 虛擬機 iPhone 大約用掉 6.9 GB,會重複輸入文字。
- 使用 Executorch Llama 編譯程式可以正常執行在 Macbook Air M1 16 GB 上
- 可轉換成 CoreML 格式在 Macbook 或 iOS 上正常執行。
---
聯發科於 2025 年初釋出他們調整過的 Llama 3.2 模型,上傳至 huggingface。MediaTek 提供部分必要的檔案,`.pte` 跟 `tokenizer.bin` 檔案。
Meta 的 llama 提供更多檔案,例如 safetensor,並且 MLX-Example 已經提供 llama 轉換格式的程式碼、MLX-Swift-Example 移植到 iOS 平台上,可以使用 mlx-swift-example repository,搭配 Apple Silcon 一次支援 M1 與 iOS 系統。
`pte` 檔案可以使用 Executorch 跟它提供的專案,移植到 iOS 上使用。
- [MediaTek-Research Llama3.2-3B-Instruct-mobile](https://huggingface.co/MediaTek-Research/Llama3.2-3B-Instruct-mobile)
- [meta-llama/Llama-3.2-3B-Instruct · Hugging Face](https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct)
- [mlx-swift-examples](https://github.com/ml-explore/mlx-swift-examples)
## 練習目標
1. 移植到 iOS 與 Apple M 系列的電腦上
2. 提高 token 生成速度並學會相關技巧、論文與方法
## 使用 Executorch 移植
這裡參考聯發科使用的 Executorch,Executorch 是專門移植到手機與邊緣裝置使用的框架。目前有穩定的版本(stable 0.5 分支),但是如果要移植到 iOS 與 Android 等裝置,需要使用最新的分支(main 0.6 分支)。
文件內容等等都蠻混亂的,很多重複的步驟散亂在個文件中,從 Google 搜尋會給你 main 分支上的文件,其中幾個 iOS App 連結已經被移除,只在 stable 分支才有。
- [ExecuTorch](https://pytorch.org/executorch-overview)
- [Welcome to the ExecuTorch Documentation](https://pytorch.org/executorch/main/index.html)
### 步驟
這裡使用的操作電腦為 Macbook Air M1 16GB,並以 main 分支連結。
1. 從來源安裝 Executorch
2. 依據範例編譯 Llama 工具、下載 Llama 3.2 並轉檔,最終會有 `*.pte` 與 `tokenizer.bin` 或 `tokenizer.model`。
3. 使用 Executorch 中的 iOS llama 範例專案或在電腦上執行 llama
- [Executorch](https://pytorch.org/executorch/main/using-executorch-building-from-source.html)
- [Llama Introduction](https://github.com/pytorch/executorch/blob/main/examples/models/llama/README.md#instructions)
- [Building an ExecuTorch iOS Demo App](https://pytorch.org/executorch/main/llm/llama-demo-ios.html)
因為很混亂所以這裡提供過程:
```
# 安裝 cmake
brew install --cask cmake
sudo /Applications/CMake.app/Contents/bin/cmake-gui --install
# 部署 Python 虛擬環境
conda create -n executorch python=3.10.0
conda activate executorch
# 下載並安裝 Executorch (預設 main branch)
git clone --depth 1 https://github.com/pytorch/executorch.git
# 到該 executorch 目錄下
cd executorch
git submodule sync
git submodule update --init
# 不知為何使用以下指令才會拉 submodule 下來
git submodule update --init --recursive
# 安裝 CoreML 與 MPS Backend
./install_executorch.sh --pybind coreml mps xnnpack
./backends/apple/coreml/scripts/install_requirements.sh
./backends/apple/mps/install_requirements.sh
# 安裝 LLama 工具
./examples/models/llama/install_requirements.sh
# 編譯工具 會創建 cmake-out 目錄
cmake -DPYTHON_EXECUTABLE=python \
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DEXECUTORCH_ENABLE_LOGGING=1 \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_BUILD_COREML=ON \
-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \
-DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \
-Bcmake-out .
cmake --build cmake-out -j16 --target install --config Release
git submodule update --init --recursive
cmake -DPYTHON_EXECUTABLE=python \
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \
-DEXECUTORCH_BUILD_COREML=ON \
-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \
-Bcmake-out/examples/models/llama \
examples/models/llama
cmake --build cmake-out/examples/models/llama -j16 --config Release
# 將 Meta llama 3.2 檔案輸出成 *.pte
# 聯發科 Llama 已經提供 *.pte 檔案,可以跳過轉檔步驟
python -m examples.models.llama.export_llama --model "llama3_2" --checkpoint llama323B/consolidated.00.pth --params llama323B/params.json -kv --use_sdpa_with_kv_cache -X -d bf16 --metadata '{"get_bos_id":128000, "get_eos_ids":[128009, 128001]}' --output_name="llama3_2_bf16.pte"
```
#### 在電腦上執行 Llama
```
# 同一虛擬環境下
conda acticate executorch
cd executorch
# 執行 Llama
cmake-out/examples/models/llama/llama_main --model_path=<model pte file> --tokenizer_path=<tokenizer.model> --prompt=<prompt>
# 範例
cmake-out/examples/models/llama/llama_main --model_path="llama3_2_bf16.pte" --tokenizer_path="tokenizer.model" --prompt="What's PyTorch?"
```
我自己電腦的聯發科 Llama 輸出:
```
cmake-out/examples/models/llama/llama_main --model_path="/Users/yangdunfu/Documents/mlx_project/Llama3.2-3B-Instruct-mobile/llama3_2.pte" --tokenizer_path="/Users/yangdunfu/Documents/mlx_project/Llama-3.2-3B-Instruct/original/tokenizer.model" --prompt="撰寫台灣統治全世界的文章來看看,其中以經濟制霸的角度和方法去描述"
撰寫台灣統治全世界的文章來看看,其中以經濟制霸的角度和方法去描述台灣在亞洲的影響力,臺灣在國際上的影響力主要是經濟制?,臺灣的經濟實力是亞洲第一,經濟發展是亞洲第一,亞洲其他國家都在追隨臺灣的經濟發展。所以臺灣的經濟實力是亞洲第一,在亞洲的影響力是非常大。
第二,臺灣在亞洲的影響力主要是教育制?,臺灣的教育是亞洲第一,臺灣的教育
PyTorchObserver {"prompt_tokens":25,"generated_tokens":102,"model_load_start_ms":1742969142119,"model_load_end_ms":1742969144796,"inference_start_ms":1742969144796,"inference_end_ms":1742969166178,"prompt_eval_end_ms":1742969146508,"first_token_ms":1742969146508,"aggregate_sampling_time_ms":132,"SCALING_FACTOR_UNITS_PER_SECOND":1000}
```
我自己電腦的 meta Llama 輸出:
```
cmake-out/examples/models/llama/llama_main --model_path="llama3_2_bf16_test.pte" --tokenizer_path="/Users/yangdunfu/Documents/mlx_project/Llama-3.2-3B-Instruct/original/tokenizer.model" --prompt="撰寫台灣統治全世界的文章來看看,其中以經濟制霸的角度和方法去描"
撰寫台灣統治全世界的文章來看看,其中以經濟制霸的角度和方法去描?台灣的統治形態》.
.
* 「臺灣社會發展史-中華民國史與臺灣史」(1994)- 本書是由台大教育局所出版的,?在作為學生與教師的參考書。它的內容分為五章,第一章是介紹台大的成立與發展的歷史,第二章是中華民國的建立與發展,第三章是台北地方法
PyTorchObserver {"prompt_tokens":25,"generated_tokens":102,"model_load_start_ms":1742969188460,"model_load_end_ms":1742969190524,"inference_start_ms":1742969190524,"inference_end_ms":1742969204241,"prompt_eval_end_ms":1742969191839,"first_token_ms":1742969191839,"aggregate_sampling_time_ms":153,"SCALING_FACTOR_UNITS_PER_SECOND":1000}
```
恩...說實話看不出來差在哪裡,輸出文字有夠短的,我記得有說有改成繁體中文與台灣用詞的東西。
#### 執行 iOS llama 專案
iOS 專案底下的 LLaMARunner,會連結到部分 gitsubmodule,只按照 iOS 文件的步驟很容易會漏掉。前面的 llama 工具執行過程會產生 iOS 需要的檔案。
另外,因為 xcode 專案目錄管理自成一套,編譯過程會發現其他維護者的檔案路徑,造成編譯錯誤。
```
# 有幾包目錄檔案要下載下來
git submodule update --init --recursive
# 在 executorch 目錄下,打開 iOS 範例專案
open ./executorch/examples/demo-apps/apple_ios/LLaMA/LLaMA.xcodeproj
```
最後的執行結果非常糟糕,模型完全無法正常反應,而且還蠻詭異的,看起來有存取到不正確的記憶體位置。在 iPhone 16 pro 上跑會因為記憶體限制關係強制關閉,模擬器可以跑出來。
### 心得
安裝過程蠻折騰人的,文件本身很多地方要改, issue 中有表示效果不好或回覆有問題。iOS 的範例專案有包含到其他維護者的電腦目錄路徑,導致檔案找不到。
coremltools 不支援 onnx 檔案格式,coremltools 跟 Apple 有一套自己的 llama 跟 transofmer fusion 的方法,如果可以移植,還是使用 safetensor 去移植比較有用。Apple WWDC 有一堆開發者影片展示如何轉換。
對於聯發科來說,量測或改進生 token 的速度才是最重要的事情,感覺我還有一大段路要走!
Executorch 很多文件沒有補齊,是個可以貢獻開源的好機會!
- [Llama 3.2 3B Core ML poor output quality #9395](https://github.com/pytorch/executorch/issues/9395)
- [Move ExecuTorchDemo iOS app to pytorch-labs/executorch-demo #8788](https://github.com/pytorch/executorch/issues/8788)
- [GitHub: Llama 3.x CoreML Converter](https://github.com/andmev/llama-to-coreml)
- [On Device Llama 3.1 with Core ML](https://machinelearning.apple.com/research/core-ml-on-device-llama)
## 使用 CoreML 移植
CoreML 與 `mlmodelc` 是蘋果的模型格式,早於 gguf 的模型格式,透過 `coremltools` 轉換現有 Pytorch 模型 `pth` 檔案,透過 Pytorch jit 技術追蹤模型網路組成,輸出蘋果支援格式。
CoreML 移植比較簡單,在 LLM 模型推出之後,huggingface 便推出 swift-transformer 等實作來使用,swift-transformer 本身使用 Swift 程式語言實作,提供類似 `huggingface-cli` 的模型下載跟使用的功能。
- [GitHub - huggingface/swift-transformers: Swift Package to implement a transformers-like API in Swift](https://github.com/huggingface/swift-transformers)
### 步驟
以下的 `llama-to-coreml` 專案跟 `Swift-Chat` 專案有使用到 huggingface 提供的套件,如果不是使用自製的語言模型,可以直接參考程式碼使用現有模型,套件會幫你自動下載。專案本身都沒有教學怎麼手動使用自己的模型。
1. 使用 Python 專案 `llama-to-coreml`,這套件使用 huffingface 的 `transformer` 去讀取並下載模型。這個專案固定會從 huggingface 下載模型。轉換過程中會用到約 28 GB 記憶體,但是我的 16 GB 的電腦還是轉得過沒問題。
2. 從 huggingface meta 頁面下載 `tokenizer_config.json` 與 `tokenizer.json`
3. 使用我的 Swift XCode 專案,這程式碼多數從 `LanguageModelWithStatefulKVCache` 內容複製,程式碼目前主在 `preview` 分支。
4. 修改 `LlamaCoreml.swift` 的每個路徑。
5. 執行
- [GitHub - andmev/llama-to-coreml: Converts models from HuggingFace to CoreML format.](https://github.com/andmev/llama-to-coreml)
- [LanguageModelWithStatefulKVCache](https://github.com/huggingface/swift-transformers/blob/preview/Sources/Models/LanguageModel.swift#L341)
- [My Swift Xcode Project](https://github.com/a1091150/SwiftMLXPractice)
#### 輸出
```
<|begin_of_text|>介紹你自己
==========================
### 關鍵技能
* **Python**: Python是目前最受歡迎的程式語言,尤其是在開源和數據科學領域的應用。
* **JavaScript**: JavaScript是目前最受歡迎的程式語言,尤其是在網路和互動式網頁應用。
* **SQL**: SQL是目前最受歡迎的程式語言,尤其是在資料庫和數據分析的應用。
* **HTML/CSS**: HTML/CSS是目前最受歡迎的程式語言,尤其是在網頁設計和前端開發的應用。
* **Git**: Git是目前最受歡迎的程式語言,尤其是在版本控制和開源的應用。
### 作品
* **Python**: Python的作品包括了許多開源程式語言的應用,例如:數據科學、機器學習、網路等。
* **JavaScript**: JavaScript的作品包括了許多網路和互動式網頁的應用,例如:網路應用、互動式
Program ended with exit code: 0
```
我沒要求輸出 MarkDown 格式,它自己就輸出了。
### 心得
想比 Executorch 設定環境,使用 CoreML 工具要為簡單很多,模型轉換後的檔案大小從 4.62 GB 降為 1.8 GB,CoreML 儲存不同精度。
執行過程中,在記憶體佔用上相比使用 Executorch 要少很多,在 Maxbook 上測試執行過程中約 4 GB ,執行過程中緩慢上升。