Ollama で Llama-3.1-Swallow-8B-Instruct-v0.3 を動かす

## 概要
- Ollama で [`Llama-3.1-Swallow-8B-Instruct-v0.3`](https://huggingface.co/tokyotech-llm/Llama-3.1-Swallow-8B-Instruct-v0.3) を動かす手順を記載する
- 記載時点で、上記モデルは Ollama のリポジトリに含まれていないため、手動で変換・パッケージングする必要がある
  - 上記以外のモデルも、同様の手順で動かすことができると思われる
- 下記環境（スペック）では未量子化モデルを動かすのは困難である（重すぎる）ため、モデルの量子化も行った

### 環境
以下の環境で動作確認を行った。

- [MacBook Pro (13-inch, M1, 2020)](https://support.apple.com/ja-jp/111893)
  - メモリ 16 GB
- macOS Sequoia 15.2
- Python 3.12.7

モデルのファイルサイズが大きいため、概ね30GB以上のストレージの空き容量が必要。


### ディレクトリ構成
```

local-llm
├── llama.cpp
│
├── models
│   ├── Llama-3.1-Swallow-8B-Instruct-v0.3/
│   ├── Llama-3.1-Swallow-8B-Instruct-v0.3-f16.gguf
│   ├── Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3-f16
│   ├── Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M.gguf
│   └── Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M
│
└── venv
```

「モデルのパッケージング」の完了後は、`local-llm/`配下のファイルは削除しても問題ない。（そのままでも問題ないが、容量が大きいため注意。）

## 手順

### 必要なパッケージ類のインストール
必要なパッケージをインストールする。
```sh
# /local-llm
brew install cmake
brew install ollama
brew install git-lfs
git lfs install
```

### リポジトリのクローン
ディレクトリを作成する。
```sh
# /local-llm
mkdir models
```
リポジトリをクローンする。
```sh
# /local-llm
git clone https://github.com/ggerganov/llama.cpp.git
```
```sh
# /local-llm/models
git clone https://huggingface.co/tokyotech-llm/Llama-3.1-Swallow-8B-Instruct-v0.3
```

### llama.cpp のビルド
lamma.cpp をビルドする。
```sh
# /local-llm/llama.cpp
cmake -B build
cmake --build build --config Release
```

### モデル変換
Hugging Face フォーマットのモデルを llama.cpp のフォーマット (GGUF) に変換する。
```sh
# /local-llm
python3 -m venv venv
source venv/bin/activate
python -m pip install -r ./llama.cpp/requirements.txt
python ./llama.cpp/convert_hf_to_gguf.py ./models/Llama-3.1-Swallow-8B-Instruct-v0.3/ --outtype f16 --outfile ./models/Llama-3.1-Swallow-8B-Instruct-v0.3-f16.gguf
```

### モデルの量子化
先述の環境（スペック）では未量子化モデルを動かすのは困難である（重すぎる）ため、モデルの量子化を行う。
```sh
# /local-llm
./llama.cpp/build/bin/llama-quantize ./models/Llama-3.1-Swallow-8B-Instruct-v0.3-f16.gguf ./models/Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M.gguf q4_K_M
```

参考までに、量子化前後のモデルサイズの一例を示す。
```
llama_model_quantize_impl: model size  = 15317.02 MB
llama_model_quantize_impl: quant size  =  4685.30 MB
```

### Ollama の起動
Ollama を使う際は、「Ollama のサーバープロセス」と「操作コマンドを入力するクライアント」 のように、少なくとも 2 つのターミナル（またはバックグラウンドでの起動）が必要になる。
```sh
# /local-llm
ollama serve
```
Ollama が起動しているターミナルはそのままにしておく。

別ターミナルで引き続き作業を行う。

### モデルのパッケージング

#### 未量子化モデル
モデルファイルを作成する。
```sh
# /local-llm/models
touch Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3-f16
```

`Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3-f16`は以下のように記述する。
```txt
FROM ./Llama-3.1-Swallow-8B-Instruct-v0.3-f16.gguf

TEMPLATE "{{ if .System }}
system


{{ .System }}
{{ end }}{{ if .Prompt }}
user


{{ .Prompt }}
{{ end }}
assistant


{{ .Response }}
"
PARAMETER num_keep 24
PARAMETER stop 

PARAMETER stop 

PARAMETER stop 

```
モデルのパッケージングを行う。

```sh
# /local-llm/models
ollama create Llama-3.1-Swallow-8B-Instruct-v0.3-f16.gguf -f Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3-f16
ollama list # 該当のモデルが表示されることを確認
```

#### 量子化モデル
未量子化モデルと同様。

モデルファイルを作成する。
```sh
# /local-llm/models
touch Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M
```
`Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M`は以下のように記述する。（`FROM` のファイル名のみ変更。それ以外は未量子化モデルと同様）
```txt
FROM ./Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M.gguf

TEMPLATE "{{ if .System }}
system


{{ .System }}
{{ end }}{{ if .Prompt }}
user


{{ .Prompt }}
{{ end }}
assistant


{{ .Response }}
"
PARAMETER num_keep 24
PARAMETER stop 

PARAMETER stop 

PARAMETER stop 

```

モデルのパッケージングを行う。
```sh
ollama create Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M.gguf -f Modelfile_Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M
ollaam list # 該当のモデルが表示されることを確認
```

### モデルの実行
モデルを実行する。
```sh
ollama run Llama-3.1-Swallow-8B-Instruct-v0.3.Q4_K_M.gguf:latest
```
REPL が起動するので、プロンプトを入力し、応答が返ってくることを確認する。

## 参考サイト
[Llama 3.1 SwallowをOllamaで使えるようにする｜ローカルLLM](https://kobayashinote.com/llama3-1-swallow-ollama-localllm)

[【M3mac環境】llama.cppを使ったGGUF変換からOllamaで実行までの手順](https://zenn.dev/k_zumi_dev/articles/1c752e21c6406f)