Repository navigation
Add AGENTS.md, CLAUDE.md #1480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add AGENTS.md, CLAUDE.md #1480
Changes from all commits
0fe37fc
7ad6b6c
6d3356e
4d00a21
3a86c17
3b8214c
4c9c012
25366c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| # AGENTS.md | ||
|
|
||
| OneTrainer trains diffusion models with full fine-tune / LoRA / embedding / | ||
| FINE_TUNE_VAE methods. Built on `diffusers` + PyTorch + | ||
| [`mgds`](https://github.com/Nerogar/MGDS). Supported families: | ||
| `modules/util/enum/ModelType.py`. | ||
|
|
||
| ## Run | ||
|
|
||
| ``` | ||
| pre-commit install # install OUTSIDE the project venv | ||
| pre-commit run --all-files # mandatory before every PR | ||
| python scripts/train.py --config-path <preset.json> [--secrets-path secrets.json] | ||
| python scripts/train_ui.py # GUI (CustomTkinter) | ||
| ``` | ||
|
|
||
| Every `scripts/*.py` (except `generate_debug_report.py`) starts with `script_imports()` | ||
| from `scripts/util/import_util.py`: it fixes `sys.path`, filters xformers/Triton noise, | ||
| and bootstraps ZLUDA. Don't try to replicate it from a bare `python -c`. | ||
|
|
||
| There is **no automated test suite.** Verification is launching scripts and exercising | ||
| the change. | ||
|
|
||
| ## Layout | ||
|
|
||
| ``` | ||
| modules/ | ||
| model/ BaseModel subclasses — state (weights, optim, EMA, embeddings) | ||
| modelLoader/ BaseModelLoader — ckpt/safetensors/diffusers → model | ||
| modelSetup/ BaseModelSetup — optimizer, LR, grad checkpointing, device | ||
| dataLoader/ BaseDataLoader — wraps mgds dataset; bucketing, aug, captions | ||
| modelSampler/ BaseModelSampler — preview/inference sampling | ||
| modelSaver/ BaseModelSaver — model → disk | ||
| trainer/ BaseTrainer, GenericTrainer (main loop), CloudTrainer (RunPod), MultiTrainer | ||
| module/ | ||
| EMA / LoRA / OFT / AdditionalEmbedding training wrappers | ||
| quantized/ Fp8 / Nf4 / W8A8 / GGUFA8 / SVD linear layers | ||
| Blip / ClipSeg / WD / Rembg / HPSv2 / AestheticScore backends for caption_ui / generate_* | ||
| ui/ CustomTkinter; one *UI/*Tab/*Window per screen. | ||
| TrainUI extends ctk.CTk; others extend ctk.CTkToplevel. | ||
| util/ | ||
| create.py ★ factory — TrainConfig → pipeline | ||
| factory.py auto-discovery (import_dir + class registry) | ||
| config/ TrainConfig + sub-configs (Sample, Concept, Cloud, Secrets) | ||
| enum/ ModelType, Optimizer, LearningRateScheduler, NoiseScheduler, | ||
| TrainingMethod, DataType, ... | ||
| callbacks/ TrainCallbacks (training-loop event hooks) | ||
| commands/ TrainCommands (UI → trainer signals) | ||
| optimizer/ CAME / adam / adamw / adafactor / muon extensions | ||
| ui/ UIState, components.py, validation.py | ||
| LayerOffloadConductor.py ⚠ fragile VRAM offloading; incompatible with dataloader_threads > 1 | ||
| zluda/ Windows AMD shim; disables cuDNN / flash_sdp / mem_efficient_sdp / cudnn_sdp | ||
|
|
||
| scripts/ | ||
| util/import_util.py ★ script_imports() — sys.path + ZLUDA bootstrap; called first by every script | ||
| train.py / train_ui.py / train_remote.py / sample.py | ||
| caption_ui.py / convert_model_ui.py / video_tool_ui.py | ||
| generate_captions.py / generate_masks.py / convert_model.py / calculate_loss.py | ||
| create_train_files.py / install_zluda.py / generate_debug_report.py | ||
|
|
||
| training_presets/ ~50 partial-override JSONs of TrainConfig defaults, "#<model> <method>[ <vram>].json" | ||
| embedding_templates/ plain-text prompt files (`<embedding>` placeholder); .gitignore excludes user files | ||
| resources/ icons + sd_model_spec/*.json | ||
| docs/ ProjectStructure / Contributing / QuickStartGuide / CliTraining / | ||
| EmbeddingTraining / CaptioningAndMasking / RamOffloading / DockerImage | ||
| LAUNCH-SCRIPTS.md OT_* env vars, venv/conda selection | ||
| lib.include.sh runtime/venv/conda bootstrap; forces PYTORCH_ENABLE_MPS_FALLBACK=1 on macOS | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Factory + auto-discovery (`modules/util/create.py`) | ||
|
|
||
| `create_trainer(config, callbacks, commands)` is the top-level entry: returns | ||
| `CloudTrainer` if `config.cloud.enabled`, `MultiTrainer` if `config.multi_gpu`, else | ||
| `GenericTrainer` (the only branch that calls `ZLUDA.initialize_devices`). | ||
|
|
||
| `GenericTrainer.start()` then calls per-layer factories in order: | ||
| `create_model_loader → create_model_setup → create_data_loader → create_model_saver → | ||
| create_model_sampler`. | ||
|
|
||
| The selection mechanism for those five "per-model" layers is **auto-discovery**: | ||
|
|
||
| ```python | ||
| factory.import_dir("modules/modelSampler", "modules.modelSampler") | ||
| factory.import_dir("modules/modelLoader", "modules.modelLoader") | ||
| factory.import_dir("modules/modelSaver", "modules.modelSaver") | ||
| factory.import_dir("modules/modelSetup", "modules.modelSetup") | ||
| factory.import_dir("modules/dataLoader", "modules.dataLoader") | ||
| ``` | ||
|
|
||
| Dropping a file with the right base class in any of those five directories registers | ||
| it — you do **not** edit `create.py` to register new per-model classes. You **do** edit | ||
| `create.py` for `create_optimizer`, `create_ema`, `create_lr_scheduler`, | ||
| `create_noise_scheduler`, `create_trainer` — those are explicit `match`/`case` branches | ||
| keyed off enums. | ||
|
|
||
| ### UI | ||
|
|
||
| CustomTkinter. One file per screen in `modules/ui/`. `TrainUI` (the root window) | ||
| extends `ctk.CTk`; `CaptionUI`, `ConvertModelUI`, `VideoToolUI` extend `ctk.CTkToplevel`. | ||
| `TrainUI` composes tabs (`ModelTab`, `TrainingTab`, `SamplingTab`, `LoraTab`, | ||
| `ConceptTab`, `AdditionalEmbeddingsTab`, `CloudTab`); sub-windows are opened by whichever | ||
| component needs them. | ||
|
|
||
| Reactive state: `modules/util/ui/UIState.py` is `UIState(master, obj)` — it introspects | ||
| typed attributes on any config-shaped object and two-way-binds them to tkinter | ||
| vars. Shared widgets: `components.py`. Validation: `validation.py` + | ||
| `validation_helpers.py`. | ||
|
|
||
| ### Config | ||
|
|
||
| `TrainConfig` (`modules/util/config/TrainConfig.py`) is **not** a `@dataclass`; it's a | ||
| `BaseConfig` subclass using class-level annotations. Serialization is via `to_dict()` / | ||
| `from_dict()` on `BaseConfig` — JSON conversion happens at the call site | ||
| (`scripts/train.py` does `json.load` → `from_dict`). `TrainConfig.py` also declares | ||
| several sub-configs inline (`TrainOptimizerConfig`, `TrainModelPartConfig`, | ||
| `TrainEmbeddingConfig`, `QuantizationConfig`); standalone sub-configs: | ||
| `SampleConfig.py`, `ConceptConfig.py`, `CloudConfig.py`, `SecretsConfig.py`. | ||
|
|
||
| Validation lives in `modules/util/ui/validation.py` — the **UI** layer. CLI scripts | ||
| bypass it. Validate at load time too if a field can be invalid from JSON. | ||
|
|
||
| Presets in `training_presets/` are partial overrides applied on top of | ||
| `TrainConfig.default_values()` (only fields that differ from defaults are present). | ||
|
|
||
| ## Recipes | ||
|
|
||
| Detailed implementation guides live in [`docs/recipes/`](docs/recipes/): | ||
|
|
||
| - **New optimizer** — see [`docs/recipes/AddOptimizer.md`](docs/recipes/AddOptimizer.md). | ||
|
|
||
| ### Add a `TrainConfig` field | ||
|
|
||
| 1. Declare a class-level annotation (`my_field: int`) on the appropriate `BaseConfig` subclass; set its default in that class's `default_values()`. | ||
| 2. UI: bind via `UIState`. Add validation in `modules/util/ui/validation.py` if it can be invalid. | ||
| 3. Presets keep loading (partial overrides). Migrate only if a default they relied on changes. | ||
| 4. CLI bypasses UI validation — if a malformed JSON value would crash deeper in, validate at load. | ||
|
|
||
| ### Hook into the training loop | ||
|
|
||
| - **Callbacks** (training → caller): `modules/util/callbacks/TrainCallbacks.py`. Instantiated in `scripts/train.py` / `TrainUI`, passed to `create_trainer(...)`. | ||
| - **Commands** (caller → training): `modules/util/commands/TrainCommands.py`. Available: `stop`, `sample_default`, `sample_custom(SampleConfig)`, `backup`, `save` (each paired with `get_and_reset_*` polled by the trainer). Multi-GPU sync: `modules/util/multi_gpu_util.py::sync_commands` + `TrainCommands.merge`. | ||
|
|
||
| ## Footguns | ||
|
|
||
| - `modules/util/LayerOffloadConductor.py` — **incompatible with `dataloader_threads > 1`** when `gradient_checkpointing.offload()` and `layer_offload_fraction > 0` (hard-raised in `create.py`). | ||
| - ZLUDA (`modules/zluda/ZLUDA.py`) — `ZLUDA.initialize_devices(config)` runs only in the `GenericTrainer` branch of `create_trainer`. On Win-AMD it disables `cuDNN`, `flash_sdp`, `mem_efficient_sdp`, `cudnn_sdp`. Silent CPU fallback if its self-test fails. | ||
| - macOS — `lib.include.sh` exports `PYTORCH_ENABLE_MPS_FALLBACK=1`. Slow workflow on Mac? Suspect this first. | ||
| - `OT_*` env vars (`LAUNCH-SCRIPTS.md`) change install / venv selection / low-mem mode / platform requirements. | ||
| - CustomTkinter trace-removal workaround in `modules/util/ui/components.py` (references upstream CTK PR #2077, unlikely to merge). Don't simplify without re-verifying. | ||
| - `requirements-global.txt` has `git+https` commit pins for `diffusers`, `mgds`, `muon`. Don't bump silently. | ||
| - Adding a `ModelType` without sweeping every `if/elif model_type == ...` causes silent feature absence (no crash). | ||
| - CLI scripts bypass UI validation — a field validated only in `modules/util/ui/validation.py` can arrive malformed from JSON. | ||
|
|
||
| ## Before opening a PR | ||
|
|
||
| - `pre-commit run --all-files` clean | ||
| - Launched the affected UI / script and exercised the change | ||
| - Touched the training path? Ran a short training job with a real preset | ||
| - No silent new top-level dependencies | ||
| - Can defend every line in the diff |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's the purpose of the redirect? are there other agends that would read AGENTS.md directly? Codex?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically all the other AI providers use the AGENTS.md but Anthropic/Claude - so yes the best practice seems to just redirect on CLAUDE.md
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't a symlink better here? That's what I've seen in other projects. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This project's contributor rules for AI coding agents live in **[AGENTS.md](AGENTS.md)**. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Adding a New Optimizer | ||
|
|
||
| 1. `modules/util/enum/Optimizer.py` — add enum entry; update `is_adaptive` / `is_schedule_free` / `supports_fused_back_pass` predicates if applicable. | ||
| 2. `modules/util/create.py::create_optimizer` — add `case Optimizer.<NAME>:`. | ||
| 3. `modules/util/optimizer_util.py::OPTIMIZER_DEFAULT_PARAMETERS` — register default hyperparams. | ||
| 4. If torch internals need patching: add a module under `modules/util/optimizer/` modelled on the existing `*_extensions.py`. | ||
| 5. UI exposure: `modules/ui/OptimizerParamsWindow.py`. | ||
| 6. Pin any new package in `requirements-global.txt` (or appropriate platform file). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how was this file created?
/init?
as a result of discussing with Claude?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/init, and then thorough discussion based on the last merged PR. I then rewrote any bits that are just wrong or too verbose (to my knowledge)
The caveat with /init only is that it's very surface level with lots of useless information that is easily accessible, my goal is for these files to provide the right entry point so no context/time is lost