Nodes/ComfyUI-Lora-Sweeper/Lora Epoch Sweeper
ComfyUI Node

Lora Epoch Sweeper

Press Queue once, get an image from every one of your LoRA's training checkpoints

By ethanfel·Created 2 months ago·Updated 2 months ago· 0
Lora Epoch Sweeper
  • model
  • clip
  • model
  • clip
  • step_label
  • lora_name
folder_path
lora_basename
start_step0
end_step0
step_interval0
strength_model1.00
strength_clip1.00
include_basetrue
max_count0

You just finished a LoRA training run and you have 32 checkpoints sitting in a folder. Which one is actually good? The answer is almost never "the last one" - the community has said for years that you should save intermediate epochs because the final checkpoint is frequently overtrained (that advice predates the Flux era and survives it untouched). The only honest way to find your best step is to look at all of them, side by side, same seed, same prompt.

The Lora Epoch Sweeper is the node that makes that look trivial. It points at your training output folder, you tell it which step range to sweep, and it emits a list of patched models. Because ComfyUI runs everything downstream of a list once per item, one press of Queue gives you one image per checkpoint. No hand-editing the LoRA loader twenty times, no giant manually-built workflow. For anyone who trains their own LoRAs (ai-toolkit or kohya output, e.g. my_lora_000002000.safetensors), this is one of those "how did I live without this" nodes. If you only download finished LoRAs, skip it - there's nothing here for you.

How it works

Under the hood it's honest plumbing: the node scans the folder, parses the trailing _<digits> step from each filename, groups files by LoRA name, filters by your step range, then patches the base model once per selected checkpoint using ComfyUI's own load_lora_for_models. The interesting part is the step_interval thinning: it targets the round multiples of your interval inside the range and snaps each to the nearest available checkpoint. With epochs saved every 250 steps, step_interval = 500 gives you 500, 1000, 1500… exactly the grid you actually want, instead of a wobbly sample.

The source has zero dependencies - no requirements, no model files, no API. It's a single small Python file, MIT licensed.

The inputs that matter

You'll set a handful, and the defaults cover the rest:

  • model (required) - your base model. clip is optional; connect it and it gets patched too.
  • folder_path - the epoch folder. ~ expands; a bare subfolder name also works if it lives inside your loras dir.
  • start_step / end_step - the inclusive range of training steps. end_step = 0 means no upper limit.
  • step_interval - thin the range to ~one checkpoint per this many steps. 0 keeps every epoch.
  • lora_basename - when a folder holds several training runs, pick one by substring; leave empty to auto-pick the LoRA with the most epochs.
  • include_base, max_count, strength_model/strength_clip - include the suffix-less final file, cap the sweep, and set the usual LoRA strengths.

Outputs are all lists: model, clip, step_label (the step number as a string, "final" for the base file), and lora_name. Wire model to your KSampler, clip to your text encoders.

Install

Clone into custom_nodes and restart ComfyUI:

cd ComfyUI/custom_nodes
git clone https://github.com/ethanfel/ComfyUI-Lora-Sweeper

ComfyUI Manager can find it as ComfyUI-Lora-Sweeper too. No extra steps, no dependencies to fight.

Where people get burned

The filename convention is the whole contract: the node only parses steps from a _<at least 4 digits>.safetensors suffix. If your trainer saves epochs as _step2000 or without the underscore, every file gets treated as the "final" checkpoint and your sweep collapses into one image. kohya and ai-toolkit both output the expected format, so you're fine unless you renamed things.

Two more gotchas worth knowing. First, each epoch is a separate patched model held in memory, so a 40-epoch sweep eats RAM - that's what step_interval and max_count are for. Second, the node prints what it's sweeping to the console ([LoraEpochSweeper] sweeping N epochs of 'my_lora'), which is genuinely useful when it picks the wrong LoRA from a mixed folder - the error message lists the ambiguous matches.

One last trick that makes it complete: right-click SaveImageConvert filename_prefix to input, and wire step_label (or lora_name) into it. Now every saved file is named after the epoch that made it, and comparing a grid of 16 images is actually a pleasant experience instead of a guessing game.

Categoryloaders/LoraSweeper

Inputs (11)

NameTypeDefaultDescription
modelMODELBase diffusion model to apply each epoch to.
folder_pathSTRINGAbsolute path to a folder of LoRA epochs (or a sub-folder name inside the loras dir).
lora_basenameSTRINGWhich LoRA in the folder to sweep (substring of its name). Leave empty to auto-pick the LoRA with the most epochs.
start_stepINT00–18446744073709550000Lowest training step to include (inclusive).
end_stepINT00–18446744073709550000Highest training step to include. 0 = no upper limit.
step_intervalINT00–18446744073709550000Thin the range to ~one checkpoint per this many training steps (e.g. 500). 0 = keep every epoch.
strength_modelFLOAT1.00-100–100
strength_clipFLOAT1.00-100–100
clipoptCLIPOptional CLIP/text-encoder to also patch.
include_baseoptBOOLEANtrueAlso include the final, suffix-less .safetensors.
max_countoptINT00–1000Cap the number of epochs swept. 0 = unlimited.

Outputs (4)

NameTypeDescription
modelMODELList of models, one per selected epoch.
clipCLIPList of CLIPs, one per selected epoch (passthrough if no clip given).
step_labelSTRINGTraining step of each epoch as a string ('final' for the suffix-less file).
lora_nameSTRINGFilename (without extension) of each epoch.