opción
HogarHogar Skill Ciencia de datos y aprendizaje automático tao-analyze-gaps-visual-changenet

tao-analyze-gaps-visual-changenet

NVIDIA/skills NVIDIA/skills

Identifica las muestras más débiles por etiqueta de referencia en los experimentos de NVIDIA TAO VCN Classify mediante la ejecución de un contenedor de Docker que realiza un barrido de umbrales, una puntuación de debilidad y una expansión por condiciones de iluminación; a continuación, muestra las K muestras más débiles para su posterior aumento o reetiquetado.

...Expandir todo
2
Tiempo actualizado 28 de septiembre de 2026

Habilidad de análisis de deficiencias de TAO VCN Classify

Eres analista de los resultados de inferencia de NVIDIA TAO VCN Classify (Visual Component Net). Tu trabajo consiste en identificar las muestras más débiles por cada etiqueta de referencia midiendo la distancia con signo desde el umbral de decisión en la dirección errónea, para luego seleccionarlas con vistas a su aumento o reetiquetado posterior.

Esta habilidad está diseñada para ser ligera. El módulo de clasificación de VCN es un límite binario de puntuación única (PASS frente a NO_PASS según siamese_score), por lo que el análisis es computacional, no investigativo. Todo el cálculo se lleva a cabo mediante una única invocación directa de Docker contra la imagen «tao_toolkit.data_services» declarada en «versions.yaml» (resuelta en tiempo de ejecución; véase «Configuración»). El punto de entrada del contenedor toma [anulaciones de Hydra...]; pasamos gap_analysis vcn_aoi clave=valor …. Cada anulación es una simple pareja clave=valor de Hydra que anula selectivamente el esquema GapAnalysisConfig del script (los valores por defecto están integrados en el contenedor; compruébalo con ` docker run ... gap_analysis vcn_aoi --cfg=job`). (No hay ninguna palabra clave «dataset» dentro del contenedor; ese es el prefijo «pillar» del lanzador TAO y aquí se omite). No necesitas análisis delegados, auditorías de imágenes en varias fases ni agrupaciones por tipo de componente: VCN no expone esas dimensiones. Examina solo un pequeño conjunto de muestras débiles representativas para calificar las brechas una vez que el contenedor haya devuelto el resultado.

La interfaz de la CLI puede variar entre las diferentes compilaciones de contenedores de servicios de datos. Si una invocación de `gap_analysis vcn_aoi ` falla al analizar los argumentos, examina el esquema real una vez por imagen con ` docker run --rm "$DS_IMAGE" gap_analysis vcn_aoi --cfg=job y concilia cualquier clave renombrada (p. ej., «inference_csv» frente a «inference_results_dir», «output_dir» frente a «results_dir») antes de volver a intentarlo. El nombre del archivo Parquet de salida es «kpi_gaps.parquet».

Entradas

  1. Directorio de resultados del experimento: contiene el archivo `inference/inference.csv ` procedente de la inferencia de TAO VCN Classify. Columnas obligatorias: `input_path`, `object_name`, `label`, `siamese_score`. Pasa el directorio (p. ej., «inference/latest/»), no el archivo CSV: el contenedor lee «inference_results_dir/inference.csv».
  2. Directorio de código/configuración de entrenamiento: contiene el archivo YAML de entrenamiento de VCN. El contenedor lee de él dataset.classify.input_map (lista de condiciones de iluminación) y dataset.classify.image_ext para expandir cada muestra débil en una fila por cada condición de iluminación.
  3. Directorio del conjunto de datos: la ruta raíz de la imagen se antepone a la ruta relativa input_path de cada fila (kpi_media_path).
  4. Modificaciones del esquema: min_recall, top_k_per_label y, opcionalmente, un umbral fijo se pasan como modificaciones de Hydra (valores por defecto: min_recall=1,0; top_k_per_label=50; threshold=-1,0, lo que significa un barrido). top_k_per_label debe ser un entero positivo; si se omite, el contenedor pasa al modo de «filtro por debajo del umbral», lo que con min_recall=1,0 devuelve solo clasificaciones erróneas de tipo PASS y cero filas de tipo NO_PASS. Véase «Errores comunes».

Configuración

El barrido de umbrales, la clasificación de debilidades y la expansión por iluminación se ejecutan dentro de la imagen tao_toolkit.data_services declarada en versions.yaml. Resuelve el URI concreto una vez al inicio de la ejecución; a continuación, confirma que Docker, el kit de herramientas de contenedores de NVIDIA y una GPU estén presentes, y asegúrate de que la imagen esté almacenada en caché:

# Resolver tao_toolkit.data_services → URI concreta nvcr.io/... de versions.yaml
DS_IMAGE=$(python3 -c "import yaml,os; print(yaml.safe_load(open(os.environ['TAO_SKILL_BANK_PATH']+'/versions.yaml'))['images']['tao_toolkit']['data_services'])")
echo "DS_IMAGE=$DS_IMAGE"

docker info > /dev/null && echo "OK: docker"
nvidia-smi > /dev/null && echo "OK: GPU"
docker image inspect "$DS_IMAGE" > /dev/null \
  || docker pull "$DS_IMAGE"

TAO_SKILL_BANK_PATH suele ser exportada por el banco de habilidades instalado. Si no está configurada, dirígela a la raíz del repositorio del banco de habilidades antes de continuar. Se requiere una GPU; interrumpir el proceso en una fase temprana en un host sin GPU evita un error confuso más adelante.

Hay tres reglas de configuración fundamentales en las que es fácil equivocarse:

  • Montaje de rutas: todas las rutas del host que el contenedor lee o escribe (inference.csv, el archivo YAML de entrenamiento, la raíz de la imagen del conjunto de datos, el directorio de salida) deben montarse mediante bind; la forma más sencilla es con -v $WORKSPACE:$WORKSPACE -w $WORKSPACE, de modo que las rutas absolutas se resuelvan de forma idéntica en ambos lados.
  • No pases --user $(id -u):$(id -g): provoca un KeyError: «getpwuid(): uid not found: » durante la importación de transformers por parte del contenedor; en su lugar, chown devuelve el UID del host posteriormente.
  • -e es obligatorio, no opcional: las imágenes actuales lo exigen estrictamente y se cierran con un ValueError: La subtarea vcn_aoi requiere el siguiente argumento: -e/--experiment_spec_file antes de analizar las modificaciones de la CLI.

Consulte references/container-setup.md para conocer el patrón completo de montaje de rutas, la justificación de--user/chown y el comando chown de Alpine, la guía sobre el uso de múltiples --v y los detalles del requisito -e .

Método

Toda la habilidad consiste en una única invocación de `docker run` seguida de una pequeña comprobación visual puntual. El contenedor realiza los pasos 1 a 4 de forma interna (barrido de umbrales, puntuación de vulnerabilidades, selección de los K principales, expansión por iluminación). Tú te encargas del paso 5 (comprobación visual puntual) directamente con la herramienta Read.

Pasos 1 a 4: ejecutar el contenedor

$DOCKER gap_analysis vcn_aoi \
    inference_results_dir=/inference/

Siempre hay que pasar el parámetro top_k_per_label. Este es el argumento que cambia el contenedor del filtro predeterminado «muestras por debajo del umbral» a una clasificación adecuada de top-K-por-etiqueta . Con min_recall=1,0, el umbral se sitúa, por definición, en o por debajo de cada puntuación NO_PASS, por lo que el filtro «por debajo del umbral» devuelve ÚNICAMENTE filas PASS clasificadas erróneamente y cero filas NO_PASS, lo que lo hace inútil como cola de aumento. Con top_k_per_label establecido en un entero positivo (ya sea en la especificación o como una sobrescritura de Hydra), el contenedor calcula la debilidad con signo respecto al umbral para cada fila y muestra las K más débiles por etiqueta de verdad fundamental, que es la salida clasificada por etiqueta que consumen los pasos posteriores.

Lee el archivo inference.csv, recorre todos los valores únicos de siamese_score más uno justo por debajo del mínimo, conserva los candidatos con una recuperación de la clase NO_PASS ≥ min_recall (con una tolerancia de 1e-12 ) y, a continuación, selecciona el umbral con el mejor F1 (en caso de empate: precisión y, a continuación, valor del umbral). Para cada fila, calcula la debilidad con signo a partir de ese umbral (positiva = clasificación errónea, negativa = correcta, magnitud = margen). Ordena por debilidad en orden descendente y toma los primeros top_k_per_label por cada etiqueta de referencia; a continuación, expande cada fila débil en una fila por cada condición de iluminación utilizando dataset.classify.input_map y dataset.classify.image_ext del archivo YAML de entrenamiento.

Si ningún umbral candidato cumple el objetivo de recuperación, el contenedor sale con un valor distinto de cero y escribe el archivo unreachable_kpi.txt en results_dir, explicando qué nivel de recuperación puede alcanzar realmente el modelo. En ese caso, detén el análisis tras la llamada a Docker, redacta un informe de una sola sección en el que se explique que el modelo es fundamentalmente incapaz de alcanzar el KPI en ningún punto de funcionamiento, y recomienda volver a entrenar o reetiquetar — omite la comprobación visual aleatoria.

El contenedor escribe en results_dir:

Artefacto Contenido
kpi_gaps.parquet Los Top-K más débiles por etiqueta, desglosados por iluminación. Columnas: ruta de archivo, etiqueta, puntuación siamesa, debilidad.
threshold.txt Umbral de decisión elegido (un único número de tipo float, texto sin formato).
metrics.json En el umbral elegido: precisión, recuperación, F1, matriz de confusión {tp, fp, tn, fn}, además de por etiqueta {total, media_de_debilidad, mediana_de_debilidad, máxima_de_debilidad, n_clasificaciones_erróneas}.
weak_samples_breakdown.txt Desglose de las filas conservadas por etiqueta: total, <%> de todas las filas conservadas, N clasificadas erróneamente (debilidad > 0), N marginales (debilidad ≤ 0).
unreachable_kpi.txt Solo se genera cuando el objetivo de recuperación es inalcanzable. La presencia de este archivo significa: omitir el paso 5, generar el informe resumido y recomendar un nuevo entrenamiento.

Imprime el resumen de la salida estándar del contenedor (umbral elegido, recuento de filas conservadas, desglose por etiqueta) en tu propia salida estándar para que el hook de comprobación de scripts pueda verificar la salida generada por la ejecución.

Paso 5 — Comprobación visual aleatoria (pequeña, fija)

Omite este paso si existe el archivo unreachable_kpi.txt. De lo contrario, utiliza la herramienta «Read» para ver las 5 muestras «PASS» más débiles y las 5 muestras «NO_PASS» más débiles de kpi_gaps.parquet (deduplicadas a una fila por muestra, utilizando la ruta de archivo «FIRST-lighting»), clasifica cada una de ellas exactamente en una de las siguientes categorías: «etiquetada incorrectamente », «caso límite », «calidad de los datos » o «sistemática», y copia cada imagen visualizada (redimensionada a 128×128 si hay PIL disponible; de lo contrario, simplemente cópiala) en /rca_images/. Esta es la única inspección de imágenes necesaria: no revises docenas de imágenes, no realices agrupaciones por modos de fallo ni audites imágenes de referencia (VCN no tiene imágenes de referencia).

Consulte references/visual-spot-check.md para conocer el orden exacto de selección de muestras, la regla de deduplicación por iluminación, la definición completa de cada categoría de veredicto y los detalles sobre la copia de imágenes.

Invocación de referencia

Pega y edita el espacio de trabajo, las cuatro rutas y los dos parámetros numéricos; esto se ejecuta de principio a fin. Captura la salida estándar (stdout) para que el gancho de comprobación del script detecte el recuento de filas.

WORKSPACE=           # montado de forma idéntica dentro del contenedor
EXP_DIR=     # contiene inference/inference.csv y train.yaml; debe estar dentro de $WORKSPACE
DATASET_ROOT=         # raíz de imágenes para las entradas de input_path en inference.csv; debe estar dentro de $WORKSPACE
MIN_RECALL=1.0                       # valor predeterminado de «cero omisiones»; reducirlo si se relajan los KPI
TOP_K=50                             # presupuesto de aumento por etiqueta
OUT="$EXP_DIR/rca_results/$(date +%Y-%m-%d_%H%M%S)"
SPEC="$OUT/vcn_aoi_spec.yaml"
IMG=$(python3 -c "import yaml,os; print(yaml.safe_load(open(os.environ['TAO_SKILL_BANK_PATH']+'/versions.yaml'))['images']['tao_toolkit']['data_services'])")

mkdir -p "$OUT"

# Escribir la especificación del análisis de brechas para esta ejecución
cat > "$SPEC" <<EOF
min_recall: $MIN_RECALL
top_k_per_label: $TOP_K
EOF

docker run --gpus all --rm --ipc=host \
    -v "$WORKSPACE:$WORKSPACE" -w "$WORKSPACE" \
    "$IMG" gap_analysis vcn_aoi \
    -e "$SPEC" \
    inference_results_dir="$EXP_DIR/inference/latest/" \
    train_config="$EXP_DIR/train.yaml" \
    kpi_media_path="$DATASET_ROOT" \
    results_dir="$OUT"

# El contenedor escribe como root con la opción --user desactivada; si es necesario, se cambia el propietario (chown) al UID del host.
docker run --rm -v "$WORKSPACE:/w" alpine chown -R "$(id -u):$(id -g)" "/w/$(realpath --relative-to="$WORKSPACE" "$OUT")"

# Impresión de comprobación para que el gancho de script-check vea números reales
python3 - "$OUT" << 'PYEOF'
import json, os, sys
out = sys.argv[1]
unreachable = os.path.join(out, "unreachable_kpi.txt")
if os.path.isfile(unreachable):
    print("KPI INACCESIBLE — ver", unreachable)
    sys.exit(0)
with open(os.path.join(out, "threshold.txt")) as f:
    print("umbral:", f.read().strip())
with open(os.path.join(out, "metrics.json")) as f:
    m = json.load(f)
print(f"precisión={m['precisión']:.4f} recuperación={m['recuperación']:.4f} F1={m['F1']:.4f}")
import pandas as pd
df = pd.read_parquet(os.path.join(out, "kpi_gaps.parquet"))
print(f"kpi_gaps.parquet: filas={len(df)}, columnas={list(df.columns)}")
print(df['label'].value_counts())
PYEOF

Resultados

Guarda todo en una carpeta con marca de tiempo dentro del directorio de resultados del experimento. Los resultados del contenedor se guardan directamente allí; la comprobación visual aleatoria se guarda en rca_images/; cualquier gancho de empaquetado en tiempo de ejecución puede añadir artefactos de captura de sesión/configuración después de que se haya escrito RCA_Report.md.

/rca_results/AAAA-MM-DD_HHMMSS/
├── RCA_Report.md              # Informe completo de análisis de brechas (lo redactas tú)
├── kpi_gaps.parquet           # Contenedor: las K más débiles por etiqueta, desglosadas por iluminación
├── threshold.txt              # Contenedor: umbral de decisión elegido (único número flotante)
├── metrics.json               # Contenedor: matriz de confusión + estadísticas de distribución por etiqueta
├── weak_samples_breakdown.txt # Contenedor: recuento por etiqueta / muestras mal clasificadas / recuentos marginales
├── unreachable_kpi.txt        # Contenedor: SOLO cuando ningún umbral cumple con min_recall
├── rca_images/                # Tú: miniaturas de las 10 muestras débiles visualizadas
├── rca_config/                # Copiado automáticamente por el hook
└── session log/artifacts      # Opcional, captura del empaquetado dependiente del tiempo de ejecución

Al inicio de la ejecución, obtén la marca de tiempo real ejecutando «date +%Y-%m-%d_%H%M%S» en Bash. NO la introduzcas de forma fija ni la adivines. Si el usuario especifica una ruta de salida personalizada, utilízala en su lugar, pero mantén la misma estructura interna.

Errores habituales

El modo de fallo más grave es olvidarse de «top_k_per_label» cuando «min_recall=1,0»: a ese nivel de recuperación, el umbral elegido se sitúa en o por debajo de cada puntuación NO_PASS, por lo que, sin top_k_per_label, el contenedor recurre a un filtro de «muestras por debajo del umbral» que devuelve ÚNICAMENTE filas PASS mal clasificadas y cero filas NO_PASS, lo que interrumpe la cola de aumento. Incluye siempre un top_k_per_label positivo explícito (por defecto 50) en la especificación o como una configuración de Hydra.

Consulta references/pitfalls.md para ver la lista de comprobación completa, que incluye: olvidarse de top_k_per_label; pasar --user; llamar al programa solo con modificaciones de Hydra (sin -e ); archivo de especificaciones fuera de $WORKSPACE; archivo de especificaciones con centinelas ??? sin resolver; imagen no descargada / etiqueta incorrecta; descoincidencia en el montaje de rutas; archivo unreachable_kpi.txt escrito; falta de columnas obligatorias en inference.csv; falta de dataset.classify.input_map o image_ext en el YAML de entrenamiento; kpi_media_path que no coincide con los prefijos de input_path; y no se detecta ninguna GPU desde el interior del contenedor.

Estructura del informe

Redacta el archivo RCA_Report.md como un análisis conciso (entre 1000 y 1800 palabras) de las deficiencias computacionales: la profundidad se consigue con cifras precisas y una lista clara de acciones, no con la narrativa. La plantilla completa del informe (7 secciones: Veredicto, Selección de umbrales, Distribución de debilidades, Muestras más débiles Top-K, Comprobación visual aleatoria, Desglose por etiqueta, Acciones recomendadas —con la matriz de confusión y los diseños de las tablas—) se encuentra en references/output-template.md. Si existe el archivo unreachable_kpi.txt, sustituye las secciones 3 a 6 por una única sección breve en la que se cite el contenido de dicho archivo y reduce la sección 7 a una sola recomendación: volver a entrenar o reetiquetar.

Orden de ejecución

  1. Resuelve DS_IMAGE a partir de versions.yaml (images.tao_toolkit.data_services); a continuación, ejecuta docker info, nvidia-smi y docker image inspect "$DS_IMAGE" (descargándola si falta) una vez para confirmar el entorno. Aborta la operación con un mensaje claro si falla alguno de los pasos.
  2. Ejecuta «date +%Y-%m-%d_%H%M%S » para obtener la marca de tiempo; crea «/rca_results//».
  3. Escribe vcn_aoi_spec.yaml en el directorio con la marca de tiempo, rellenando los campos min_recall y top_k_per_label. Guárdalo en $WORKSPACE para que la ruta -e se resuelva dentro del contenedor.
  4. Ejecuta ` docker run … "$DS_IMAGE" gap_analysis vcn_aoi -e vcn_aoi_spec.yaml inference_results_dir=… train_config=… kpi_media_path=… output_dir=…`. El contenedor escribe kpi_gaps.parquet, threshold.txt, metrics.json y weak_samples_breakdown.txt en results_dir. Imprime el umbral elegido y el recuento de filas conservadas en la salida estándar (stdout) para que el hook script-check pueda verificar la salida generada por la ejecución.
  5. Si existe el archivo unreachable_kpi.txt, omite el paso 6 y genera el informe resumido. De lo contrario, continúa.
  6. Selecciona 10 muestras débiles (las 5 más débiles que han pasado la prueba y las 5 más débiles que no la han pasado) de kpi_gaps.parquet, visualiza cada imagen de prueba con Read, clasifícalas y cópialas en rca_images/.
  7. Escribe RCA_Report.md en último lugar: al hacerlo se activa el hook de empaquetado, que copia los registros de sesión y la configuración de la habilidad junto con el archivo.
Ver en GitHub
---
name: tao-analyze-gaps-visual-changenet
description: Identifies the weakest samples per ground-truth label in NVIDIA TAO VCN Classify experiments by running a Docker container that performs threshold sweep, weakness scoring, and per-lighting expansion, then surfaces top-K weak samples for downstream augmentation or relabeling.
license: Apache-2.0
---

# TAO VCN Classify Gap Analysis Skill

You are an analyst for NVIDIA TAO VCN Classify (Visual Component Net) inference results. Your job is to identify the **weakest samples per ground-truth label** by measuring signed distance from the decision threshold *in the wrong direction*, then surface them for downstream augmentation or relabeling.

This skill is intentionally lightweight. VCN's classify head is a single-score binary boundary (PASS vs NO_PASS by `siamese_score`), so the analysis is computational, not investigative. The whole computation lives behind one direct `docker run` invocation against the `tao_toolkit.data_services` image declared in `versions.yaml` (resolved at runtime — see Setup). The container's entrypoint takes `<category> <action> [hydra overrides...]`; we pass `gap_analysis vcn_aoi key=value …`. Each override is a bare Hydra `key=value` that selectively overrides the script's `GapAnalysisConfig` schema (defaults are baked into the container; introspect with `docker run ... gap_analysis vcn_aoi --cfg=job`). (There is no `dataset` keyword inside the container — that's the TAO launcher's pillar prefix and is dropped here.) You do **not** need delegated analysis, multi-phase image audits, or component-type clustering — VCN does not expose those dimensions. View only a small set of representative weak samples to qualify the gaps after the container returns.

CLI surface can shift between data-services container builds. If a `gap_analysis vcn_aoi` invocation fails on argument parsing, introspect the actual schema once per image with `docker run --rm "$DS_IMAGE" gap_analysis vcn_aoi --cfg=job` and reconcile any renamed keys (e.g. `inference_csv` vs `inference_results_dir`, `output_dir` vs `results_dir`) before retrying. Output parquet name is `kpi_gaps.parquet`.

---

## Inputs

1. **Experiment result directory** — contains `inference/inference.csv` from TAO VCN Classify inference. Required columns: `input_path`, `object_name`, `label`, `siamese_score`. Pass the **directory** (e.g. `inference/latest/`), not the CSV file — the container reads `inference_results_dir/inference.csv`.
2. **Training code/config directory** — contains the VCN train YAML. The container reads `dataset.classify.input_map` (lighting condition list) and `dataset.classify.image_ext` from it to expand each weak sample into one row per lighting.
3. **Dataset directory** — image root prepended to the relative `input_path` from each row (`kpi_media_path`).
4. **Schema overrides** — `min_recall`, `top_k_per_label`, and optionally a hard-pinned `threshold` are passed as Hydra overrides (defaults: `min_recall=1.0`, `top_k_per_label=50`, `threshold=-1.0` meaning sweep). **`top_k_per_label` must be a positive integer** — omitting it flips the container into "below-threshold filter" mode, which at `min_recall=1.0` returns only PASS misclassifications and zero NO_PASS rows. See Common pitfalls.

---

## Setup

The threshold sweep, weakness ranking, and per-lighting expansion all run inside the `tao_toolkit.data_services` image declared in `versions.yaml`. Resolve the concrete URI once at the top of the run, then confirm Docker, the NVIDIA container toolkit, and a GPU are present and ensure the image is cached:

```bash
# Resolve tao_toolkit.data_services → concrete nvcr.io/... URI from versions.yaml
DS_IMAGE=$(python3 -c "import yaml,os; print(yaml.safe_load(open(os.environ['TAO_SKILL_BANK_PATH']+'/versions.yaml'))['images']['tao_toolkit']['data_services'])")
echo "DS_IMAGE=$DS_IMAGE"

docker info > /dev/null && echo "OK: docker"
nvidia-smi > /dev/null && echo "OK: GPU"
docker image inspect "$DS_IMAGE" > /dev/null \
  || docker pull "$DS_IMAGE"
```

`TAO_SKILL_BANK_PATH` is usually exported by the installed skill bank. If it is unset, point it at the skill-bank repo root before resolving. A GPU is required; aborting early on a GPU-less host saves a confusing late error.

Three setup rules are load-bearing and easy to get wrong:

- **Path mounting** — every host path the container reads or writes (`inference.csv`, train YAML, dataset image root, output dir) must be bind-mounted, simplest with `-v $WORKSPACE:$WORKSPACE -w $WORKSPACE` so absolute paths resolve identically on both sides.
- **Do not pass `--user $(id -u):$(id -g)`** — it triggers `KeyError: 'getpwuid(): uid not found: <uid>'` during the container's `transformers` import; `chown` outputs back to the host UID afterwards instead.
- **`-e <spec>` is required, not optional** — current images hard-require it and exit with `ValueError: The subtask vcn_aoi requires the following argument: -e/--experiment_spec_file` before parsing CLI overrides.

See `references/container-setup.md` for the full path-mounting pattern, the `--user`/`chown` rationale and `alpine` chown command, multi-`-v` guidance, and the `-e <spec>` requirement detail.

---

## Method

The whole skill is a single `docker run` invocation followed by a small visual spot-check. The container does Steps 1–4 internally (threshold sweep, weakness scoring, top-K selection, per-lighting expansion). You handle Step 5 (visual spot-check) directly with the Read tool.

### Step 1–4 — Run the container

```bash
$DOCKER gap_analysis vcn_aoi \
    inference_results_dir=<exp_dir>/inference/<label>/ \
    train_config=<exp_dir>/train.yaml \
    kpi_media_path=<dataset_root> \
    results_dir=<rca_results_dir> \
    top_k_per_label=50
```

> **Always pass `top_k_per_label`.** This is the argument that switches the container
> from the default "samples below threshold" filter into proper top-K-per-label
> ranking. At `min_recall=1.0` the threshold is by construction at-or-below every
> NO_PASS score, so the below-threshold filter returns ONLY misclassified PASS rows
> and zero NO_PASS rows — useless as an augmentation queue. With `top_k_per_label`
> set to a positive integer (either in the spec or as a Hydra override), the
> container computes signed weakness against the threshold for every row and
> surfaces the K weakest **per ground-truth label**, which is the per-label ranked
> output downstream steps consume.

Reads `inference.csv`, sweeps every unique `siamese_score` plus one value just below the minimum, keeps the candidates with NO_PASS-class recall ≥ `min_recall` (with `1e-12` tolerance), then picks the threshold with the best F1 (tie-break: precision, then threshold value). For every row, computes signed weakness from that threshold (positive = misclassified, negative = correct, magnitude = margin). Sorts by weakness descending and takes the top `top_k_per_label` per ground-truth label, then expands each weak row into one row per lighting condition using `dataset.classify.input_map` and `dataset.classify.image_ext` from the train YAML.

If **no** candidate threshold meets the recall target, the container exits non-zero and writes `unreachable_kpi.txt` into `results_dir` explaining which recall the model can actually achieve. In that case, stop the analysis after the docker call, write a one-section report explaining the model fundamentally cannot reach the KPI at any operating point, and recommend retraining or relabeling — skip the visual spot-check.

**Container writes into `results_dir`:**

| Artifact | Contents |
|----------|----------|
| `kpi_gaps.parquet` | Top-K weakest per label, expanded per lighting. Columns: `filepath`, `label`, `siamese_score`, `weakness`. |
| `threshold.txt` | Chosen decision threshold (single float, plain text). |
| `metrics.json` | At the chosen threshold: `precision`, `recall`, `f1`, confusion matrix `{tp, fp, tn, fn}`, plus per-label `{total, mean_weakness, median_weakness, max_weakness, n_misclassified}`. |
| `weak_samples_breakdown.txt` | Per-label kept-row breakdown: `<count>` total, `<%>` of all kept rows, `N` misclassified (weakness > 0), `N` marginal (weakness ≤ 0). |
| `unreachable_kpi.txt` | Only written when the recall target is unreachable. Presence of this file means: skip Step 5, write the abridged report, recommend retrain. |

Print the container's stdout summary (chosen threshold, kept-row counts, per-label breakdown) to your own stdout so the script-check hook can verify the run produced output.

### Step 5 — Visual spot check (small, fixed)

Skip this step if `unreachable_kpi.txt` exists. Otherwise use the Read tool to **view** the 5 weakest PASS samples and the 5 weakest NO_PASS samples from `kpi_gaps.parquet` (deduplicated to one row per sample, using the FIRST-lighting `filepath`), classify each as exactly one of **mislabeled** / **edge case** / **data quality** / **systematic**, and copy each viewed image (resized to 128×128 if PIL is available, otherwise just copy) into `<results_dir>/rca_images/`. This is the only image inspection required — do not view dozens of images, run failure mode clustering, or audit goldens (VCN has no golden images).

See `references/visual-spot-check.md` for the exact sample-selection sort, the per-lighting deduplication rule, the full definition of each verdict category, and the image-copy detail.

---

## Reference invocation

Paste-and-edit the workspace, the four paths, and the two numeric knobs; this runs end-to-end. Capture stdout so the script-check hook sees row counts.

```bash
WORKSPACE=<absolute path>            # mounted identically inside the container
EXP_DIR=<experiment_result_dir>      # contains inference/inference.csv and train.yaml; must be inside $WORKSPACE
DATASET_ROOT=<dataset_root>          # image root for inference.csv input_path entries; must be inside $WORKSPACE
MIN_RECALL=1.0                       # zero-miss default; lower if KPI relaxes
TOP_K=50                             # per-label augmentation budget
OUT="$EXP_DIR/rca_results/$(date +%Y-%m-%d_%H%M%S)"
SPEC="$OUT/vcn_aoi_spec.yaml"
IMG=$(python3 -c "import yaml,os; print(yaml.safe_load(open(os.environ['TAO_SKILL_BANK_PATH']+'/versions.yaml'))['images']['tao_toolkit']['data_services'])")

mkdir -p "$OUT"

# Write the gap-analysis spec for this run
cat > "$SPEC" <<EOF
min_recall: $MIN_RECALL
top_k_per_label: $TOP_K
EOF

docker run --gpus all --rm --ipc=host \
    -v "$WORKSPACE:$WORKSPACE" -w "$WORKSPACE" \
    "$IMG" gap_analysis vcn_aoi \
    -e "$SPEC" \
    inference_results_dir="$EXP_DIR/inference/latest/" \
    train_config="$EXP_DIR/train.yaml" \
    kpi_media_path="$DATASET_ROOT" \
    results_dir="$OUT"

# Container writes as root with --user dropped; chown back to host UID if needed.
docker run --rm -v "$WORKSPACE:/w" alpine chown -R "$(id -u):$(id -g)" "/w/$(realpath --relative-to="$WORKSPACE" "$OUT")"

# Sanity print so the script-check hook sees real numbers
python3 - "$OUT" << 'PYEOF'
import json, os, sys
out = sys.argv[1]
unreachable = os.path.join(out, "unreachable_kpi.txt")
if os.path.isfile(unreachable):
    print("KPI UNREACHABLE — see", unreachable)
    sys.exit(0)
with open(os.path.join(out, "threshold.txt")) as f:
    print("threshold:", f.read().strip())
with open(os.path.join(out, "metrics.json")) as f:
    m = json.load(f)
print(f"precision={m['precision']:.4f} recall={m['recall']:.4f} f1={m['f1']:.4f}")
import pandas as pd
df = pd.read_parquet(os.path.join(out, "kpi_gaps.parquet"))
print(f"kpi_gaps.parquet: rows={len(df)}, cols={list(df.columns)}")
print(df['label'].value_counts())
PYEOF
```

---

## Outputs

Write everything into a timestamped folder under the experiment result directory. The container's outputs go straight there; the visual spot-check writes `rca_images/`; any runtime packaging hook may add session/config capture artifacts after `RCA_Report.md` is written.

```
<experiment_result_dir>/rca_results/YYYY-MM-DD_HHMMSS/
├── RCA_Report.md              # Full gap analysis report (you write this)
├── kpi_gaps.parquet           # Container: top-K weakest per label, expanded per lighting
├── threshold.txt              # Container: chosen decision threshold (single float)
├── metrics.json               # Container: confusion matrix + per-label distribution stats
├── weak_samples_breakdown.txt # Container: per-label count/misclassified/marginal counts
├── unreachable_kpi.txt        # Container: ONLY when no threshold meets min_recall
├── rca_images/                # You: thumbnails of the 10 viewed weak samples
├── rca_config/                # Auto-copied by hook
└── session log/artifacts      # Optional, runtime-dependent packaging capture
```

At the start of the run, get the real timestamp by running `date +%Y-%m-%d_%H%M%S` in Bash. Do NOT hardcode or guess. If the user specifies a custom output path, use that instead but maintain the same internal structure.

---

## Common pitfalls

The single most consequential failure mode is **forgetting `top_k_per_label` when `min_recall=1.0`**: at that recall the chosen threshold sits at or below every NO_PASS score, so without `top_k_per_label` the container falls back to a "samples below threshold" filter that returns ONLY misclassified PASS rows and zero NO_PASS rows, breaking the augmentation queue. Always include an explicit positive `top_k_per_label` (default 50) in the spec or as a Hydra override.

See `references/pitfalls.md` for the complete checklist, covering: forgetting `top_k_per_label`; passing `--user`; calling with only Hydra overrides (no `-e <spec>`); spec file outside `$WORKSPACE`; spec file with unresolved `???` sentinels; image not pulled / wrong tag; path-mount mismatch; `unreachable_kpi.txt` written; `inference.csv` missing required columns; train YAML missing `dataset.classify.input_map` or `image_ext`; `kpi_media_path` not matching `input_path` prefixes; and no GPU detected from inside the container.

---

## Report Structure

Write `RCA_Report.md` as a tight (1000–1800 word) computational gap analysis — depth comes from accurate numbers and a clear action list, not narrative. The full report template (7 sections: Verdict, Threshold Selection, Weakness Distribution, Top-K Weakest Samples, Visual Spot Check, Per-Label Breakdown, Recommended Actions — with the confusion-matrix and table layouts) is in `references/output-template.md`. When `unreachable_kpi.txt` exists, replace sections 3–6 with a single short section quoting that file's contents and collapse section 7 to one recommendation: retrain or relabel.

---

## Execution Order

1. Resolve `DS_IMAGE` from `versions.yaml` (`images.tao_toolkit.data_services`), then run `docker info`, `nvidia-smi`, and `docker image inspect "$DS_IMAGE"` (pulling if missing) once to confirm the environment. Abort with a clear message if any fail.
2. Run `date +%Y-%m-%d_%H%M%S` to get the timestamp; create `<experiment_result_dir>/rca_results/<timestamp>/`.
3. Write `vcn_aoi_spec.yaml` into the timestamped dir with `min_recall` and `top_k_per_label` filled in. Keep it under `$WORKSPACE` so the `-e` path resolves inside the container.
4. Run `docker run … "$DS_IMAGE" gap_analysis vcn_aoi -e vcn_aoi_spec.yaml inference_results_dir=… train_config=… kpi_media_path=… output_dir=…`. The container writes `kpi_gaps.parquet`, `threshold.txt`, `metrics.json`, `weak_samples_breakdown.txt` into `results_dir`. Print the chosen threshold and kept-row counts to stdout so the script-check hook can verify the run produced output.
5. If `unreachable_kpi.txt` exists, skip Step 6 and write the abridged report. Otherwise continue.
6. Pick 10 weak samples (5 weakest PASS + 5 weakest NO_PASS) from `kpi_gaps.parquet`, view each test image with Read, classify, and copy each into `rca_images/`.
7. Write `RCA_Report.md` last — writing it triggers the packaging hook, which copies session logs and skill config alongside.

Todos los archivos

1 archivos

Instalar tao-analyze-gaps-visual-changenet

Descarga y descomprime los archivos de habilidades en tu directorio .claude/skills/.

Descargar ZIP

Clona el repositorio y copia los archivos de la habilidad a tu proyecto.

git clone https://github.com/NVIDIA/skills/tree/main/skills/tao-analyze-gaps-visual-changenet # Copy SKILL.md to your .claude/skills/ directory

Copiar Copiar
Configuración rápida: Copia la carpeta de la habilidad en .claude/skills/ Claude detectará y utilizará automáticamente la habilidad
Repositorio NVIDIA/skills

Habilidades relacionadas

web-search
Tiempo actualizado 29 de junio de 2026
webapp-testing
Tiempo actualizado 29 de junio de 2026
lark-base
Tiempo actualizado 5 de julio de 2026
agentmail
Tiempo actualizado 29 de junio de 2026
OR