プロダクションでOllamaを使う場合のインストールメモ

# はじめに
Windows WSL2 dockerでOllamaを起動し検証をしたが最初の読み込みの時間が遅く、使い勝手が悪かったので、docker抜きで検証することにした。結論、ロードのスピードが早くなり、レスポンスも向上した。

プロダクションでOllamaを使う場合は、Dockerは使わないほうがよいかなといった印象。そもそも、Docker使う場合、色々とケアする項目（Dockerの設定など）増えるので、プロダクションでのOllama利用は、サーバーに直接Ollamaをインストールして扱うほうが無難かも。

[以前の作業メモはこちら(ollama (llama3) + docker + wsl2 + ubuntu24メモ)。](https://qiita.com/kiyotaman/items/cf405a654cee1f21641f)

# 開発環境
以下の開発環境に、WSLでubuntu22.04をインストール。ubuntu22.04を選んだ理由は、[cuda toolkit](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_local)が、現時点(202406)で、Ubuntu22.04までは、サポートしている様なので、ubuntu22.04を選択しておくことにする。

## 機器情報
| コンポーネント      | 詳細                                       |
|---------------------|--------------------------------------------|
| オペレーティングシステム | Windows 11 Pro (HAV-00213)               |
| プロセッサ          | Intel Core i9-14900KF (BX8071514900KF)    |
| 冷却システム        | DeepCool LS720S ZERO DARK (R-LS720-BKNNMM-G-1) |
| マザーボード        | ASUS PROART Z790-CREATOR WIFI             |
| メモリ              | SK Hynix DDR5-5600 48GB x4 (SMD5-U96G28H-56B-D) |
| グラフィックスカード | GAINWARD NVIDIA GeForce RTX 4090 (NED4090019SB-1020P) |
| ストレージ          | Kingston NVMe SSD 2TB x2 (SKC3000D/2048G) |
| 電源ユニット        | FSP Hydro G Pro 850W (CUT593PW)            |
| 電源ユニット        | Antec NE1000G M ATX3.0                    |

## スペック情報
| スペック            | 詳細                                       |
|---------------------|--------------------------------------------|
| 合計メモリ容量      | 192GB (SK Hynix DDR5-5600 48GB x4)        |
| 合計ストレージ容量  | 4TB (Kingston NVMe SSD 2TB x2)            |
| GPU スペック        | NVIDIA GeForce RTX 4090                   |
| GPU メモリ容量      | 24GB GDDR6X                               |
| CUDA コア数         | 10,496                                    |
| ベースクロック      | 1.70 GHz                                  |
| ブーストクロック    | 2.23 GHz                                  |


# cudaのインストール

* [WSL+Ubuntuの場合](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=WSL-Ubuntu&target_version=2.0&target_type=deb_network)
* [Ubuntuサーバーの場合](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_network)

:::note info
Nividaドライバーのインストールは、WSLの場合、Windowsでインストールすると思うのでWSL+Ubuntuではインストールは必要ない想定。OSをUbuntu22.04にする場合、上記の**Ubuntuサーバーの場合**を参照し、Nvidiaのドライバーのインストールをするとよい。
:::

# Ollamaのインストール

https://github.com/ollama/ollama/blob/main/docs/linux.md

下記、上記のドキュメントのおさらい

## one-linerでインストール
:::note warn
one-linerで再インストールすると、ollama.serviceが初期化されるので、バックアップしておいたほうがよいかも。
:::

```bash
curl -fsSL https://ollama.com/install.sh | sh
```

:::note info
GPUによってインストールの方法が異なるので、確認して作業をする
:::

## Ollama serverの設定

**ユーザーを作成:**
```
sudo useradd -r -s /bin/false -m -d /usr/share/ollama ollama
```
:::note info
one-linerのインストールをした場合、設定する必要はない
:::

**ollama.serviceの設定:**
```
sudo vi /etc/systemd/system/ollama.service
```
:::note info
one-linerのインストールをした場合、必要に応じて設定を変更
:::

**Ollamaサービスの設定サンプル:**
```ini
[Unit]
Description=Ollama Service
After=network-online.target

[Service]
Environment="OLLAMA_HOST=0.0.0.0"
Environment="OLLAMA_MAX_LOADED_MODELS=3"
Environment="OLLAMA_MAX_QUEUE=512"
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_DEBUG=1"
Environment="OLLAMA_FLASH_ATTENTION=1"
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3

[Install]
WantedBy=default.target
```

### 環境変数の表

| 環境変数名                    | デフォルト値          | 型       | 説明                                             |
|-------------------------------|----------------------|----------|--------------------------------------------------|
| `OLLAMA_DEBUG`                | `0`              | `int`   | 追加のデバッグ情報を表示 (例: `OLLAMA_DEBUG=1`)    |
| `OLLAMA_FLASH_ATTENTION`      | `0`              | `int`   | フラッシュアテンションを有効化                    |
| `OLLAMA_HOST`                 | `127.0.0.1:11434`    | `string` | OllamaサーバーのIPアドレス (外部接続は `0.0.0.0:11434`) |
| `OLLAMA_KEEP_ALIVE`           | `"5m"`               | `string` | モデルがメモリに保持される期間 (`-1`は永続)       |
| `OLLAMA_LLM_LIBRARY`          |  なし               | `string` | 自動検出をバイパスするLLMライブラリを設定         |
| `OLLAMA_MAX_LOADED_MODELS`    | `1`                  | `int`    | ロードされたモデルの最大数                        |
| `OLLAMA_MAX_QUEUE`            | `512`                | `int`    | キューに入るリクエストの最大数                    |
| `OLLAMA_MAX_VRAM`             | `0`                  | `uint64` | 最大VRAM                                         |
| `OLLAMA_MODELS`               |   なし     | `string` | モデルディレクトリへのパス                        |
| `OLLAMA_NOHISTORY`            | NoHistory              | `string`   | readline履歴を保存しない                          |
| `OLLAMA_NOPRUNE`              | NoPrune              | `string`   | 起動時にモデルブロブをプルーンしない              |
| `OLLAMA_NUM_PARALLEL`         | `1`                  | `int`    | 並行リクエストの最大数                            |
| `OLLAMA_ORIGINS`              |   localhost,127.0.0.1,0.0.0.0,  | `string` | 許可されるオリジンのカンマ区切りリスト            |
| `OLLAMA_RUNNERS_DIR`          |     なし             | `string` | ランナーの場所                                    |
| `OLLAMA_TMPDIR`               | なし               | `string` | 一時ファイルの場所                                |

**詳細な説明:**

- **OLLAMA_DEBUG**: 追加のデバッグ情報を表示するために使用
- **OLLAMA_FLASH_ATTENTION**: [フラッシュアテンション](https://zenn.dev/nhandsome/articles/388b2ebb57d5d1)機能を有効にし、高速化のための機能
- **OLLAMA_HOST**: OllamaサーバーのIPアドレスを指定し、デフォルトはローカルホストで、外部接続も可能
- **OLLAMA_KEEP_ALIVE**: モデルがメモリに保持される期間の設定、デフォルトは5分で、永続化も可能
- **OLLAMA_LLM_LIBRARY**: 自動検出しないで、指定した特定のLLMライブラリを使用する場合に設定
- **OLLAMA_MAX_LOADED_MODELS**: 同時にロードできるモデルの最大数、RAMの容量に合わせて設定
- **OLLAMA_MAX_QUEUE**: キューに入るリクエストの最大数
- **OLLAMA_MAX_VRAM**: 使用する最大VRAM量を指定
- **OLLAMA_MODELS**: モデルが保存されているディレクトリのパスの設定
- **OLLAMA_NOHISTORY**: コマンドラインの履歴の保存の有無を設定
- **OLLAMA_NOPRUNE**: 起動時に古いモデルデータを削除しないようにするためのもの
- **OLLAMA_NUM_PARALLEL**: 並行して処理するリクエストの最大数の設定
- **OLLAMA_ORIGINS**: 許可されたオリジンのリストを指定
- **OLLAMA_RUNNERS_DIR**: ランナーのファイルが保存されているディレクトリを指定
- **OLLAMA_TMPDIR**: 一時ファイルの保存場所の設定

### ファイルの内容説明

```ini
[Unit]
Description=Ollama Service
After=network-online.target
```
- **[Unit]セクション**: サービスの説明と、他のユニットが開始された後にこのユニットを開始するかどうかを定義する
  - `Description`: サービスの説明
  - `After`: このサービスがネットワークでオンラインになった後、起動することを指定

```ini
[Service]
Environment="OLLAMA_HOST=0.0.0.0"
Environment="OLLAMA_MAX_LOADED_MODELS=3"
Environment="OLLAMA_MAX_QUEUE=512"
Environment="OLLAMA_NUM_PARALLEL=3"
Environment="OLLAMA_KEEP_ALIVE=-1"
Environment="OLLAMA_DEBUG=1"
Environment="OLLAMA_FLASH_ATTENTION=1"
ExecStart=/usr/local/bin/ollama serve
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
```
- **[Service]セクション**: サービスの実行に関する設定を定義
  - `Environment`: 環境変数の指定
  - `ExecStart`: サービスを開始するコマンド
  - `User`: サービスを実行するユーザー
  - `Group`: サービスを実行するグループ
  - `Restart`: サービスが終了した場合の再起動ポリシー
  - `RestartSec`: 再起動までの待機時間
  - `Environment`: 環境変数の設定

```ini
[Install]
WantedBy=default.target
```
- **[Install]セクション**: サービスのインストール時の設定の定義
  - `WantedBy`: サービスがどのターゲットに関連付けられるかを指定
  - `default.target`: はシステムのデフォルトのターゲットを指す

## Ollamaの操作方法

**ユニットファイルのリロード:**
新しいサービスユニットファイルを読み込むためにsystemdをリロード

```bash
sudo systemctl daemon-reload
```

**サービスの起動:**
 
```bash
sudo systemctl start ollama
```
   
**サービスの有効化:**

サービスを自動起動するように設定します。
```bash
sudo systemctl enable ollama
```

**サービスの状態確認:**

サービスを自動起動するように設定します。
```bash
sudo systemctl status ollama
```

## Ollamaの最適な設定値の決め方

最適な設定を決めるためには、以下の要素を考慮する必要がある：

### 1. システムのハードウェアリソース
- **GPU**: NVIDIA GeForce RTX 4090
- **メモリ (RAM)**: 192GB
- **VRAM**: 24GB

### 2. 予想される負荷と使用ケース
- 同時に複数のリクエストを処理する必要がある場合
- 複数のモデルを同時に使用する必要がある場合

### 3. 既存の制限とベストプラクティス
- **`OLLAMA_MAX_LOADED_MODELS`**: 同時にロードされるモデルの最大数
- **`OLLAMA_MAX_QUEUE`**: 処理待ちキューに保持できるリクエストの最大数
- **`OLLAMA_NUM_PARALLEL`**: 同時に処理するリクエストの数

### 設定例

#### `OLLAMA_MAX_LOADED_MODELS`
RAMの192GBを考慮して、同時に複数のモデルをロードする場合、各モデルが消費するRAMに基づいて設定。例えば、1つのモデルが約20GBのRAMを消費する場合、4つまで同時にロード80GBをロードしておくことができる。

```sh
export OLLAMA_MAX_LOADED_MODELS=3
```

#### `OLLAMA_MAX_QUEUE`
システムのメモリと予想される同時リクエスト数に基づいて設定します。大量のリクエストを効率的に処理するために、512に設定します。

```sh
export OLLAMA_MAX_QUEUE=512
```

#### `OLLAMA_NUM_PARALLEL`
OLLAMA_MAX_LOADED_MODELSと合わせたほうがよいかなと思ったので、今回は、3にしてみる

```sh
export OLLAMA_NUM_PARALLEL=3
```

:::note warn
Ollamaは複数のモデルを同時にロードし、効率的にリクエストを処理することができ感じだが、実際の使用環境でのパフォーマンステストを行い、必要に応じて設定を微調整は必要。
:::


# Ollama動作確認
systemdでollamaを起動させている前提で確認

```bash
$ sudo systemctl daemon-reload
$ sudo systemctl start ollama
$ sudo systemctl status ollama
● ollama.service - Ollama Service
     Loaded: loaded (/etc/systemd/system/ollama.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-06-02 19:37:45 JST; 4s ago
   Main PID: 5371 (ollama)
      Tasks: 17 (limit: 115729)
     Memory: 594.2M
     CGroup: /system.slice/ollama.service
             └─5371 /usr/local/bin/ollama serve

Jun 02 19:37:47 dev ollama[5371]: time=2024-06-02T19:37:47.807+09:00 level=DEBUG source=gpu.go:342 msg="Unable to load nvcuda" library=/usr/lib/x86_64-linux-gnu/libcuda.so.545.29.06 error="nvcuda init failure: 100"
Jun 02 19:37:47 dev ollama[5371]: CUDA driver version: 12.5
Jun 02 19:37:47 dev ollama[5371]: time=2024-06-02T19:37:47.903+09:00 level=DEBUG source=gpu.go:127 msg="detected GPUs" count=1 library=/usr/lib/wsl/lib/libcuda.so
Jun 02 19:37:47 dev ollama[5371]: time=2024-06-02T19:37:47.903+09:00 level=DEBUG source=cpu_common.go:11 msg="CPU has AVX2"
Jun 02 19:37:47 dev ollama[5371]: [GPU-8840bbeb-fd27-80fa-ffc1-c0a5cbf8c73a] CUDA totalMem 24563 mb
Jun 02 19:37:47 dev ollama[5371]: [GPU-8840bbeb-fd27-80fa-ffc1-c0a5cbf8c73a] CUDA freeMem 22994 mb
Jun 02 19:37:47 dev ollama[5371]: [GPU-8840bbeb-fd27-80fa-ffc1-c0a5cbf8c73a] Compute Capability 8.9
Jun 02 19:37:48 dev ollama[5371]: time=2024-06-02T19:37:48.015+09:00 level=DEBUG source=amd_linux.go:322 msg="amdgpu driver not detected /sys/module/amdgpu"
Jun 02 19:37:48 dev ollama[5371]: releasing nvcuda library
Jun 02 19:37:48 dev ollama[5371]: time=2024-06-02T19:37:48.015+09:00 level=INFO source=types.go:71 msg="inference compute" id=GPU-8840bbeb-fd27-80fa-ffc1-c0a5cbf8c73a library=cuda compute=8.9 driver=12.5 name="NVIDIA GeForce RTX 4090" >
lines 1-19/19 (END)
```


# Ollamaに接続

llama3を正しく認識している

```
$ ollama run llama3
>>> /show info
Model details:
Family              llama
Parameter Size      8.0B
Quantization Level  Q4_0
```

# open-webuiのインストール
dockerを使わずopen-webuiの設定

```bash
# python環境設定
$ sudo apt install python3.11 python3.11-venv
$ cd /path/to/dir
$ python -mvenv venv

# pythonの仮想環境の準備
$ source venv/bin/activate
$ pip install -U pip
$ pip install open-webui

# ログインなし、DEVモードで起動
$ WEBUI_AUTH=Fales open-webui dev
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/dd253e40-3ace-8c1e-80f2-85fd5519f19b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/6805e0cc-aae1-502b-985e-649c91558350.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/0643de49-31ee-6afa-c9fb-d97835f39353.png)

レスポンスもdocker経由より格段に早くなった！

# まとめ
クラウド上のプロダクションサーバーやオンプレサーバーで、どれぐらいさばけるか？また、さばくための最適な構成は何かを検証しする必要がある。また、