LLM MLX LM - eiichiromomma/CVMLAB GitHub Wiki

(LLM) MLX-LM

M4 mac(32GB)での話.

Unified Memoryなのでそこまで潤沢ではなく,そこそこの規模のものを使いたかったら量子化モデルは必須になる. 運用としてはWebUIでも良いのだが,そのためにリソース使うのも何なのでChatbox CEを使う. LLMフレームワークは色々あるが,モデルの充実度合いとお手軽に弄れるところからMLX-LMにした.

MLX-LMの利用

にある通りで仮想環境を作って

python3 -m pip install mlx-lm
rehash

で入る.ついでにmlx_lm.*, mlx.*なコマンド群もインストールされるのでrehashしておく.mlx_lm.manageでローカルにキャッシュっされているモデルの管理もできる. オススメのモデルはmlx-community/ABEJA-Qwen2.5-32b-Japanese-v0.1-4bitだが,モデルは最初に呼び出したときにダウンロードしてくれるのでhugginfaceから何かする必要はない.

mlx-mlを選んだ理由としては--kv-bits 4でのKVキャッシュ量子化(4bit)がある.再現性に拘らないならこのお陰でメモリの消費が抑えられる.

コマンドでのgenerate

python -m mlx_lm generatemlx_lm.generateで呼び出す.--max-tokensをそれなりにデカくしないと途切れる.

python -m mlx_lm generate \
  --model mlx-community/ABEJA-Qwen2.5-32b-Japanese-v0.1-4bit \
  --max-kv-size 8192 \
  --max-tokens 4096 \
  --kv-bits 4 \
  --prompt "LLMパッケージやアプリで起動時に適切なkvキャッシュや出力トークン数が無難なデフォルト値にならないのはなぜ?"
Fetching 12 files: 100%|████████████████████████████████████████████████████████████████| 12/12 [00:00<00:00, 144631.17it/s]
==========
LLM(大規模言語モデル)パッケージやアプリで、起動時に適切なkvキャッシュや出力トークン数が無難なデフォルト値にならない理由はいくつかあります。

1. **モデルの多様性**: LLMは様々な用途やタスク向けに設計されており、それぞれのモデルが異なる特性や要件を持っています。そのため、一概に「無難なデフォルト値」を設定することが難しい場合があります。

2. **リソースの効率**: kvキャッシュや出力トークン数は、メモリや計算リソースに大きな影響を与えます。デフォルト値が高すぎると、リソースが不足する環境ではパフォーマンスが低下したり、エラーが発生したりする可能性があります。逆に低すぎると、モデルの性能が十分に発揮されない場合があります。

3. **ユーザーのカスタマイズ**: ユーザーが特定の用途や環境に応じてパラメータを調整できるように、デフォルト値を最小限に設定することがあります。これにより、ユーザーは必要に応じてパラメータを最適化できます。

これらの理由から、デフォルト値は一般的に最小限の設定に抑えられることが多いです。
==========
Prompt: 69 tokens, 19.509 tokens-per-sec
Generation: 299 tokens, 5.571 tokens-per-sec
Peak memory: 18.606 GB

ローカルサーバー運用

対話で考えたい場合もあり毎度コマンドで実行するのも面倒なのでサーバー運用する.ただし,サーバーのスクリプトはおまけ程度のものらしく,generateで使えたオプションが存在しないのでハードコードしてしまう.

python -c "import mlx_lm.server as m; print(m.__file__)"

で出てきたファイルを開き下記を変更する.(repetition_penalty はMoEで遊んでたときのものなのでデフォルトの1.0でもたぶん問題ない)

--- server.py	2025-12-27 11:24:04
+++ mlx_lm_server_hacked.py	2025-12-27 11:22:08
@@ -336,6 +336,9 @@
         self.min_p = self.body.get("min_p", self.model_provider.cli_args.min_p)
         self.repetition_penalty = self.body.get("repetition_penalty", 1.0)
         self.repetition_context_size = self.body.get("repetition_context_size", 20)
+        self.max_tokens = 4096
+        self.repetition_penalty = 1.1
+        logging.info(f"😈 Force Override: MaxTokens={self.max_tokens}, RepPenalty={self.repetition_penalty}")
         self.xtc_probability = self.body.get("xtc_probability", 0.0)
         self.xtc_threshold = self.body.get("xtc_threshold", 0.0)
         self.logit_bias = self.body.get("logit_bias", None)
@@ -700,8 +703,11 @@
             model=self.model,
             tokenizer=self.tokenizer,
             prompt=prompt,
-            max_tokens=self.max_tokens,
+            #max_tokens=self.max_tokens,
+            max_tokens=4096, #
             sampler=sampler,
+            kv_bits=4, #
+            max_kv_size=8192, #
             logits_processors=logits_processors,
             prompt_cache=self.prompt_cache.cache,
             draft_model=self.model_provider.draft_model,

サーバー起動はモデル指定だけになる.mlx_lm.sererコマンドでも良い.(ネットワーク内の別クライアントでも使いたい場合は--host 0.0.0.0)

python -m mlx_lm server \
  --model mlx-community/ABEJA-Qwen2.5-32b-Japanese-v0.1-4bit 

クライアント

設定は至ってシンプルでOpenAIを選んでlocalhost:8080を叩く.URLにv1を付けるとv1/v1を掘り始めるので不要.APIキーは何でもよいのでEMPTYとでも入れとく.