Generated banner for Tao Generate Anomalies
Generated logo for Tao Generate Anomalies

Tao Generate Anomalies

NVIDIAOfficialCreated by NVIDIA Corporation

  • Skill
  • Workflow
  • Data and AI
  • Apache-2.0
  • Medium risk

From the author

Full PAIDF AnomalyGen pipeline — fine-tune on a new anomaly dataset, generate synthetic anomaly images (SDG), evaluate quality (nn_score), and search per-sample (guidance, crop_ratio) parameters. Three modes: full (Phase 0→7: finetune then generate), finetune_only (Phase 0→1: train only), inference_only (Phase 0, 2→7: generate from an existing checkpoint). Use when the user asks to "fine-tune AnomalyGen", "generate anomaly images", "run PAIDF SDG", "evaluate SDG output quality", "run per-sample search", or run any part of the AnomalyGen pipeline, even if they only mention one phase.
— the description by NVIDIA Corporation

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The TAO Generate Anomalies skill provides a comprehensive pipeline for training and using PAIDF AnomalyGen models. It supports three operational modes: full (fine-tuning and generation), fine-tune only, and inference only. The pipeline manages the entire lifecycle from checkpoint verification and dataset fine-tuning to synthetic data generation, quality evaluation, and iterative per-sample parameter refinement.

What it does

  • Fine-tunes AnomalyGen models on custom anomaly datasets.
  • Generates synthetic anomaly images using trained checkpoints.
  • Evaluates synthetic image quality using nn_score metrics.
  • Performs per-sample search for optimal guidance and crop_ratio parameters.
  • Filters generated samples based on quality thresholds and performs automated regeneration.
  • Provides guardrail checks to identify and replace unsafe generated content.

When to use it

  • When you need to fine-tune an AnomalyGen model on a new dataset.
  • When you need to generate synthetic anomaly images for training or testing.
  • When you need to evaluate the quality of synthetic anomaly images.
  • When you need to optimize generation parameters for specific anomaly samples.

Advantages

  • Automates the end-to-end workflow from training to final evaluation.
  • Supports iterative refinement of generation parameters per sample.
  • Includes automated filtering and regeneration to meet target sample counts.
  • Provides built-in guardrail checks for generated image content.

Usage examples

“Fine-tune AnomalyGen on my new PCB dataset.”
The agent initiates the fine-tuning phase (Phase 1) using the provided dataset directory and configuration.
“Generate 50 synthetic anomaly images using an existing checkpoint.”
The agent runs the inference-only mode to generate images based on the specified checkpoint and step.
“Evaluate the quality of my generated anomaly images.”
The agent executes the evaluation phase to calculate nn_score metrics and generate an evaluation log.
“Run the full PAIDF AnomalyGen pipeline for my experiment.”
The agent executes the full mode (Phases 0-7), covering checkpoint verification, fine-tuning, generation, search, and final filtering.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/nvidia/tao-generate-anomalies/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip tao-generate-anomalies.zip -d .agents/skills

Documentation by NVIDIA Corporation

TAO Generate Anomalies

Standalone install? If this session was not initialized by the TAO skill bank plugin, run the tao-setup skill first (host preflight, credentials, cross-skill discovery).

Multi-phase pipeline (0–7); the mode flag selects which phases run.

PhaseWhat runsMode(s)
0Verify / download pretrained checkpointsall
1Fine-tune on dataset_dirfull, finetune_only
2Prepare inference JSONL (AMP routing)full, inference_only
3SDG — generate synthetic anomaly images → original/full, inference_only
4Eval original/ — emit per_sample.csv + eval.log, merge nn_score into SDG_result.csvfull, inference_only
5Per-sample (guidance, crop_ratio) search rounds → rounds/round_NN/ (each round runs SDG + eval)full, inference_only
6Assemble best-of-rounds into searched/ (stitch only), plus rounds/search_summary.csvfull, inference_only
7Filter searched/ by nn_threshold (default 0.4), regen dropped samples, then canonical bucket eval → searched/{per_sample.csv, eval.log}full, inference_only

Run every phase through to completion without mid-run pauses. Collect all required parameters up front, and run every command from the repo root.

Shell setup. All ${ANOMALYGEN_SCRIPTS} references resolve to the packaged helper-script directory. Inside the container this is preset (ENV ANOMALYGEN_SCRIPTS=<dir>/scripts/utilities); on the host, export it once per shell:

export ANOMALYGEN_SCRIPTS="$(git rev-parse --show-toplevel)/scripts/utilities"

python3 -m scripts.utilities.<name> invocations work from any CWD inside the container (PYTHONPATH is preset) and from the repo root on the host. When inside a product container (ANOMALYGEN_PRODUCT_MODE=1), invoke anomalygen-guard before any GPU work; if it reports BLOCKED, fix the listed issues before continuing.

Quick Start

The pipeline runs inside the metropolis_sdg.paidf_anomalygen container (declared in versions.yaml) or any host with the cosmos-predict2 conda env active. All phase commands assume that environment, at the repo root, with ANOMALYGEN_SCRIPTS exported.

Minimal end-to-end run (mode=full):

# 1. Set the shared variables (see "Shared variables" for the full set).
export ANOMALYGEN_SCRIPTS="$(git rev-parse --show-toplevel)/scripts/utilities"
MODE=full
NAME=my_exp
DATASET_DIR=/data/uc1
DEFECT_DESC=assets/defect_spec_template.jsonl
NUM_SDG=20
MODEL_SIZE=2b

# 2. Phase 0 — verify / download checkpoints (~40 GB for the 2B default; needs HF_TOKEN).
${ANOMALYGEN_SCRIPTS}/check.sh --model-sizes ${MODEL_SIZE^^} \
    || ${ANOMALYGEN_SCRIPTS}/download_checkpoints.sh --model-sizes ${MODEL_SIZE^^}

# 3. Walk Phases 1→7 in order (see each Phase section).

For mode=inference_only (reuse a checkpoint) also set CKPT/STEP and skip Phase 1. For mode=finetune_only run only Phases 0–1.

Running in Docker — container launch, mounts & permissions

The paidf-anomalygen image runs as a non-root baked-in user (USER anomalygen, uid=10000), independent of your host uid. Docker does not remap uids on bind mounts, so a host directory owned by your uid is not writable by uid 10000 and the container fails the instant it tries to create a file there. Run with the full host identity: --user "$(id -u):$(id -g)", matching USER/LOGNAME, HOME=/tmp, and read-only /etc/passwd+/etc/group mounts, plus the cache redirects. Run the fail-fast write preflight before Phase 0. See references/docker.md for the full docker run command, the load-bearing-flag table, the preflight snippet, and the uid-10000 chown/chmod fallback.

Reference files — read before executing phases

Read references/finetune.md before Phase 0/1 and references/inference.md before any of Phases 2–7; for mode=full read both before starting. The remaining references below are on-demand — read when troubleshooting or needing full detail for a specific phase.

FileRead when
references/finetune.mdBefore Phase 0/1: env check, checkpoint download, dataset validation, config generation, training commands, best-checkpoint selection
references/finetune-commands.mdExact Phase 1 Step 1–4 commands and CKPT/STEP derivation
references/inference-commands.mdExact Phase 5 run_round.sh and Phase 7 filter_with_regen commands
references/inference.mdBefore Phases 2–7: AMP routing, JSONL validation, SDG flags, eval interpretation, search loop, filtering
references/setup.mdCheckpoint download fails; first-time setup; HF_TOKEN / disk issues
references/datasets.mdUser needs to prepare or obtain a UC1 / UC2 / UC3 dataset; dataset_dir doesn't exist yet
references/prep-testcase.mdAMP fails; need full param table, helper script descriptions, allocation invariant
references/sdg-inference.mdNCCL hang; checkpoint validation error; multi-GPU VRAM question; full step list
references/eval.mdUnexpected scores; FID column order confusion; eval output format reference
references/sdg-refine.mddraws.json alignment; re-AMP heuristics; search output layout
references/guard-and-custom-counts.mdFull guard preflight command; --per-defect-counts example
references/docker.mdContainer launch command, mount-permission flags, write preflight, uid-10000 fallback
references/output-layout.mdFull results/<name>/ directory tree with per-file annotations; post-run Verification checklist
references/error-handling.mdPipeline-level failure modes: missing mask dirs, short/empty AMP, mid-round resume, off-boundary step

Required parameters

num_SDG allocation depends on prep_testcase.sh --mode: inference (default, Phase 2) is uniform across defect types, override per-defect via --per-defect-counts; validation (Phase 1's validation JSONL) is proportional to training mask counts (largest-remainder rounding) and enforces ≥1 per defect. See references/prep-testcase.md for the full mode table.

ParameterDescription
modefull (Phase 0→7), inference_only (skip Phase 1), or finetune_only (Phase 0→1 only).
nameExperiment label.
dataset_dirTraining/reference dataset root. Drives mask-count allocation, AMP submask templates, and holds semantic_segmentation_labels.json for cad defects.
defect_specJSONL tagging each defect spatial_dependency as free/text/cad. text entries need roi_prompt_defect_location. Template: assets/defect_spec_template.jsonl.
num_SDGTotal output samples per bucket. (Ignored when mode=finetune_only.)

Conditionally required

ParameterRequired whenDescription
checkpoint_dir / stepmode=inference_onlyPre-existing fine-tuned model. In mode=full these are auto-derived after Phase 1; passing them is an error. In mode=finetune_only silently ignored — Phase 1 always trains from scratch (no resume-from-checkpoint support). Both must be present together — supplying only one is an error.

Optional parameters

ParameterDefaultDescription
clean_dirdataset_dirClean images. Set only when they live outside the training dataset. Forwarded as --clean-dir to prep-testcase and --clean-image-path to finetune.
validation_jsonlauto-generatedPre-built validation JSONL for Phase 1. When supplied, preflight verifies every defect_spec type appears and paths exist.
num_search_run3Per-sample search budget for Phase 5. 0 skips search (only original/). (Ignored when mode=finetune_only.)
nn_threshold0.4nn_score cutoff for Phase 7 (DINOv2 correspondence to real defects — key KPI). Samples below are regenerated; final searched/ always has num_SDG. 0 disables filtering.
max_iter75000Phase 1 only. Total fine-tune iterations.
save_iter5000Phase 1 only. Checkpoint save interval.
validation_iter5000Phase 1 only. Validation (nn_score) logging interval.
num_gpus1Forwarded to Phase 1 (finetune) and Phase 3 (SDG). Eval and search rounds stay single-GPU.
model_size2b2b or 14b. Used by finetune and SDG. On-disk checkpoint path encodes in upper-case (2b→2B, 14b→14B).
lr0.02Phase 1 only. Learning rate.
batch_size2Phase 1 only. Per-GPU batch size.
image_size512Phase 1 only. Training resolution (square).
guidance_range1.5 10.0Phase 5 search draw range for guidance.
crop_ratio_range1.5 10.0Phase 5 search draw range for crop_ratio.

Mode validation (fail fast before any phase)

  • mode unset → halt: "mode is required (full | inference_only | finetune_only)."

  • mode=inference_only missing either checkpoint_dir or step → halt: "inference_only requires both checkpoint_dir and step."

  • mode=full with checkpoint_dir or step supplied → halt: "full mode runs finetune; use mode=inference_only to reuse an existing checkpoint."

Shared variables

Set once before Phase 0:

MODE=<full|inference_only|finetune_only>
NAME=<exp>
DATASET_DIR=<dataset_dir>
CLEAN_DIR=${clean_dir:-${DATASET_DIR}}
CKPT=<checkpoint_dir>      # required iff MODE=inference_only; auto-derived after Phase 1 when MODE=full
STEP=<iter>                # required iff MODE=inference_only; auto-derived after Phase 1 when MODE=full
NUM_SDG=<N>
DEFECT_DESC=<defect_spec.jsonl>
DEFECTS=(T+A T+B)          # TEXTURE+TYPE names. For mode=inference_only, derive from ${CKPT}/ag_config.yaml → dataloader_train.dataset.anomaly_types (also printed by validate_checkpoint.py in Phase 0). For mode=full, take from DEFECT_DESC entries. See references/inference.md §Phase 0.
NUM_SEARCH_RUN=${num_search_run:-3}
NN_THRESHOLD=${nn_threshold:-0.4}
MODEL_SIZE=<2b|14b>
NUM_GPUS=${num_gpus:-1}
MAX_ITER=${max_iter:-75000}
SAVE_ITER=${save_iter:-5000}
VALIDATION_ITER=${validation_iter:-5000}
LR=${lr:-0.02}
BATCH_SIZE=${batch_size:-2}
IMAGE_SIZE=${image_size:-512}
VALIDATION_JSONL=${validation_jsonl:-}  # optional; set by Phase 1 Step 2 if not user-supplied

BASE=results/${NAME}
JSONL=ag_inference/${NAME}/testcase.jsonl
ORIGINAL=${BASE}/original
SEARCHED=${BASE}/searched
ROUNDS=${BASE}/rounds
REGENS=${BASE}/regens

Guard preflight (product mode only)

When ANOMALYGEN_PRODUCT_MODE=1, run .agents/skills/anomalygen-guard/scripts/preflight.py before any GPU work and fix any BLOCKED issues. --validation-jsonl is forwarded only when the user supplied one; for MODE=finetune_only omit --num-sdg if not supplied. See references/guard-and-custom-counts.md for the full preflight command with all forwarded flags and the validation-JSONL / allocate_samples.py 0-entry checks.


Phase 0 — checkpoints

Read references/finetune.md §Phase 0 for HF_TOKEN requirements and what gets downloaded. Both scripts default to the 2B base + t5-large (~40 GB); pass --model-sizes ${MODEL_SIZE^^} so the chain checks and fetches the base size this run actually uses (2b→2B, 14b→14B) — otherwise a 14b run silently passes the 2B-only check and never downloads its checkpoint. Verify first; download only what is missing.

${ANOMALYGEN_SCRIPTS}/check.sh --model-sizes ${MODEL_SIZE^^} \
    || ${ANOMALYGEN_SCRIPTS}/download_checkpoints.sh --model-sizes ${MODEL_SIZE^^}

Phase 1 — fine-tune (skip when MODE=inference_only)

Read references/finetune.md §Phase 1 for dataset structure, config template details, and best-checkpoint selection. Four steps: (1) validate dataset / derive anomaly types, (2) generate the validation JSONL (skip if user supplied VALIDATION_JSONL), (3) generate the training config — show it to the user and confirm before writing — (4) launch training in the background. Then derive CKPT (path encodes upper-case MODEL_SIZE) and STEP (highest nn_score step from validation logs). If MODE=finetune_only, stop after training. See references/finetune-commands.md for the exact Step 1–4 commands and the CKPT/STEP derivation snippet.


Phase 2 — prep-testcase (skip when MODE=finetune_only)

Read references/inference.md §Phase 2 for AMP routing detail and n_seeds sizing. Do NOT pass --seeds — it is auto-computed and is not a recognized flag. prep_testcase.sh defaults to --mode inference (uniform allocation across defect types, no KPI floor), which Phase 2 always uses.

${ANOMALYGEN_SCRIPTS}/prep_testcase.sh \
    --name ${NAME} --num-sdg ${NUM_SDG} \
    --dataset-dir ${DATASET_DIR} \
    --clean-dir ${CLEAN_DIR} \
    --defect-spec ${DEFECT_DESC} \
    --amp-output-dir ag_inference/${NAME}/amp \
    --output-jsonl ${JSONL}

Custom per-defect counts: when the user specifies counts per defect type, translate to --num-sdg plus a --per-defect-counts JSON dict (types absent from the dict get 0; sum should equal --num-sdg, else the script warns on stderr and uses the override sum). Confirm the allocation when intent is ambiguous. See references/guard-and-custom-counts.md for the full --per-defect-counts command example and the ambiguity-handling detail.


Phase 3 — SDG → original/

Read references/inference.md §Phase 3 for JSONL validation against the checkpoint, multi-GPU caveats, and output verification.

python3 -m scripts.utilities.validate_checkpoint ${CKPT} --step ${STEP}
python3 -m scripts.utilities.validate_jsonl ${CKPT} ${JSONL}

${ANOMALYGEN_SCRIPTS}/run_sdg.sh \
    --checkpoint_dir ${CKPT} --step ${STEP} \
    --input_jsonl ${JSONL} --output_dir ${ORIGINAL} \
    --model_size ${MODEL_SIZE} --num_gpus ${NUM_GPUS}

${ANOMALYGEN_SCRIPTS}/verify_output.sh ${JSONL} ${ORIGINAL}

Phase 4 — eval original/

Read references/inference.md §Eval for score interpretation and feature-count explanation. run_eval.sh writes per_sample.csv and eval.log inside original/ and merges nn_score into SDG_result.csv.

${ANOMALYGEN_SCRIPTS}/run_eval.sh \
    --real-path ${DATASET_DIR} --generated-path ${ORIGINAL} \
    --anomaly-types ${DEFECTS[@]}

Phase 5 — per-sample search rounds

Read references/inference.md §Phase 5 for draw strategy, ranges, and re-AMP guidance. For r in 1..NUM_SEARCH_RUN:

  1. Read prior round's per_sample.csv (or ${ORIGINAL}/per_sample.csv for r=1).

  2. Write ${ROUNDS}/round_${r}/draws.json with selected (guidance, crop_ratio) per sample.

  3. Run round via ${ANOMALYGEN_SCRIPTS}/run_round.sh (SDG + eval; the round dir gets its own sdg/{SDG_result.csv, per_sample.csv, eval.log}). See references/inference-commands.md §Phase 5 for the full command and flags.

NUM_SEARCH_RUN=0 is valid — skip this phase entirely and let Phase 6 clone original/ into searched/.


Phase 6 — assemble searched/ (stitch only)

Always run assemble (works with 0 rounds — searched/ clones original/, so downstream always reads searched/ regardless of num_search_run). Stitch-only: copies winning images per sample-index into searched/ and carries over per-sample nn_score / mnn_score from each pick's source-round per_sample.csv. No eval — Phase 7 emits the canonical searched/eval.log.

mkdir -p ${ROUNDS}
python3 -m scripts.utilities.assemble_searched \
    --original-dir ${ORIGINAL} --original-csv ${ORIGINAL}/per_sample.csv \
    --rounds-dir ${ROUNDS} --searched-dir ${SEARCHED}

Phase 7 — filter + regen + eval (default nn_threshold=0.4)

Phase 7 runs by default (nn_threshold=0.4) on every mode=full and mode=inference_only invocation; pass nn_threshold=0 to skip it. It filters searched/ by nn_threshold, regenerates dropped samples via re-AMP (fresh (clean, submask) pairing in the same defect type) for up to 5 attempts, then falls back to best-scoring non-passing regens and finally to dropped originals, so the final bucket always equals num_SDG.

Run python3 -m scripts.utilities.filter_with_regen. Pass --allocation ag_inference/${NAME}/allocation.json so regen targets the intended per-defect counts — without it a bucket left short (e.g. by an interrupted SDG) cannot be topped back up to num_SDG. It runs the final run_eval.sh internally — the only eval against searched/. Read references/inference.md §Phase 7 for regen mechanics, source-column tracing, and the regens/regen_summary.csv schema; see references/inference-commands.md §Phase 7 for the full command and flags.


Output layout

Every bucket that gets eval'd carries the same triad of files: SDG_result.csv (generation params + nn_score + guardrail_pass), per_sample.csv (per-sample nn + mnn), and eval.log (aggregate FID / per-defect avg). Buckets live under results/<name>/ as original/ (Phase 3+4), searched/ (Phase 6 stitch + Phase 7 filter+regen+eval), rounds/round_NN/ (Phase 5, plus search_summary.csv), and regens/regen_NN/ (Phase 7, plus regen_summary.csv).

Image content guardrail. A SigLIP content-safety check runs on every generated image and records its verdict in SDG_result.csv.guardrail_pass (1 safe / 0 blocked). A blocked image is replaced with an all-black image that still occupies its slot on disk, so counting files cannot detect it — never hand a guardrail_pass=0 sample downstream. Blacked-out samples score near-zero nn_score, so Phase 7 regenerates them like any other sub-threshold sample. Disable with ANOMALYGEN_IMAGE_GUARDRAIL=0.

See references/output-layout.md for the full directory tree with per-file annotations, the guardrail semantics, and the post-run Verification checklist (image counts per bucket, search_summary.csv / regen_summary.csv row checks, the per-type nn_score / mnn_score / fid fields in each eval.log, and the guardrail_pass sweep).

Error handling

Common pipeline failure modes (missing mask dirs, short/empty AMP output and the 0 entries written halt, mid-round SDG failure resume, off-boundary step, validate_dataset.py's non-zero exit on any pairing issue, the 2B-only check.sh default, and guardrail-blocked black images) are covered in references/error-handling.md; see also references/finetune.md and references/inference.md for phase-specific error handling.

Files

references/inference.md

Inference Reference — Phases 2–7

Detail for anomalygen Phases 2–7. Read before executing any inference phase. Operational summaries for each phase — deep detail is in the per-phase reference files (prep-testcase.md, sdg-inference.md, eval.md, sdg-refine.md). When updating, keep those files in sync.

Contents

  • Pre-flight

  • Phase 2: AMP Routing and JSONL Preparation

  • Phase 3: SDG Inference

  • Eval (Phases 4 and 6)

  • Phase 5: Per-Sample Search

  • Phase 6: Assemble (stitch only)

  • Phase 7: Filter + Regen + Eval


Pre-flight: Environment and Checkpoint Validation

Environment check
nvidia-smi --query-gpu=name,memory.total --format=csv,noheader
python -c "import torch; print(f'torch={torch.__version__}, CUDA={torch.cuda.is_available()}, devices={torch.cuda.device_count()}')"

Stop if CUDA unavailable (conda activate cosmos-predict2); stop if num_gpus exceeds detected count. If compilation errors: export CUDA_HOME=$CONDA_PREFIX.

Checkpoint validation (run before Phase 3)

validate_checkpoint.py ensures ag_config.yaml exists and is well-formed. It prints the supported TEXTURE+ANOMALY set — use this as DEFECTS if not already set from defect_spec.

# What validate_checkpoint.py reads:
cfg["dataloader_train"]["dataset"]["anomaly_types"]
# Each entry is [texture, anomaly] → rendered as "texture+anomaly"

Stop if ag_config.yaml is missing — ask the user to verify checkpoint_dir.


Phase 2: AMP Routing and JSONL Preparation

Read references/prep-testcase.md for the full parameter table, helper script descriptions, pipeline invariant, two calling conventions (validation vs inference), and AMP error diagnosis.

AMP routing table
spatial_dependencyAMP branchExtra inputs required
freeWhole-image ROInone
texttext2roi (Qwen VL + SAM2)roi_prompt_defect_location in defect_spec
cadcad2roi<dataset>/<TEXTURE>/cad_mask/<stem>.png + <dataset>/semantic_segmentation_labels.json

Unrecognized values default to text. Auto-cad routing fires whenever a record has a non-null cad_mask regardless of spatial_dependency.

Clean image discovery

prep_testcase.sh probes these layouts in order:

  1. <clean_dir>/<TEXTURE>/clean_image/*

  2. <clean_dir>/<TEXTURE>/*

  3. flat <clean_dir>/*

When clean images live at <dataset_dir>/<TEXTURE>/clean_image/, omit --clean-dir (defaults to dataset_dir).

Pairing strategy

Budget per defect = num_submasks[d] × num_cleans[texture] (every submask × clean combination). Pairing iterates every combination once (deterministic shuffle per defect) before any pair repeats.

JSONL defaults: guidance=7.0, crop_ratio=2.0, seed=42 — overridden by Phase 5 search.

n_seeds sizing

Auto-computed from allocation — do NOT pass --seeds:

n_seeds = max_d ⌈allocation[d] / (num_submasks[d] × num_cleans[texture])⌉

n_seeds > 1 only when allocation exceeds the pair budget.

Submask handling

AMP's preprocess_submask defaults submask_split_largest=True — a multi-component training submask is reduced to its largest connected component. Accept this default unless preserving multiple components is required for a specific defect. To override, set submask_split_largest: false on the individual record in amp_samples.json before build_jsonl.py runs.

Verification after prep_testcase.sh
  • JSONL has num_SDG entries (minus logged AMP skips).

  • allocation.json sums to num_SDG.

  • amp_samples.json has exactly num_SDG records.

Phase 2 errors
  • Validator failure → stop with itemised report (missing submask/clean/cad/prompt).

  • AMP output count < allocation → build_jsonl.py errors (check run_auto_roi_amp.py logs for NO_DETECTION / FAILED).

  • Mask-size mismatch → verify_jsonl.py auto-resizes into resized_masks/ cache.


Phase 3: SDG Inference

Read references/sdg-inference.md for the full parameter table, step-by-step detail, multi-GPU VRAM constraints, and verification checklist.

JSONL validation against checkpoint

validate_jsonl.py cross-checks anomaly types in the JSONL against the checkpoint's supported set. If any are unsupported, stop and show the mismatch:

Supported:  TEXTURE+TYPE_A, TEXTURE+TYPE_B
JSONL has:  TEXTURE+TYPE_C  ← unsupported

Options: retrain with extended defect set, use an isolated model for the new defect, or trim defect_spec to supported types.

If many image/mask paths are missing → stop; ask the user to verify paths before burning GPU time.

run_sdg.sh flags
${ANOMALYGEN_SCRIPTS}/run_sdg.sh \
    --checkpoint_dir <CKPT> \
    --step <STEP> \
    --input_jsonl <JSONL> \
    --output_dir <OUTPUT_DIR> \
    --model_size <2b|14b> \
    [--num_gpus N] \
    [--seed 0]
Multi-GPU caveats
ConfigBehavior
14B + num_gpus > 1FSDP auto-disabled at inference; each rank holds the full 14B model (~80 GB VRAM per GPU)
14B + single GPUFSDP enabled; fits on smaller GPUs
2B + any num_gpusStandard DDP; no special VRAM constraint

NCCL hang controls (set as env vars before run_sdg.sh if needed):

VarDefaultEffect
ANOMALY_GEN_FINALIZE_BACKENDglooSet to nccl only if gloo finalization hangs
TORCH_DISTRIBUTED_TIMEOUT_SEC1800Process-group timeout in seconds
TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC(alias)Same effect as TORCH_DISTRIBUTED_TIMEOUT_SEC; set whichever is defined in your environment
MASTER_PORT12341Override if port is occupied
SDG output structure
<output_dir>/
├── reconstructed_image/   # final synthetic anomaly images
├── annotated_image/
├── cropped_image/
├── cropped_mask/
├── original_image/
├── original_mask/
└── SDG_result.csv
Verify before eval
${ANOMALYGEN_SCRIPTS}/verify_output.sh ${JSONL} ${OUTPUT_DIR}

Counts in reconstructed_image/ must match JSONL entry count. If SDG was interrupted, do NOT eval the partial output — re-run SDG first.

Phase 3 errors
  • Missing ag_config.yaml → stop; verify checkpoint_dir.

  • step not on a save_iter boundary → torch.load FileNotFoundError; run ls ${CKPT}/checkpoints/model/iter_*.pt and pick a valid step.

  • OOM → reduce num_gpus or switch to model_size=2b.

  • Non-binary masks → pipeline raises ValueError; masks must be 0 or 255 only.

  • Port conflict → increment MASTER_PORT.


Eval (run_eval.sh — used by Phase 4, search rounds, and Phase 7)

Read references/eval.md for the full parameter reference, example output table (FID column comes first — surprises people), detailed pre-flight, and all error cases. Summary of the essentials below.

run_eval.sh flags
${ANOMALYGEN_SCRIPTS}/run_eval.sh \
    --real-path <real_path> \
    --generated-path <generated_path> \
    --anomaly-types <TEXTURE+TYPE> [<TEXTURE+TYPE> ...] \
    [--per-sample-csv <path>] \
    [--backbone cradio_v3_base]

per_sample.csv is always emitted to <generated_path>/per_sample.csv by default. Columns: anomaly_type, path, nn_score, mnn_score. sdg-refine and filter_with_regen.py both consume this file.

Score interpretation

nn_score (DINOv2 nearest-neighbour, locked to dinov2-large) is the key KPI — higher is better. It is relative: compare within the same dataset and backbone, not across datasets. Scoring uses top-K=3 averaging (compute_correspondence_kpi): each generated image is scored against every real reference of its type and the three highest-NN values are averaged.

mnn_score (mutual nearest-neighbour) is a diagnostic for refinement internals. fid (using backbone flag, default cradio_v3_base) is a secondary diagnostic.

If a type has < 2 real or generated samples → FID is skipped for that type and logged as None; nn_score/mnn_score still run.

If a type has < 10 real images → warn that nn_score may be noisy. Interpret results cautiously and consider acquiring more training data.

Feature counts

The eval log reports feature counts that may exceed image count. This is expected: mask_crop_images extracts individual defect instances via DBSCAN clustering (eps=30) on mask contours. A single image with a multi-region mask produces multiple feature crops.

Eval pre-flight

Check before running:

  1. reconstructed_image/ exists and is non-empty.

  2. No SDG process is still writing to the output directory.

  3. Auto-detect anomaly types from generated filenames if not supplied:

    ls <generated_path>/reconstructed_image/ | sed 's/_[0-9]*\.\(png\|jpg\)$//' | sort -u
Eval errors
  • Empty reconstructed_image/ → SDG may not have finished; stop.

  • Anomaly type not found in real data → 0 real features; check <TEXTURE>/anomaly_image/<TYPE>/ structure.

  • SDG still running → wait for completion; partial output produces incorrect scores.


Read references/sdg-refine.md for the full inputs table, draws.json alignment detail (SDG_result.csv index column), output layout, and re-AMP heuristics.

Agent draw strategy

For each round r:

  1. Read per_sample.csv from round r-1 (or original/per_sample.csv for r=1).

  2. For each sample, pick new (guidance, crop_ratio). Focus search budget on low-scoring samples. Skip samples already scoring well to save inference time.

  3. Write draws.json to ${ROUNDS}/round_${r}/draws.json.

draws.json format
{
  "<sample_index>": {"guidance": 4.2, "crop_ratio": 2.7},
  "<sample_index>": {"guidance": 8.1, "crop_ratio": 1.8}
}
  • Sample indices are 0-based JSONL line numbers.

  • Omitted samples are not retried this round (stay at current best-seen).

  • Ranges to consider: guidance ∈ [1.5, 10.0], crop_ratio ∈ [1.5, 10.0]. Narrow or widen based on prior-round feedback.

run_round.sh produces rounds/round_r/testcase.jsonl, sdg/, and per_sample.csv. The sdg/SDG_result.csv.index column carries the base-JSONL sample_index, keeping assemble_searched.py aligned across rounds.

Re-rolling AMP (optional)

By default the (clean_image, mask) pair per sample index is fixed across all rounds — only (guidance, crop_ratio) change. If nn_score stays flat for a sample across ≥ 2 rounds of (g, c) variation, the mask placement itself may be the blocker. Add --reamp-seed to re-run AMP with a fresh base seed on the same (clean, submask) pairs:

${ANOMALYGEN_SCRIPTS}/run_round.sh \
    ...standard args... \
    --reamp-seed $((1000 + r)) \
    --defect-spec ${DEFECT_DESC}

Use sparingly — each re-AMP is one extra run_auto_roi_amp.py pass. The text2roi ROI cache is reused, so Qwen VL + SAM2 are not re-run.

num_search_run = 0

Valid. Skip run_round.sh entirely; Phase 6 (assemble_searched.py) still runs with an empty rounds dir and clones original/ into searched/, preserving the downstream invariant that the final SDG bucket is always searched/.

search_summary.csv

After Phase 6 assemble: rounds_dir/search_summary.csv has one row per sample with best_round, best_guidance, best_crop_ratio, best_nn_score, attempts.


Phase 6: Assemble searched/ (stitch only)

Runs assemble_searched.py to pick best-of-rounds (or clone original/ when num_search_run=0) into searched/. No eval runs here. The script copies each picked sample's images into searched/ and stitches searched/per_sample.csv by carrying over per-sample nn_score and mnn_score from the picked sample's source round per_sample.csv — correspondence-to-real-set scoring is per-sample-independent (one generated image against the real set, no sibling-generation coupling), so the stitched values are exact, not approximate. The same nn_score gets merged into searched/SDG_result.csv. Phase 7 owns the canonical post-pipeline eval against the final regen-aware bucket.


Phase 7: Filter + Regen + Eval

Runs by default (nn_threshold=0.4). Set nn_threshold=0 to disable.

Updates searched/ in place — downstream always reads searched/ as the final SDG bucket regardless of whether Phase 7 ran or whether num_search_run was 0.

filter_with_regen.py orchestrates a re-AMP + re-pair regen flow:

  1. Initial filter — partition source bucket into passing_per_defect and dropped_per_defect. Target allocation (per-defect count) comes from --allocation (the pipeline's allocation.json) when given, else from the source bucket. Samples with no nn_score in per_sample.csv are excluded from keep/fallback (logged; regen replaces them).

  2. Regen loop — for each attempt up to 5:

    • Compute needed_per_defect = target_alloc - kept_per_defect. If zero everywhere, stop.

    • Write a subset allocation.json for the still-needed defects.

    • Run build_amp_samples.py --seed=attempt_seed — per-defect (clean, submask) lists get shuffled before pairing, so each attempt's pairings are distinct.

    • Run run_auto_roi_amp.py --seed=attempt_seed (new placement).

    • Run build_jsonl.py, then overwrite each row's seed field with attempt_seed (so diffusion noise via AnomalyInpaintCondition.seed → misc.arch_invariant_rand also varies).

    • Run SDG into regens/regen_NN/sdg/, eval.

    • Admit new samples scoring ≥ threshold into admitted_regens_by_defect, greedy by nn descending up to the defect's quota.

  3. Per-defect fallback fill — if a defect is still short of its target, top up with the best non-admitted regens for that defect, then with the highest-scoring dropped originals (last resort).

  4. Atomic-ish in-place swap — stage to searched.staging/, rename over searched/. Atomic on same filesystem.

regens/ (sibling of rounds/) holds Phase 7 artifacts: regens/regen_NN/{allocation.json, amp_samples.json, amp/, testcase.jsonl, sdg/} per attempt, plus regens/regen_summary.csv with columns sample_index (-1 for regen), source, clean_image, mask_filename, prev_nn, nn_score, passed_threshold, output_filename.

For at-a-glance tracing, searched/SDG_result.csv carries a source column:

  • original — survived Phase 5 assemble straight from Phase 3 SDG

  • round_<N> — Phase 5 search round N produced this sample's best attempt

  • regen_<k> — Phase 7 regen attempt k produced this sample

searched/SDG_result.csv alone suffices for most tracing (it has image_filename, mask_filename, nn_score, source). regen_summary.csv adds prev_nn and passed_threshold for deeper audit.

Per-attempt eval is invoked with only the anomaly types present in that attempt's subset, suppressing harmless "No generated defect patches" warnings for types absent from the subset.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Needs Python

The author says: Requires docker + nvidia-container-toolkit and a CUDA GPU. Pulls the `metropolis_sdg.paidf_anomalygen` image declared in `versions.yaml` at the skill bank root.

Security

What our scanner noticed· Medium risk

  • Large base64-encoded blobs
  • References to credential files
  • Instructions that use the network

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
NVIDIA Corporation
Publisher
NVIDIA (Official)
Source
NVIDIA/skills · skills/tao-generate-anomalies · commit fce3cca
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE-APACHE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by NVIDIA Corporation or NVIDIA.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download tao-generate-anomalies.zip