Mac M1 MaxでLoRA学習に13回全敗してからRunPodで成功するまで
Mac Studio M1 Max 64GBがあるんだから、ローカルでSDXL系のLoRA学習くらいできるだろう。そう思って始めたら13回試行して全部失敗した。複数のAIエージェントに相談しながら設定を変え続けたが、Macでは最後まで「崩れた手」と「ERROR」の文字しか出なかった。最終的にRunPod RTX 4090に移行して成功するまでの全記録。
環境
- Mac Studio (M1 Max, 64GB RAM)
- Python 3.10 / PyTorch 2.x (MPS)
- ベースモデル: Illustrious-XL v1.0 (waiIllustriousSDXL_v160.safetensors)
- 学習スクリプト: kohya-ss/sd-scripts
学習データはこんな感じのキャラクター画像を59枚用意した。

症状
学習を開始するとLossは0.06付近で安定して下がっていく。数値上は学習が進んでいるように見える。しかしサンプル画像を生成すると、Epoch 1からEpoch 10まで一貫して崩れた手や**「ERROR」という謎の文字**が出力される。キャラクターが出る気配がまったくない。
13回の試行錯誤
v1〜v5: 基本設定の調整
普通のSDXL学習設定から開始。mixed_precisionをfp16とbf16で切り替え、OptimizerもAdamWとAdamW8bitを試した。ただしbitsandbytesがMacで動かない問題にぶつかり、AdamW8bitは使えなかった。
結果: 謎の手しか出ない。
v6〜v9: Mac特化設定
MPSバックエンドが怪しいと睨んで、Mac向けに最適化を試みた。
mixed_precision="no"でfp32を強制(メモリは食うが精度優先)- PyTorch 2.0のsdpa (Scaled Dot Product Attention) を使用
- xformersはMacで使えないため無効化
結果: 変わらず「手」。生成速度が遅くなっただけ。
v10〜v11: UNetのみ学習とキャッシュ全削除
テキストエンコーダーの学習がMPSでおかしくなっている仮説を立てて、network_train_unet_only = trueでUNetのみに絞った。既存の.npzキャッシュが壊れている可能性も考えて全削除・再生成。
結果: それでも「手」。むしろ「ERROR」の文字が鮮明になってきた。
v12: 1枚画像テスト
データセットに問題がある可能性を排除するため、クリーンな画像1枚だけで学習を実行。
結果: 1枚だろうが何だろうが「手」が出る。ここで心が折れかける。
v13: ステップ数の見直し(Claudeの指摘)
ここでClaude(Claude Code)に相談したところ、「1エポックあたりのステップ数が少なすぎる(12ステップしかない)」という指摘を受けた。num_repeatsを1→5に増やし、learning_rateを1e-4→5e-5に下げて再挑戦。
推論スクリプトで確認すると、ベースモデル自体は正常にキャラクターを生成できていた。モデルと環境は死んでいない。
結果: Epoch 1で「顔」らしきものが出た。が、Epoch 2に向かう途中で力尽きた。
関わったAIエージェントたち
この一連の作業には複数のAIエージェントが関わっている。
| エージェント | 役割 |
|---|---|
| Antigravity | 失敗ログ全体の作成・記録。v1〜v13の試行を通じて設定変更とログ出力を担当 |
| Claude (Claude Code) | v13でステップ数の不足を指摘。その後RunPod向けのv3設定・クイックスタート手順・確定チートシートの作成も担当 |
| Gemini | 成功事例の調査レポートを作成。6件の成功事例を収集し、失敗設定との比較表を生成 |
それぞれ別のタイミング・文脈で協力を求めた結果、ファイルが複数箇所に散らばっている。Mac全敗のフェーズではAntigravityとClaudeが中心で、原因調査でGeminiが入り、RunPod移行後のセットアップはClaudeと詰めた。
成功事例との設定差分
Geminiが収集した成功事例6件と、失敗した設定を比較すると明確な差分が浮かび上がる。
確実に問題だった設定
text_encoder_lr = 0(無効)
全成功事例でテキストエンコーダー学習が有効になっていた。これが0だとキャラクター特徴をプロンプトに紐づけできない。DCAI事例では5e-5、Prodigy使用事例では1.0(自動調整)に設定されていた。
clip_skip = 1
Illustrious系はclip_skip = 2が鉄板。成功事例すべてで2が使われている。
sdxl_no_half_vae 未設定
SDXL VAEはfp16で壊れるという既知問題がある。成功事例ではsdxl_no_half_vae = trueが明示的に設定されていた。
おそらく問題だった設定
network_dim=32, alpha=32(比率1.0)
成功事例ではalpha/dim比が0.125〜0.5。比率1.0はLoRA効果が強すぎてサンプル崩壊を引き起こす可能性がある。
repeats=1
59枚×1repeat=59ステップ/エポック。成功事例ではrepeats=5〜10で、総ステップ数1,400〜3,000が目安。
設定比較表
| パラメータ | 失敗設定 | DCAI(成功) | カズヤ弟氏(成功) |
|---|---|---|---|
| Optimizer | Adafactor | AdamW8bit | Prodigy |
| text_encoder_lr | 0 | 5e-5 | 1.0(自動) |
| network_dim | 32 | 8 | 8 |
| network_alpha | 32 | 1 | 4 |
| alpha/dim比 | 1.0 | 0.125 | 0.5 |
| clip_skip | 1 | 2 | 不明 |
| no_half_vae | 未設定 | 不明 | 不明 |
| repeats | 1 | 5 | 10 |
RunPodで再挑戦→成功
Macを諦め、RunPod RTX 4090に移行した。Geminiの調査レポートとClaudeとの設定詰めを経て、v3設定を確定。
環境
RunPod Template: RunPod Pytorch 2.1
GPU: RTX 4090
PyTorch: 2.1.2 + CUDA 11.8
sd-scripts: v0.8.7
xformers: 0.0.23.post1
致命的だった3パラメータ
Macでの13回の試行で一度も正しく設定できていなかった致命的なパラメータが3つある。
| パラメータ | 正しい値 | 間違えた値 | なぜ壊れるか |
|---|---|---|---|
no_half_vae | true | 未設定(false) | VAEがfp16でオーバーフロー→サンプル画像が破綻 |
text_encoder_lr | 5e-5 | 0 | トリガーワードとキャラ特徴が紐付かない |
clip_skip | 2 | 1 | Illustrious系はclip_skip=2で学習されている |
確定設定(抜粋)
[additional_network_arguments]
unet_lr = 1e-4
text_encoder_lr = 5e-5 # 0にしない
network_dim = 8
network_alpha = 1 # ratio = 0.125
network_train_unet_only = false # trueにしない
[optimizer_arguments]
optimizer_type = "AdamW8bit"
learning_rate = 1e-4
lr_scheduler = "cosine"
[training_arguments]
max_train_epochs = 10
clip_skip = 2 # 1にしない
no_half_vae = true # 必須
mixed_precision = "fp16"
xformers = true
[dataset]
num_repeats = 10
自動化スクリプト
Claudeと一緒に、RunPodでの学習を1コマンドで回せるスクリプトを2本作った。
runpod_train_final.sh — 環境セットアップから学習完了まで全自動。PyTorch 2.1.2+CUDA 11.8のインストール、sd-scripts v0.8.7のクローン、xformers/bitsandbytesの導入、設定ファイル生成、事前チェック(ベースモデル・学習データの存在確認、ステップ数計算、warmup自動算出)、そして学習実行まで一気に走る。
setup_comfyui_final.sh — 学習完了後にComfyUIをセットアップして生成テストするためのスクリプト。ベースモデルと出力LoRAをシンボリックリンクで配置し、RunPodのPort 8188でブラウザアクセスできるようにする。
手順はこうなる:
- RunPodでRTX 4090 / RunPod Pytorch 2.1 / Disk 50GBを起動
- scpでスクリプト2本、ベースモデル、学習データ(png+txt)をアップロード
bash runpod_train_final.shで学習開始- 完了後
bash setup_comfyui_final.shでComfyUI起動 - epoch 3,5,7,10あたりを比較してベストを選ぶ
結果
59枚×10repeats×10epochs = 5,900ステップ。RTX 4090で1.3 it/s、約75分で完了。Lossは0.06台で安定。
RunPod上でテスト生成した画像がこちら。





学習済みLoRAをダウンロードして、手元のComfyUIでも生成してみた。

RunPodでもローカルでも問題なく動く。Macで13回「崩れた手」しか出なかったのが嘘のように、ちゃんとキャラクターが出ている。
なぜsd-scripts直叩きだとハマるのか
kohya_ss GUIを使っている人はこの問題に遭遇しにくい。理由は単純で、GUIがデフォルトで正しい値を設定してくれるから。
no_half_vae: GUIでは「No half VAE」チェックボックスがデフォルトONtext_encoder_lr: GUIでは入力欄が見えるので自然と設定するclip_skip: GUIではモデル種別ごとのプリセットがある
sd-scriptsを直接叩くとこれらが全部デフォルト値(false/0/1)になる。設定ファイルに書かなければ存在しないのと同じ。Mac環境の問題だと思い込んで13回もMPS周りを弄っていたが、実際には設定値の問題がほとんどだった。
振り返り
Macでの13回全敗は「MPSの限界」ではなく「設定の問題」が大半だった可能性が高い。ただし、MacではAdamW8bit(bitsandbytes)やxformersが使えないという制約があり、NVIDIA環境と同じ土俵に立てない部分は確かにある。
RunPod RTX 4090は1時間あたり数十円程度。Mac環境でデバッグに費やした数時間と精神的コストを考えると、最初からクラウドGPUを借りるべきだった。