3行でいうと

  • mlx-lmのコマンドは mlx_lm.lora。モデルが量子化済みならQLoRA、そうでなければ普通のLoRAになります。
  • 学習データは train.jsonl(1行に1例)で、chat・tools・completions・textの4形式です。
  • 公式文書の32GB向けの例は、7Bモデル、batch-size 1、num-layers 4で、M1 Maxで約250トークン/秒です。
  • メモリを減らす手は、QLoRA、バッチ縮小、層数削減、短い例、勾配チェックポイントの5つです。

この記事は、実際に使って確かめた記録ではありません。この記事は公式の文書や論文を読んでまとめたものです。数字の計算は、設定ファイルの値から僕らが行ったものです。

先に結論

Macで「自分のデータでモデルを少し賢くする」には、mlx-lmの mlx_lm.lora が公式の入口です。モデル全部を学習し直すのではなく、モデルの横に小さな追加部品(アダプター)を付けて、そこだけを学習します。これがLoRA(Low-Rank Adaptation、低ランク適応)です。

公式文書は、メモリ32GBのマシンで「そこそこ速く動く」例として、7Bモデルを最小限の設定(バッチ1、4層)で動かす例を挙げています。それより大きいモデルや長い学習データについて、公式文書に目安の数字はありません。

見立てです。32GBのMacで7B前後は試せる範囲だと読めますが、確かめてはいません。最初は、小さいモデル(公式の設定例が使っているのは1Bクラス)と数百行のデータで、手順とメモリの減り方を体感してから広げるのが安全だと思います。

前提:何をする話か

mlx-lmとは

公式READMEによると、mlx-lmは、Apple siliconで、MLX(Appleの機械学習の枠組み)を使って、文章生成と大規模言語モデルの微調整をするPythonパッケージです。低ランク(LoRA)と全体の微調整の両方に対応し、量子化したモデルも扱えます。入れ方は pip install mlx-lm(condaも可)です。PyPIで見える最新版は0.32.0(2026年10月1日公開)で、Pythonは3.11以上を要求します。

微調整に必要な追加部品は、pip install "mlx-lm[train]" で入ります。

手順:公式文書の流れ

1. 学習データを用意する

--data に、train.jsonl を入れたフォルダを指定します。valid.jsonl(検証用)は任意で、あれば学習中に検証の損失(loss)が報告されます。学習後の評価(--test)には test.jsonl が要ります。公式文書の注意書きでは、1つの例は必ず1行に収め、複数の例を1行に入れたり、1つの例を複数行に割ったりしてはいけません。

形式は4つです。ファイルの中身から自動で判定されます。

形式 1行の中身 使いどころ(見立てです)
chat messages(役割と本文のリスト) 会話の口調や応答の形を覚えさせる
tools messages と tools(関数の定義) 道具の呼び出しの形を覚えさせる
completions prompt と completion 質問と答えのペア
text text だけ 自分で整形した文章をそのまま学習させる

公式文書は、迷ったら chat か completions から始めるよう勧めています。chat・tools・completions では、モデル固有の「チャットテンプレート」(会話を並べる決まった書式)が自動で当てはまります。

2. 学習する

公式文書の例です。この記事では、実行していません。

mlx_lm.lora \
    --model <path_to_model> \
    --train \
    --data <path_to_data> \
    --iters 600

--model には、Hugging Faceのリポジトリ名か、手元のフォルダを指定できます。--model が量子化済みのモデルならQLoRA、そうでなければ普通のLoRAになる、と公式は書いています。

結果は既定で adapters/ に保存されます。--adapter-path で場所を変えられ、--resume-adapter-file で途中から再開できます。YAML設定ファイルは -c で渡せ、コマンドラインの指定が優先されます。

3. 評価して、試しに生成する

--test を付けると、テスト用データでの損失から perplexity(困惑度、低いほど予測が当たっている)を出します。生成は mlx_lm.generate に --adapter-path を付けます。

4. アダプターをモデルに溶かす(fuse)

mlx_lm.fuse で、アダプターを元のモデルに統合した新しいモデルができます(既定の保存先は fused_model/)。Hugging Faceへのアップロードもできます。GGUF形式への書き出し(--export-gguf)もありますが、公式文書は「MistralとMixtralとLlama系で、fp16の場合に限る」と書いています。

設定の既定値(ソースコードで確認)

mlx_lm/lora.py の CONFIG_DEFAULTS(2026年10月8日にmainブランチで確認)の主な値です。

項目 既定値 意味
fine_tune_type lora lora・dora・full から選ぶ
optimizer adam 学習の更新方法
num_layers 16 後ろから数えて何層を学習するか(-1で全部)
batch_size 4 一度に処理する例の数
iters 1000 学習の回数
learning_rate 1e-5 学習の速さ
max_seq_length 2048 1つの例の最大トークン数
grad_checkpoint False 勾配チェックポイント(後述)
lora_parameters rank 8、scale 20.0、dropout 0.0 LoRAの部品の大きさなど

注意点が2つあります。まず、lora_parameters はコマンドラインでは指定できず、YAML設定ファイルでのみ変えられます(設定例のコメントに書かれています)。次に、公式のYAML例では対象を self_attn.q_proj と self_attn.v_proj(注意機構の2つの行列)に絞っていますが、keys を書かない場合、ソースコードの linear_to_lora_layers は、対象の層の中にある線形層をすべて自動で拾う作りに見えます。この記事は、実際に使って確かめた記録ではありません。

メモリの目安

Mistral 7Bで見る、学習する部品の数と重みの大きさ

僕らの計算です。Mistral-7B-v0.1の設定ファイル(Hugging Faceのconfig.json)は、隠れ層の幅4,096、層数32、中間層の幅14,336、KVヘッド数8(Keyの出力幅は1,024)です。パラメータ数は、Hugging Faceの情報で7,241,732,096個です。

重みの大きさ

BF16(1つ2バイト)なら約14.5GB、4ビット(1つ0.5バイト)なら約3.6GBです。4ビットの値は、量子化の細かい上乗せを含まない概算です。

LoRAで学習する数

LoRAは、入力幅×出力幅の行列1枚につき、rank×(入力幅+出力幅)個を足します。rank 8で計算すると、次のとおりです。

対象 1層あたり 16層 全体に対する割合
q_projとv_projだけ 106,496個 約170万個 約0.02%
注意機構の4つ+MLPの3つ(全部の線形層) 655,360個 約1,049万個 約0.14%

学習する数は、全体の1%にも届きません。QLoRAの論文は、7Bモデルで、学習する部品が約26MBなのに対して、4ビットの本体は5,048MBだったと報告しています。ただし、同じ論文は、メモリの大半は「活性化の勾配」(学習の途中で必要になる一時データ)で、部品の数を減らしても節約は小さい、とも述べています。

論文の数字

  • LoRA論文:GPT-3 175Bで、学習時のVRAMが1.2TBから350GBになり、チェックポイントの大きさがrank 4・q/vのみの場合に350GBから35MBになる。
  • QLoRA論文:16ビットで65Bを微調整すると780GB超のGPUメモリが要る。7B(バッチ1)で、LoRAの入力の勾配が567MB、勾配チェックポイントありなら1シーケンスあたり平均18MB。

公式文書の「32GB」の例

公式文書の「Memory Issues」節は、32GBのマシンで「そこそこ速く動く」例として、次を挙げています。公式文書の例です。この記事では、実行していません。

mlx_lm.lora \
    --model mistralai/Mistral-7B-v0.1 \
    --train \
    --batch-size 1 \
    --num-layers 4 \
    --data  mlx-community/wikisql

文書は、M1 Max(32GB)で、この命令が約250トークン/秒だったと書いています。データは wikisql(SQL生成のデータ)です。

見立てです。この例は量子化されていないモデルの名前を指しているので、上のルールどおりなら、普通のLoRAです。重みだけで約14.5GBあり、32GBの半分近くを占めます。残りにOSと学習中の一時データが入ることになります。文書に、このときの実際のメモリ使用量は書かれていません。

メモリを減らす5つの手

公式文書は、次の順に挙げています。

  1. QLoRA:量子化したモデルを使う。公式は、convert に -q を付けて作る方法を案内しています。READMEには mlx_lm.convert --model ... -q もあります。
  2. バッチを小さくする:--batch-size(既定4)を2か1にする。遅くはなるが、メモリは減る。--grad-accumulation-steps N で、メモリを増やさずに実質のバッチを大きくできる。
  3. 学習する層を減らす:--num-layers(既定16)を8や4にする。メモリは減るが、データが多いと品質が下がることがある。
  4. 例を短くする:長い例ほどメモリを使う。区切れるなら、短い列に分けてファイルを作る。
  5. 勾配チェックポイント:--grad-checkpoint。途中の値を保存せず、必要なときに計算し直すことで、メモリを節約して計算量を増やす方法。バッチや列が長いとき、あるいは小さい・量子化したモデルのときに、より効果がある、と公式は書いています。

もう一つ、READMEの「Large Models」節に、macOS 15以上で、モデルがメモリに対して大きいとき、sudo sysctl iogpu.wired_limit_mb=N でGPUが使える固定メモリの上限を上げられる、とあります。Nはモデルの大きさ(MB)より大きく、マシンのメモリ量より小さい値にします。学習のコード側でも、maybe_set_recommended_wired_limit で推奨値に設定する処理を呼んでいます。

判断の基準

見立てです。

よくあるつまずき

気をつけること

出典

更新履歴