longcat: hand SimpleTuner its config the way it actually reads one (v0.2.58)

The venv built, SimpleTuner 4.9.3 installed, and the trainer RAN — the first time
anything past the setup has executed. It then failed on how it was invoked:

  ValueError: JSON configuration file not found. Paths tried: config/config.json

SimpleTuner takes no --config. Its loader picks a configuration BACKEND and asks
that backend where to look; the JSON one reads CONFIG_PATH (a file, or a directory
holding config.json) and otherwise defaults to ./config/config.json relative to
the working directory. The --config we passed was simply ignored, so it fell
through to the default and found nothing.

Now the backend is named (SIMPLETUNER_CONFIG_BACKEND=json) and the path handed
over in CONFIG_PATH, read from the installed package's own json_file.py rather
than guessed. The same config is also written to <workdir>/config/config.json, so
a loader change that ignored CONFIG_PATH would still find it.

Worth recording what this run proved, since all of it was unexercised an hour ago:
the vendored source resolves, the training venv rebuilds itself with a 3.12+
interpreter, SimpleTuner installs from PyPI into it, and the job reaches
SimpleTuner's own argument parsing. The dataset built from the township clips has
not been read yet — that is the next thing in the way.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
parent 79ee74cd
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API # Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here. # metadata and the admin web UI read from here.
__version__ = "0.2.57" __version__ = "0.2.58"
__tagline__ = "Complete orchestration, distribution and escalation of remotizable advanced inference." __tagline__ = "Complete orchestration, distribution and escalation of remotizable advanced inference."
# Configure the CUDA caching allocator BEFORE torch is imported anywhere. # Configure the CUDA caching allocator BEFORE torch is imported anywhere.
......
...@@ -113,3 +113,27 @@ def test_progress_from_the_worker_is_accepted(monkeypatch, dataset): ...@@ -113,3 +113,27 @@ def test_progress_from_the_worker_is_accepted(monkeypatch, dataset):
loras._train_externally("longcat", _req(dataset_config=str(dataset)), loras._train_externally("longcat", _req(dataset_config=str(dataset)),
"/models/longcat", [], "p", 10, 4, "480x832", 1e-4, 1) "/models/longcat", [], "p", 10, 4, "480x832", 1e-4, 1)
assert got and got[0]["step"] == 3 and got[0]["total"] == 9 assert got and got[0]["step"] == 3 and got[0]["total"] == 9
# ── how SimpleTuner is actually invoked ─────────────────────────────────────
def test_the_config_is_handed_over_the_way_simpletuner_reads_it():
"""SimpleTuner takes no --config. Its loader picks a configuration BACKEND and
asks that backend where to look; the JSON one reads CONFIG_PATH and otherwise
defaults to ./config/config.json relative to cwd. Passing --config produced:
ValueError: JSON configuration file not found. Paths tried: config/config.json
"""
src = (ROOT / "tools" / "longcat_train.py").read_text(encoding="utf-8")
assert '"--config", str(cfg_path)' not in src, "that argument is ignored"
assert 'env["CONFIG_PATH"] = str(cfg_path)' in src
assert 'env["SIMPLETUNER_CONFIG_BACKEND"] = "json"' in src
assert "env=env" in src, "the environment must reach the child"
def test_the_config_is_also_written_where_the_default_lookup_finds_it():
"""Belt and braces: if a loader change ignored CONFIG_PATH, the default
./config/config.json is there too."""
src = (ROOT / "tools" / "longcat_train.py").read_text(encoding="utf-8")
assert 'fallback = workdir / "config"' in src
assert '(fallback / "config.json").write_text' in src
...@@ -133,9 +133,27 @@ def main(argv=None) -> int: ...@@ -133,9 +133,27 @@ def main(argv=None) -> int:
+ (f", base {cfg['base_model_precision']}" + (f", base {cfg['base_model_precision']}"
if cfg.get("base_model_precision") else ", bf16 base")) if cfg.get("base_model_precision") else ", bf16 base"))
cmd = [sys.executable, "-m", "simpletuner.train", "--config", str(cfg_path)] # SimpleTuner does NOT take --config. Its loader picks a configuration
# BACKEND and then asks that backend where to look; the JSON one reads
# CONFIG_PATH (a file, or a directory holding config.json) and otherwise
# defaults to ./config/config.json relative to the working directory —
# which is what produced
# ValueError: JSON configuration file not found. Paths tried: config/config.json
# So the backend is named explicitly and the path handed over in the
# environment, rather than as an argument it ignores.
env = os.environ.copy()
env["SIMPLETUNER_CONFIG_BACKEND"] = "json"
env["CONFIG_PATH"] = str(cfg_path)
# Belt and braces: the default lookup is ./config/config.json relative to
# cwd, so the same file is placed there too. A loader change that ignored
# CONFIG_PATH would still find it.
fallback = workdir / "config"
fallback.mkdir(parents=True, exist_ok=True)
(fallback / "config.json").write_text(json.dumps(cfg, indent=2))
cmd = [sys.executable, "-m", "simpletuner.train"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
text=True, bufsize=1, cwd=str(workdir)) text=True, bufsize=1, cwd=str(workdir), env=env)
total = int(cfg["max_train_steps"]) total = int(cfg["max_train_steps"])
last = -1 last = -1
tail = [] tail = []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment