Windows AI Toolkitのconsole_chat.pyで「Can’t find ‘adapter_config.json’」が出る原因と完全解決(Phi‑3/LoRA対応)

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 を学習済みチェックポイントへ差し替える

  1. 学習/微調整が完了したチェックポイントのパスを確認します。例: ../models/checkpoints/checkpoint-1875 フォルダー直下に adapter_config.json と adapter_model.safetensors(または adapter_model.bin)があることを確認してください。
  2. console_chat.py の adapters_name を書き換えます。 # 修正前(サンプルのまま) # adapters_name = "../models/qlora/qlora/gpu-cpu_model/adapter" # 修正後(自身の環境に合わせて変更) adapters_name = "../models/checkpoints/checkpoint-1875"
  3. 再実行し、エラーが消え、会話推論が始まることを確認します。

フォルダー構成の目安

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] 指定なし:ベースモデルのみで起動します")
  

テストの流れ:失敗から成功までの確認手順

  1. 失敗の再現:サンプルのまま起動してエラーを確認(ログを控える)。
  2. パスの修正:adapters_name を学習済みチェックポイントへ。
  3. 存在チェック:adapter_config.json、adapter_model.* が直下にあるか確認。
  4. 再起動:推論が開始すること(プロンプトが表示され応答が返ること)を確認。
  5. 追加の堅牢化: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 つの導線を全て用意しておくとミスが激減します。

  1. 起動スクリプト(.bat/.ps1):モデル名を引数に渡すランチャー。
  2. 環境変数:AI_ADAPTER_PATH を作り、CI/ジョブスケジューラで差し替え。
  3. 設定ファイル(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-xxxxraw 文字列 or pathlib.Path を使用
LoRA 未所持アダプター自体が存在しないLoRA 読み込みをオフ(フォールバック起動)

最後に

本記事の要点はシンプルです。「まずは adapters_name を正しく」。これで adapter_config.json のエラーは解消します。そこから先は、引数化・環境変数・事前チェック・フォールバック・マージといった「壊れにくい設計」に寄せていけば、Windows AI Toolkit のサンプルはプロダクション準備の素地を備えます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次