---
title: "Chapter 02: Train an Adapter"
description: "Understand Dreambooth and training checkpoints, install mflux and smoke-test generation, prepare a raw→512 dataset with captions, then train (and resume) from a JSON config — including what drives wall-clock training time."
type: lesson
order: 2
chapter: "01-lora-eyes-open"
---

# Chapter 02: Train an Adapter

## Objective

Understand **Dreambooth** and **checkpoints** (what they store, how mflux saves and **resumes**), prove **mflux** can generate on your machine, prepare a **raw → 512×512** subject dataset with a trigger token, and start **one** baseline training run from a JSON config — knowing how to continue if it stops. Before a multi-hour job, walk through **what affects tuning time** (epochs, dataset size, max resolution, previews, checkpoints) and set a deliberate baseline.

Your tutor walks this lesson **gate by gate**. Do not skip to training until the smoke test passes.

---

## Concept: How Dreambooth works

A base image model has seen millions of dogs (or faces, or objects). If you prompt “a dog in a park,” you get *a* dog — not *your* dog. Your subject is a rare identity the base model never specialized on.

**Dreambooth** teaches one new concept from a **small set of photos** (about 15–20):

| Piece | Role |
|--------|------|
| **Subject photos** | “This is the thing” — same identity, varied angle / light / background |
| **Trigger token** | A rare word (`TOK`, `sks`, …) that becomes the *handle* for that subject |
| **Captions** | Link each photo to text: `a photo of TOK dog on the couch` |
| **Training** | Nudge a **small LoRA adapter** so the model associates the token with *that* identity |
| **Generation** | Prompt with the token in a **new** scene: `TOK dog on the moon` → still *your* dog |

### Mental model (one sentence)

> Freeze the big model; train a thin patch so a rare word reliably means *this* subject, not “generic dog.”

### Why a rare token?

If you only train on captions like “a golden retriever outside,” you fight the model’s existing meaning of those words. A rare token like `TOK` has almost no prior meaning, so the adapter can claim it.

### What “good” looks like for this chapter

Not gallery-perfect portraits. Success:

> When I prompt with `TOK`, I recognize **this** subject in a **new** scene in under five seconds.

- **Overfit** often looks like: same training photo, same glued-on background.  
- **Underfit**: “some dog,” not yours.  

You are here for a **working baseline** and judgment — not a shippable product LoRA.

### Tooling in one line

**mflux** is a minimal MLX port of modern image models (including FLUX-family / Z-Image stacks). Architectures are mostly hardcoded; Dreambooth/LoRA training is driven by a **JSON config**, not a pile of CLI training flags.

---

## Concept: What a checkpoint is

Training a LoRA takes a long time. A **checkpoint** is a **snapshot of training mid-run** so you can:

- stop without losing hours of progress  
- resume later from that point  
- try generation from an intermediate adapter (after the run finishes or from the adapter inside the zip)  
- compare “step 30 vs step 90” without re-running from zero  

### What is *not* a checkpoint

| Thing | Role |
|--------|------|
| **Base model weights** | Frozen download (FLUX / Z-Image). Not rewritten each step. |
| **Your photos + captions** | Training *data*. Must still exist if you resume. |
| **Preview PNGs / loss plots** | Monitoring artifacts. Useful to look at; not enough to resume training. |
| **Final adapter only** | May be enough to *generate*; usually **not** enough to *continue training* with the same optimizer trajectory |

### What a full training checkpoint usually stores

Enough to **continue** the same run:

- **Adapter weights** (the LoRA you care about)  
- **Optimizer state** (AdamW momentum buffers, etc. — without these, “resume” is really “start a new train from those weights”)  
- **Iterator / step count** (how far you got through epochs/steps)  
- **Config snapshot** (what hyperparams this run used)  
- Often **loss history** for plots  

Think of it as a **save game**, not just the high score.

### How mflux does it

In your train JSON:

```json
"checkpoint": {
  "save_frequency": 15,
  "output_path": "training"
}
```

- **`output_path`** — run directory (mflux creates subfolders under it).  
- **`save_frequency`** — write a checkpoint every N training steps (example uses `15`).  

Typical layout after a while:

```text
training/                    # or whatever output_path resolves to
  checkpoints/
    0000015_checkpoint.zip
    0000030_checkpoint.zip
    ...
  loss/
    loss.html                # loss curves
  preview/
    ...                      # periodic sample generations
```

Each `NNNNNNN_checkpoint.zip` is a **self-contained training snapshot**. Inside the zip mflux packs things like:

- LoRA **adapter** weights  
- **optimizer** state  
- **iterator** state (step / progress)  
- **loss** stats  
- a **config** / run manifest  

So the zip is for **resume**, not only for “here’s a LoRA file.”

### Resuming in mflux (yes, it is supported)

**Start a new run** from config:

```bash
mflux-train --config ~/lora-eyes-open/train.json
```

**Continue an interrupted run** from a checkpoint zip:

```bash
mflux-train --resume ~/lora-eyes-open/training/checkpoints/0000030_checkpoint.zip
```

Rules that matter in practice:

1. **Provide exactly one of** `--config` **or** `--resume` — not both. Resume loads the config from inside the checkpoint.  
2. **Your dataset folder must still be available** at the path the run expects. The zip is not a substitute for the images. Prefer **absolute** `"data"` paths so laptop sleep / cwd changes do not break resume.  
3. Resume restores adapter + optimizer + iterator so training **continues** from that step, rather than restarting epochs from scratch.  
4. Previews and loss plots under `preview/` / `loss/` are side outputs; use the **zip** to resume.  
5. If you only want to **generate** with a mid-run adapter (not train further), you need the adapter weights from that checkpoint (or a saved LoRA path your mflux version exposes) — that is inference, not resume.

### Why this shows up in Chapter 03

Sweeps mean many runs. Checkpoints let you:

- kill a bad run without losing earlier steps  
- keep intermediate adapters for the contact sheet  
- resume overnight jobs after a reboot  

You do not need every knob yet — you need the mental model: **checkpoint = resumable training state; data must still be there.**

---

## Concept check

Answer in your own words before looking at the key. Your tutor asks **one question at a time** and waits for you.

**Q1.** In Dreambooth, what is the job of the **trigger token**, and what goes wrong if you train only on captions like “a golden retriever sitting outside” with no rare token?

**Q2.** Someone has 20 photos of their dog: 12 nearly identical couch shots and 8 varied outdoor angles. For a first adapter meant to place that dog in *new* scenes, which photos should dominate the set, and why?

**Q3.** Laptop sleeps midway through `mflux-train`. You still have `0000030_checkpoint.zip` and the same `dataset/train` folder. How do you continue, and what goes wrong if you only kept a loose adapter file but deleted the zip / optimizer state?

<details>
<summary>Concept answer key — attempt first</summary>

## Answer key (concept)

### Q1

**Model answer:** The trigger token is a rare handle the model should learn to mean *this* subject. Without it, training fights generic prior meanings (“golden retriever”) and the concept does not bind cleanly to a promptable word.

**Pass criteria:** token as rare handle / binding mechanism; problem with generic captions stated (prior conflict or weak binding)

### Q2

**Model answer:** Prefer the varied outdoor (and other diverse) shots so the model learns identity across contexts, not “dog = that couch.” Keep at most a couple of similar couch frames; drop near-duplicates.

**Pass criteria:** favors variety / identity over duplicates; links to generalization to new scenes

### Q3

**Model answer:** Resume with `mflux-train --resume path/to/0000030_checkpoint.zip` (not a fresh `--config` start). The zip holds adapter + optimizer + step state. A bare adapter without optimizer/iterator is not a full resume — you’d be starting a new optimization trajectory from those weights, not continuing the same run. Data folder must still exist.

**Pass criteria:** `--resume` + zip; data still needed; full state vs weights-only / cannot truly continue without optimizer+step state

</details>

---

## Gate: Install mflux

Only after the concept check. On **Apple Silicon** macOS:

```bash
mkdir -p ~/lora-eyes-open && cd ~/lora-eyes-open
uv venv && source .venv/bin/activate
uv pip install mflux
```

Alternatively:

```bash
uv tool install --upgrade mflux
```

Confirm the CLI is on your path:

```bash
mflux-train --help
# and/or
mflux-generate-z-image-turbo --help
```

If install fails, stop here and fix with your tutor (Python version, `uv`, network, non-Apple hardware). This course’s Part 1 assumes MLX on Mac.

---

## Gate: Verify it runs (smoke test)

**Do not prepare a dataset or start training until this works.**

Generate one small image (first run downloads model weights — can take a while and needs disk):

```bash
mflux-generate-z-image-turbo \
  --prompt "A simple red apple on a white table, soft light" \
  --width 512 \
  --height 512 \
  --seed 42 \
  --steps 9 \
  -q 8
```

**Pass criteria for this gate:** a PNG/JPEG appears without a crash, and you can open it.

If generation fails (memory, download, Metal), debug **now**. Long training will not fix a broken install.

Tell your tutor when the smoke test succeeds (or paste the error).

---

## Gate: Collect raw photos

1. Pick **one** subject you can judge in under five seconds (your dog, a person who consented, a product, a place).
2. Create:

```bash
mkdir -p ~/lora-eyes-open/dataset/raw
mkdir -p ~/lora-eyes-open/dataset/train
```

3. Copy **15–20** photos into `dataset/raw/` — **leave them as originals** (any resolution). Prefer:
   - same subject
   - **varied** background, lighting, angle
   - clear subject (not a blurry speck)

4. Confirm with your tutor: how many files are in `raw/`? Name the subject and your chosen trigger token (e.g. `TOK`).

Do **not** overwrite originals. All resizing happens into `train/`.

---

## Gate: Convert to 512×512

mflux training uses a max resolution setting; for this course baseline, standardize the **train** set at **512×512**.

From `~/lora-eyes-open`, a simple approach with macOS `sips` (one file at a time or loop). Example loop for jpegs/pngs in `raw/`:

```bash
cd ~/lora-eyes-open
# zsh: unmatched globs error — either:
setopt NULL_GLOB
# or use: for f in dataset/raw/*; do [ -f "$f" ] || continue; ...
i=1
for f in dataset/raw/*.{jpg,jpeg,png,JPG,JPEG,PNG,webp,WEBP}; do
  [ -e "$f" ] || continue
  out=$(printf "dataset/train/%02d.jpg" "$i")
  # Fit inside 512x512, then pad/crop as needed for a square:
  sips -Z 512 "$f" --out "$out"
  sips -c 512 512 "$out"
  i=$((i+1))
done
ls dataset/train | wc -l
```

Notes:

- On **zsh**, `dataset/raw/*.{jpg,jpeg,...}` fails with `no matches found` if any extension is missing. Use `setopt NULL_GLOB` for that shell, or loop `dataset/raw/*` and skip non-files.
- `sips -c 512 512` center-crops to a square after the long side is 512. If a photo is very wide, crop may cut ears/tails — re-crop important shots in Preview if needed.
- You may use any tool (Preview, Photos, Python/Pillow) as long as **train/** ends up with ~15–20 images at **512×512**.
- Prefer a durable project dir (`~/lora-eyes-open`), not a temp folder, before multi-hour training.

**Pass this gate when:** `dataset/train` has 15–20 square 512 images and `dataset/raw` still holds the originals.

---

## Gate: Captions + trigger token

Beside each train image, add a **matching `.txt` caption** (same basename):

```text
dataset/train/
  01.jpg
  01.txt
  02.jpg
  02.txt
  ...
  preview.txt    # optional: prompt for mid-training previews
```

**Caption pattern** (keep it short for the first run):

```text
a photo of TOK dog sitting on grass
a photo of TOK dog sleeping on a couch
a photo of TOK dog looking at the camera outdoors
```

Rules:

- Put your rare token (`TOK` or similar) in **every** caption.
- Lightly describe pose/scene so the model does not learn one frozen pose only.
- Optional `preview.txt`: a **new** scene, e.g. `a photo of TOK dog sitting in a sunny park`.

**Pass this gate when:** every `NN.jpg` has `NN.txt`, and you can paste one sample caption for your tutor.

---

## Gate: Train from a JSON config

Training parameters live in **JSON**, not a long list of train CLI flags.

1. Create `~/lora-eyes-open/train.json`. Start from the bundled example inside the mflux package/repo:

   - Example path in source: `src/mflux/models/common/training/_example/train.json`
   - CLI: `mflux-train --config /path/to/train.json`

2. Point `"data"` at your **train** folder with an **absolute path** (resume is much less painful), e.g. `/Users/you/lora-eyes-open/dataset/train`.

3. Set checkpointing explicitly (or keep the example defaults), e.g.:

```json
"checkpoint": {
  "save_frequency": 15,
  "output_path": "/Users/you/lora-eyes-open/training-run-01"
}
```

   - Smaller `save_frequency` → more zips on disk, safer if the machine dies often.  
   - Use a **dedicated** `output_path` per experiment so Chapter 03 sweeps do not overwrite each other.

4. Keep the example’s model/LoRA targets unless you know you need otherwise. For a low-memory machine, set `"low_ram": true` in the config.

5. Dry-run if supported:

```bash
mflux-train --config ~/lora-eyes-open/train.json --dry-run
```

6. Start training (new run):

```bash
mflux-train --config ~/lora-eyes-open/train.json
```

7. If the process dies or you stop it, **resume** from the latest zip (do **not** pass `--config` again for the same continuation):

```bash
ls /Users/you/lora-eyes-open/training-run-01/checkpoints/
mflux-train --resume /Users/you/lora-eyes-open/training-run-01/checkpoints/0000030_checkpoint.zip
```

Expect **hours** for the stock example config. Under `output_path` you should see `checkpoints/`, plus `loss/` and `preview/` for monitoring. Before you leave a multi-hour job unattended, walk the tuning-time factors below with your tutor and set a **deliberate** baseline — the bundled example is often longer than Chapter 02 needs.

### Walkthrough: what affects tuning time

Wall-clock time is not a mystery number mflux prints before you start. It is almost:

```text
total time ≈ (number of train steps × time per step)
             + (number of mid-run previews × time per preview)
             + checkpoint / plot overhead
```

With `batch_size: 1` (the usual default):

```text
number of train steps ≈ num_epochs × (images in dataset/train)
```

**Example:** 50 epochs × 13 images = **650 steps**. At ~45 s/step that is already ~8 hours of *train* steps alone — before counting previews.

You get a trustworthy ETA only after the progress bar has run for a bit. Read tqdm, e.g. `2/650 [… <8:25:28, 46.80s/it]`:

| Piece | Meaning |
|-------|---------|
| `2/650` | Current step / total steps |
| `46.80s/it` | Seconds per train step *right now* |
| `<8:25:28` | Estimated time remaining |

Early steps can be slow (warmup, Metal cache). Re-check after ~15–20 steps. **650 is not required** — it is whatever `num_epochs` × image count the config implies. Chapter 02 wants a **working baseline**; Chapter 03 sweeps short / medium / long on purpose.

Walk each knob **before** the long run (or when deciding to kill and restart). Editing `train.json` does **not** change a live process — stop, edit, start a **new** run (new `output_path` recommended).

#### 1. `num_epochs` — how many times you press the whole dataset

| | |
|--|--|
| **What it is** | Full passes over every train image. |
| **Time** | Linear: 2× epochs ≈ 2× train steps. **Largest lever.** |
| **Quality tradeoff** | Too few → underfit (“some dog,” not yours). Too many on a small set → overfit (photocopy of train photos / glued backgrounds). |
| **Chapter 02 default** | Stock example often uses `50` → multi-hour. Prefer **10–20** for a first baseline (e.g. 15 × 13 images ≈ 195 steps). |

#### 2. Dataset size (how many images in `train/`)

| | |
|--|--|
| **What it is** | Count of captioned images the loop visits each epoch. |
| **Time** | Linear with steps: more images × same epochs = more steps. |
| **Quality tradeoff** | ~15–20 varied shots is the course target. Cutting to 5 “to go faster” usually hurts identity more than it helps the clock. Prefer fewer **epochs**, not a starved set. |

#### 3. `max_resolution` — training-time pixel cap

| | |
|--|--|
| **What it is** | Upper bound on resolution used **while training** (how large each image is when the trainer sees it). Not generate CLI `--width`/`--height`, and not preview pixel size. |
| **Time** | Higher caps cost more compute and memory per step. Training 512px data with `max_resolution: 1024` does **not** invent 1024 detail from the files; it can still leave you on a heavier path. |
| **Quality tradeoff** | Match the train set you prepared. Course baseline: **512×512 images → `"max_resolution": 512`**. Raise later only if you re-export a larger `train/` set. |

#### 4. Mid-run previews (`monitoring.generate_image_frequency`, preview size)

| | |
|--|--|
| **What it is** | Every N steps the trainer runs a **full sample generate** and writes `preview/*_preview_image_*.png` so you can *see* whether the subject is appearing. Prompt often comes from optional `dataset/train/preview.txt`. |
| **Time** | Each preview can cost on the order of a minute (similar to your smoke-test generate). Frequency 15 on a 650-step run → dozens of samples → easily **an hour+** of pure preview tax. `preview_width` / `preview_height` also scale that cost. |
| **Quality tradeoff** | Previews do not train the adapter; they only monitor. For a speed-first baseline use something like **45–50**, and smaller previews (e.g. 512×512). Keep learning checkpoints frequent if you want resume safety without paying for images every time. |

#### 5. Checkpoints (`checkpoint.save_frequency`)

| | |
|--|--|
| **What it is** | How often a full training-state zip is written under `checkpoints/`. |
| **Time** | Usually a smaller overhead than previews (disk write vs full generate). Still not free if set very low (every step). |
| **Quality tradeoff** | Does not change the learned subject. Smaller frequency → more zips, safer resume if the machine dies. Example: `15` is a reasonable middle ground. |

#### 6. Loss plots (`monitoring.plot_frequency`)

| | |
|--|--|
| **What it is** | How often `loss/loss.html` updates. |
| **Time** | Minor compared to steps and previews. |
| **Quality tradeoff** | None on the adapter. Bump from `1` to `5` if you want less chatter; keep previews as the visual scoreboard. |

#### 7. `low_ram` and machine load

| | |
|--|--|
| **What it is** | `low_ram: true` reduces peak memory (may recompute more). OS power mode, sleep, and other MLX/GPU jobs affect **seconds per step**. |
| **Time** | `low_ram` is often **slower** — use when you must fit, not for speed. Plugged in, not Low Power Mode; prevent sleep; do **not** interleave ad-hoc `mflux-generate` in the same session (documented slowdowns). |
| **Quality tradeoff** | Memory mode should not change the concept of the run if training completes; thrashing / OOM aborts waste the whole job. |

#### 8. LoRA rank / which layers (usually **not** first speed knobs)

| | |
|--|--|
| **What it is** | Capacity of the thin patch (`rank`, which modules in `lora_layers`). |
| **Time** | Higher rank can cost a bit per step; effect is usually small next to epochs and previews. |
| **Quality tradeoff** | Strong quality / overfit lever — Chapter 03 territory. Do not cut rank only to “make it faster” on the first baseline. |

#### Config map (time vs quality at a glance)

| Knob | Main effect on **time** | Main effect on **result** |
|------|-------------------------|---------------------------|
| `num_epochs` | **Dominant** (step count) | Underfit ↔ overfit |
| Image count in `train/` | Step count per epoch | Identity / variety |
| `max_resolution` | Cost per step | Detail ceiling (match your files) |
| `generate_image_frequency` | Preview tax | Monitoring only |
| `preview_width` / `height` | Cost per preview | Monitoring only |
| `save_frequency` | Zip overhead | Resume safety |
| `plot_frequency` | Small | Loss chart only |
| `low_ram` | Often slower | Fits machine |
| LoRA rank / targets | Mild | Capacity (Ch.03) |

#### Example: stock long vs intentional short baseline

**Stock-shaped (often multi-hour):** `num_epochs: 50`, `max_resolution: 1024`, preview every 15 steps at 1280×720 → e.g. 50×13 = 650 steps + many full generates.

**Chapter 02 speed-oriented baseline** (keep model / `lora_layers` from the package example unless you know better):

```json
"max_resolution": 512,
"training_loop": {
  "num_epochs": 15,
  "batch_size": 1,
  "timestep_low": 4,
  "timestep_high": 9
},
"checkpoint": {
  "save_frequency": 15,
  "output_path": "/Users/you/lora-eyes-open/training-run-01"
},
"monitoring": {
  "preview_width": 512,
  "preview_height": 512,
  "plot_frequency": 5,
  "generate_image_frequency": 45
}
```

Roughly: 15×13 ≈ **195 steps**, far fewer previews, resolution matched to the course dataset.

**If a long run is already going:** Ctrl+C after a useful checkpoint and generate with that zip, or leave overnight. Prefer a new short config (new `output_path`) if most of an 8-hour ETA is still ahead.

### What lands under `output_path`

Typical layout:

```text
training/   # or whatever you set as checkpoint.output_path
  checkpoints/
    0000000_checkpoint.zip
    0000015_checkpoint.zip
    ...
  preview/
    0000000_preview_image_01.png
    ...
  loss/
    loss.html
```

| Path | What it is |
|------|------------|
| **`checkpoints/*_checkpoint.zip`** | Full training state at that step (adapter + optimizer / iterator progress). Use these with `--resume`. Controlled by `checkpoint.save_frequency` (e.g. `15` → about every 15 steps). Step `0000000` is usually written near the start — not a trained subject yet. |
| **`preview/*_preview_image_*.png`** | Mid-run **sample generations** so you can *see* whether the subject is appearing, without waiting for the full job. Frequency: `monitoring.generate_image_frequency`. Prompt often comes from optional `dataset/train/preview.txt` (a *new* scene with your trigger token). |
| **`loss/loss.html`** | Loss curve for monitoring; not a photo of your subject. `monitoring.plot_frequency` controls how often it updates. |

Open previews in order (`0000000` → `0000015` → …). You are watching identity **come in** (or overfit). Early judgment only — do not thrash hyperparams mid-run.
### While it trains

- Watch `checkpoints/` fill in; note the step numbers in the zip names.  
- Open a preview image when one appears — early judgment only; do not thrash hyperparams mid-run.  
- **Do not** interleave ad-hoc generation with training in the same session (documented slowdowns). Prefer train (or resume), then generate.  
- Quality may be weak. For this chapter, success is: pipeline ran, checkpoints exist, you can resume if interrupted, and you can judge “looks like my subject.”  
- Optional: write predictions for Chapter 03 — few images + high capacity vs long run on a modest set.

### Known failure modes

- **"None of my LoRAs look good."** Early MLX Dreambooth quality can be poor; adapters may not transfer across tools. Optimize for **deltas between runs**, not a shippable portrait.
- **Interleaving gen + train** → slowdowns. Separate the phases.
- **Training before smoke test** → hours wasted on a broken install. Always verify generate first.
- **Resume fails: data path missing.** The zip does not include your photos. Keep `dataset/train` and prefer absolute paths in config.
- **Started with `--config` again after a crash.** That starts a **new** run (new folder / from scratch), not a continuation. Use `--resume path/to/*_checkpoint.zip`.
- **Eight-hour ETA on the stock example.** Usually epochs × image count and/or frequent previews — not a broken install. Cut `num_epochs` and raise `generate_image_frequency` for the next baseline; or stop and use a mid checkpoint.

---

## Check your understanding

After the gates (or after you’ve at least completed concept + install + smoke test if training is still running), answer in your own words:

**Q4.** Why does this lesson insist on a **generate smoke test** before building the dataset and starting Dreambooth training?

**Q5.** Why keep photos in `raw/` and write **512×512** copies into `train/` instead of resizing the only copy of each file?

**Q6.** Training is configured primarily through a **JSON file**, not CLI train flags. What practical advantage does that give you when you get to Chapter 03’s experiments?

**Q7.** In mflux, what is the difference between starting with `--config train.json` and continuing with `--resume …/0000030_checkpoint.zip`? Name one thing the checkpoint zip holds that a “final LoRA only” file might not.

**Q8.** A run shows `2/650` at about 45 s/step, with `num_epochs: 50`, 13 train images, and a preview every 15 steps. Name **two** config (or data) changes that would shorten wall-clock time the most, and say briefly **why** each works. What does `max_resolution` control in that picture?

<details>
<summary>Answer key — attempt every question first</summary>

## Answer key

### Q4

**Model answer:** Long training cannot fix a broken install, download, or Metal/memory setup. A one-image generate proves the stack works before you invest hours and before dataset busywork.

**Pass criteria:** smoke test proves tooling; avoids wasted long runs / orders verify before train

### Q5

**Model answer:** Preserve originals so you can re-crop, re-resize, or change resolution later without quality loss or re-exporting from phone/camera. Train set is a disposable derivative.

**Pass criteria:** originals preserved; train set as derivative / reworkable

### Q6

**Model answer:** You can copy the config, change one field (rank, epochs, data path), and keep runs comparable and reproducible — the config is the experiment record.

**Pass criteria:** reproducibility / easy variants / comparable sweeps (any of these)

### Q7

**Model answer:** `--config` starts a new training run from the JSON; `--resume` loads a checkpoint zip and continues that run. The zip includes optimizer state and iterator/step progress (and a config snapshot), not only adapter weights — so you can truly continue rather than re-optimize from scratch. Dataset must still be on disk.

**Pass criteria:** new run vs continue; optimizer and/or step/iterator state (or full training state) beyond weights alone

### Q8

**Model answer:** (1) Lower `num_epochs` — total steps ≈ epochs × image count, so this cuts the main train loop linearly. (2) Raise `generate_image_frequency` (rarer previews) — each preview is a full generate and adds a large tax on a long run. Matching `max_resolution` to the 512 train set (instead of 1024) can also help per-step cost. `max_resolution` is the training-time pixel cap (how large images are when the trainer sees them), not generate CLI size and not the quality of previews alone.

**Pass criteria:** names at least two high-impact levers with correct mechanism (epochs/steps and previews most important); `max_resolution` described as train-time resolution cap / match-to-data (not “makes images sharper than files”)

</details>

---

[← Chapter 01](/fine-tune-local-agent/01-lora-eyes-open/01-why-fine-tune/) · [Next: Chapter 03 →](/fine-tune-local-agent/01-lora-eyes-open/03-the-experiments/)
