Windows AI Toolkit のサンプル console_chat.py を実行した際に Can't find 'adapter_config.json' で止まる――多くは LoRA/QLoRA のアダプターパスがダミーのまま、または学習済みチェックポイントを指していないことが原因です。本記事では根本原因の解説から、最短の修正方法、堅牢化のためのコード例、運用ベストプラクティスまで一気にまとめます。
console_chat.py で adapter_config.json が見つからない原因と解決の全体像
症状
RuntimeError: Can't find 'adapter_config.json'
サンプルをそのまま起動すると、上記のエラーで推論が始まらないことがあります。
根本原因
console_chat.py内のadapters_name変数がダミーパスのままで、実際の学習・微調整で生成した LoRA/QLoRA のチェックポイントを指していない。- 結果として指定フォルダーに
adapter_config.jsonが存在せず、PEFT ローダーが初期化に失敗する。
結論
Windows AI Toolkit や Phi‑3 本体を更新する必要はありません。正しくは adapters_name に 自分の学習済みチェックポイント(例:../models/checkpoints/checkpoint-1875)を設定します。
最短解決:adapters_name を学習済みチェックポイントへ差し替える
- 学習/微調整が完了したチェックポイントのパスを確認します。例:
../models/checkpoints/checkpoint-1875フォルダー直下にadapter_config.jsonとadapter_model.safetensors(またはadapter_model.bin)があることを確認してください。 console_chat.pyのadapters_nameを書き換えます。# 修正前(サンプルのまま) # adapters_name = "../models/qlora/qlora/gpu-cpu_model/adapter" # 修正後(自身の環境に合わせて変更) adapters_name = "../models/checkpoints/checkpoint-1875"- 再実行し、エラーが消え、会話推論が始まることを確認します。
フォルダー構成の目安
checkpoint-1875/
├─ adapter_config.json
├─ adapter_model.safetensors # or adapter_model.bin
├─ trainer_state.json # 環境によって有無あり
└─ その他学習時の補助ファイル
原因をもう少し深掘り:adapter_config.json とは
LoRA/QLoRA は「ベースモデル」に「アダプター重み」を差し込む仕組みです。adapter_config.json は PEFT(Parameter-Efficient Fine-Tuning)で保存されたアダプターのメタ情報(タスク種別、ターゲットモジュール、ランク r など)を持ち、推論時に AutoModelForCausalLM + PeftModel がこれを読んで初期化します。
| 項目 | 役割 | 補足 |
|---|---|---|
| adapter_config.json | アダプターのハイパーパラメータ・メタ情報 | PEFT のバージョンやタスク種別なども含む |
| adapter_model.safetensors / .bin | アダプターの重み | 通常は .safetensors 推奨 |
| ベースモデル(Phi‑3 等) | 土台となる大規模言語モデル | Hugging Face から取得 or ローカル配置 |
Windows ならではのパスの落とし穴と対策
- バックスラッシュとエスケープ:Python 文字列では
\\またはr"..."(raw 文字列)を使う。例:r"C:\models\checkpoints\checkpoint-1875" - スペース/日本語/OneDrive パス:空白や日本語を含むパスを避けるか、引用符で明示する。長い同期パスは遅延・競合の原因に。
- 相対パスの起点:
python console_chat.pyを「どこで実行したか」で相対パスの解釈が変わる。混乱を避けるには 絶対パスを推奨。 - 権限:UAC やフォルダー権限で読み取りを阻害しないか確認。VS Code の統合ターミナルと外部ターミナルで権限/ワーキングディレクトリが異なる場合がある。
チェック表(最初に見るべき項目)
| 確認項目 | OK 条件 | NG のサイン |
|---|---|---|
| パスが学習済みチェックポイントを指す | checkpoint-xxxx/adapter_config.json が存在 | フォルダー直下に adapter_config.json が無い |
| 文字列リテラルの扱い | r"C:\..." か "C:\\..." を使用 | "C:\n" などで意図せぬエスケープ |
| 実行場所 | 絶対パス or 実行ディレクトリ基準が合っている | 相対パスが FileNotFoundError を引き起こす |
| ファイルロック | 同期ツールによるロック無し | OneDrive/ウイルス対策により読み取り失敗 |
堅牢化:スクリプト側を「壊れにくく」する変更例
1) pathlib とバリデーションで事前に検知
from pathlib import Path
adapters_name = r"C:\models\checkpoints\checkpoint-1875" # ← ここを自環境に合わせる
adapter_dir = Path(adapters_name)
if not adapter_dir.exists():
raise FileNotFoundError(f"[adapter] 指定パスが存在しません: {adapter_dir}")
cfg = adapter_dir / "adapter_config.json"
weights_bin = adapter_dir / "adapter_model.bin"
weights_sft = adapter_dir / "adapter_model.safetensors"
if not cfg.exists():
raise RuntimeError(f"[adapter] adapter_config.json が見つかりません: {cfg}")
if not (weights_bin.exists() or weights_sft.exists()):
raise RuntimeError("[adapter] アダプター重みが見つかりません(bin/safetensors)")
2) コマンドライン引数でパスを外出し
環境ごとに console_chat.py を編集し続けるのは非効率です。argparse で --adapters を追加し、運用をラクにします。
import argparse
from pathlib import Path
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--adapters", type=str, default="", help="LoRA/QLoRA adapter checkpoint dir")
p.add_argument("--base_model", type=str, default="microsoft/Phi-3-mini-4k-instruct")
return p.parse_args()
args = parse_args()
adapters_name = args.adapters.strip()
if adapters_name:
adapter_dir = Path(adapters_name)
if not (adapter_dir / "adapter_config.json").exists():
raise RuntimeError(f"[adapter] adapter_config.json が見つかりません: {adapter_dir}")
else:
print("[adapter] 指定なし:LoRA を読み込まずベースモデルのみで起動します")
3) 「LoRA なし」でのフォールバックを実装
アダプターが無い場合は、ベースモデル単体で動かす設計に。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(
args.base_model,
torch_dtype="auto",
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(args.base_model)
if adapters_name:
model = PeftModel.from_pretrained(base_model, adapters_name)
else:
model = base_model # LoRA 無し
4) 環境変数で切り替え(CI/CD・複数環境向け)
import os
adapters_name = os.getenv("AI_ADAPTER_PATH", adapters_name)
CI、複数マシン、複数バージョンを使い分ける際にヒューマンエラーを減らせます。
補足:LoRA をマージして「単体モデル」にする運用
配布や実行を簡素化したい場合、学習後に LoRA をベースモデルへマージして一体化したモデルを保存する方法があります。これにより adapter_config.json を参照せずに推論できます(容量は増えます)。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
BASE = "microsoft/Phi-3-mini-4k-instruct"
ADAPTER_DIR = r"C:\models\checkpoints\checkpoint-1875"
OUT = r"C:\models\merged\phi3-lora-merged"
base = AutoModelForCausalLM.from_pretrained(BASE, torch_dtype="auto")
model = PeftModel.from_pretrained(base, ADAPTER_DIR)
merged = model.merge_and_unload() # LoRA をベースに統合
merged.save_pretrained(OUT)
tok = AutoTokenizer.from_pretrained(BASE)
tok.save_pretrained(OUT)
# 以後は OUT をベースモデルとしてそのまま読み込める
メリット:
- 配布が楽(フォルダー一つで完結)。
- 起動がシンプル(
adapters_name管理が不要)。
デメリット:
- サイズ増(LoRA 分が取り込まれる)。
- 再トレーニングやアブレーション時に可搬性が下がる。
高頻度で迷うポイント Q&A
Q. Phi‑3 や Windows AI Toolkit の「最新版」に更新すべき?
A. 本件に関しては不要です。原因はパス設定であり、adapters_name が学習済みチェックポイントを指していないことが大半です。
Q. checkpoint-xxxx ではなく adapter/ サブフォルダー配下にある場合は?
A. adapter_config.json が 存在するディレクトリ を adapters_name に指定します。階層が一段深いケースでは、.../checkpoint-1875/adapter など、実ファイルのある直下を指すようにしてください。
Q. adapter_model.bin と .safetensors の違いは?
A. どちらもアダプター重みです。.safetensors は安全性・読み込み速度の観点から一般に推奨されます。いずれにせよ adapter_config.json が隣接している必要があります。
Q. 学習していない(LoRA を持っていない)場合は?
A. LoRA なしで起動すれば問題ありません。上の「フォールバック」例を参考に、adapters_name を空にしてベースモデルのみで動かしてください。
Q. 4bit/QLoRA で学習したけれど推論時の精度が不安定です
A. 学習時と推論時の量子化設定(例:bnb_4bit_compute_dtype など)や torch_dtype のミスマッチが影響します。ベースモデルとアダプター読み込み時の dtype を合わせ、VRAM/メモリの制約に応じて調整してください。
Q. OneDrive 配下で動かすと時々失敗します
A. 同期中のファイルロックや遅延が失敗の原因になることがあります。学習・推論用の作業ディレクトリはローカル固定パス(例:D:\ai\models)にするのが無難です。
実用的な改修:差分パッチ例
サンプルに最小限の堅牢性を与えるためのパッチ例(概念コード)です。
--- a/console_chat.py
+++ b/console_chat.py
@@
- adapters_name = "../models/qlora/qlora/gpu-cpu_model/adapter"
+ # 推奨:引数(--adapters)と環境変数(AI_ADAPTER_PATH)を優先
+ import os, argparse
+ from pathlib import Path
+
+ def parse_args():
+ p = argparse.ArgumentParser()
+ p.add_argument("--adapters", type=str, default="")
+ p.add_argument("--base_model", type=str, default="microsoft/Phi-3-mini-4k-instruct")
+ return p.parse_args()
+
+ args = parse_args()
+ adapters_name = os.getenv("AI_ADAPTER_PATH", args.adapters).strip()
+
+ if adapters_name:
+ adapter_dir = Path(adapters_name)
+ cfg = adapter_dir / "adapter_config.json"
+ if not cfg.exists():
+ raise SystemExit(f"[adapter] adapter_config.json が見つかりません: {cfg}")
+ else:
+ print("[adapter] 指定なし:ベースモデルのみで起動します")
テストの流れ:失敗から成功までの確認手順
- 失敗の再現:サンプルのまま起動してエラーを確認(ログを控える)。
- パスの修正:
adapters_nameを学習済みチェックポイントへ。 - 存在チェック:
adapter_config.json、adapter_model.*が直下にあるか確認。 - 再起動:推論が開始すること(プロンプトが表示され応答が返ること)を確認。
- 追加の堅牢化:CLI 引数対応、環境変数対応、パスバリデーションを組み込み。
トラブルを未然に防ぐベストプラクティス
- チェックポイントの選び方:最終エポック or 評価指標が最良のエポックのフォルダーを採用。
- パス管理の一元化:
.envや設定ファイルでBASE_MODEL_PATH、ADAPTER_PATHを定義し、コードから参照。 - 命名規約:
adapter-{日付}-{実験名}のように分かる名前にする。 - 検証スクリプト:起動前に
adapter_config.jsonの存在と JSON の整合性をチェックする小スクリプトを用意。 - 環境分離:学習用と推論用で仮想環境を分け、依存関係の競合を防止。
簡易バリデーター(起動前チェック)
import json
from pathlib import Path
def validate_adapter_dir(p: str):
d = Path(p)
cfg = d / "adapter_config.json"
ok = d.exists() and cfg.exists()
detail = {}
if ok:
try:
detail = json.loads(cfg.read_text(encoding="utf-8"))
except Exception as e:
raise RuntimeError(f"adapter_config.json が不正です: {e}")
return ok, detail
ok, info = validate_adapter_dir(r"C:\models\checkpoints\checkpoint-1875")
print("OK:", ok)
if ok:
print("peft_type:", info.get("peft_type"), "task_type:", info.get("task_type"))
運用の現実解:チーム/複数モデルの切り替え
複数の LoRA を同じ console_chat.py で切り替えるなら、以下の 3 つの導線を全て用意しておくとミスが激減します。
- 起動スクリプト(.bat/.ps1):モデル名を引数に渡すランチャー。
- 環境変数:
AI_ADAPTER_PATHを作り、CI/ジョブスケジューラで差し替え。 - 設定ファイル(YAML/JSON):
profiles.default.adapter_pathのようなキーで明示。
| 方式 | 利点 | 注意点 |
|---|---|---|
| 引数 | 一時的な切替に強い | 打ち間違い対策に補完やランチャーを併用 |
| 環境変数 | CI やジョブ実行に相性良し | セッションごとに有効範囲が変わる |
| 設定ファイル | 再現性と可読性が高い | 配布時の置き換え漏れに注意 |
よくあるエラー別の対処早見表
| メッセージ/症状 | 想定原因 | 対処 |
|---|---|---|
Can't find 'adapter_config.json' | adapters_name がダミー/誤パス | 正しいチェックポイントへ差し替え。存在チェックをコードに組み込み。 |
FileNotFoundError(Windows のパス) | バックスラッシュのエスケープ/相対パスの誤り | raw 文字列 or pathlib、絶対パスを使用。 |
| 推論は動くが応答が変 | 学習時と dtype/量子化が不一致 | torch_dtype、4bit 設定を学習時に合わせる。 |
| ときどき読み込み失敗 | 同期/ウイルス対策によるロック | ローカル固定パスへ移動、除外設定を検討。 |
セキュリティと配布の観点
- 権限管理:チェックポイントへの読み取り権限を最小限に。
- 秘匿情報:学習データやプロンプトに機密が含まれる場合、作業領域の暗号化とアクセス制御を。
- 配布ポリシー:マージ済みモデルの再配布はライセンスに注意(学習元モデル・データセットの条件に従う)。
まとめ
console_chat.py の Can't find 'adapter_config.json' は、ほぼ確実にアダプターパスの設定ミスです。adapters_name を学習済みチェックポイントへ正しく向け直すだけで解消します。さらに、引数化・環境変数化・事前バリデーション・LoRA なしフォールバック・マージ運用を押さえておけば、サンプルは本番運用に耐える堅牢さを獲得します。更新よりもまず「パス」。ここを正せば、Phi‑3 ベースの対話推論はすぐに動きます。
付録:コピペで使える最小テンプレート
"""
Windows AI Toolkit 付属の console_chat.py を堅牢化した最小テンプレート(概念コード)
"""
import os
from pathlib import Path
from argparse import ArgumentParser
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
def parse_args():
p = ArgumentParser()
p.add_argument("--base_model", type=str, default="microsoft/Phi-3-mini-4k-instruct")
p.add_argument("--adapters", type=str, default="")
return p.parse_args()
def resolve_adapter_dir(p: str) -> Path | None:
p = p.strip()
if not p:
p = os.getenv("AI_ADAPTER_PATH", "").strip()
if not p:
return None
d = Path(p)
cfg = d / "adapter_config.json"
if not (d.exists() and cfg.exists()):
raise SystemExit(f"[adapter] 不正なパスです: {d}")
return d
def load_model(base: str, adapter_dir: Path | None):
tokenizer = AutoTokenizer.from_pretrained(base)
base_model = AutoModelForCausalLM.from_pretrained(base, torch_dtype="auto", device_map="auto")
if adapter_dir:
model = PeftModel.from_pretrained(base_model, adapter_dir)
else:
print("[adapter] なし:ベースモデルのみで起動")
model = base_model
return tokenizer, model
if **name** == "**main**":
args = parse_args()
adapter_dir = resolve_adapter_dir(args.adapters)
tok, model = load_model(args.base_model, adapter_dir)
# 以降、既存の対話ループを接続
付録:チェックリスト(印刷用)
- ✅
adapters_nameはcheckpoint-xxxx(adapter_config.json直下)を指している - ✅ パスは raw 文字列/
pathlibを使用 - ✅ 相対パスの起点を把握 or 絶対パス採用
- ✅ OneDrive/同期は学習・推論フォルダーから外す
- ✅ 引数/環境変数でパスを外出し(再現性確保)
- ✅ LoRA なしフォールバック or マージ運用を準備
発生条件と対処の対応表
| 発生条件 | ファイル状況 | 修正内容 |
|---|---|---|
| サンプルのまま起動 | ダミーパスで adapter_config.json なし | adapters_name を自分の checkpoint-xxxx に変更 |
| ディレクトリ階層違い | checkpoint-xxxx/adapter/adapter_config.json | 実ファイル直下(.../adapter)を指定 |
| Windows パス文字列の崩れ | C:\models\...\checkpoint-xxxx | raw 文字列 or pathlib.Path を使用 |
| LoRA 未所持 | アダプター自体が存在しない | LoRA 読み込みをオフ(フォールバック起動) |
最後に
本記事の要点はシンプルです。「まずは adapters_name を正しく」。これで adapter_config.json のエラーは解消します。そこから先は、引数化・環境変数・事前チェック・フォールバック・マージといった「壊れにくい設計」に寄せていけば、Windows AI Toolkit のサンプルはプロダクション準備の素地を備えます。

コメント