tao-analyze-gaps-visual-changenet
NVIDIA/skills
Identifica as amostras mais fracas por rótulo de referência nas experiências do NVIDIA TAO VCN Classify, executando um contêiner Docker que realiza varredura de limiares, pontuação de fragilidade e expansão por condição de iluminação; em seguida, apresenta as K principais amostras fracas para aumento de dados ou reclassificação em etapas posteriores.
...Expandir tudoAnálise de lacunas do TAO VCN Classify
Você é analista dos resultados de inferência do NVIDIA TAO VCN Classify (Visual Component Net). Sua função é identificar as amostras mais fracas por rótulo de referência, medindo a distância assinada do limiar de decisão na direção errada, para depois destacá-las para aumento ou reclassificação em etapas posteriores.
Esta habilidade é intencionalmente leve. O cabeçalho de classificação do VCN é um limite binário de pontuação única (PASS vs NO_PASS por siamese_score), portanto, a análise é computacional, não investigativa. Todo o cálculo ocorre por meio de uma única invocação direta do Docker contra a imagem `tao_toolkit.data_services ` declarada no arquivo ` versions.yaml ` (resolvida em tempo de execução — consulte Configuração). O ponto de entrada do contêiner aceita ` `; passamos ` gap_analysis vcn_aoi key=value …`. Cada substituição é um simples par chave=valor do Hydra que substitui seletivamente o esquema GapAnalysisConfig do script (os padrões estão embutidos no contêiner; verifique com docker run ... gap_analysis vcn_aoi --cfg=job). (Não há a palavra-chave dataset dentro do contêiner — esse é o prefixo “pillar” do lançador TAO e é omitido aqui.) Você não precisa de análise delegada, auditorias de imagem em múltiplas fases ou agrupamento por tipo de componente — o VCN não expõe essas dimensões. Visualize apenas um pequeno conjunto de amostras fracas representativas para qualificar as lacunas após o retorno do contêiner.
A interface da CLI pode variar entre as compilações de contêineres de serviços de dados. Se uma invocação de `gap_analysis vcn_aoi ` falhar na análise de argumentos, examine o esquema real uma vez por imagem com ` docker run --rm "$DS_IMAGE" gap_analysis vcn_aoi --cfg=job e reconcilie quaisquer chaves renomeadas (por exemplo, inference_csv vs. inference_results_dir, output_dir vs. results_dir) antes de tentar novamente. O nome do arquivo Parquet de saída é kpi_gaps.parquet.
Entradas
- Diretório de resultados do experimento — contém
o arquivo inference/inference.csvda inferência do TAO VCN Classify. Colunas obrigatórias:input_path,object_name,label,siamese_score. Passe o diretório (por exemplo,inference/latest/), e não o arquivo CSV — o contêiner lêo arquivoinference_results_dir/inference.csv. - Diretório de código/configuração de treinamento — contém o arquivo YAML de treinamento do VCN. O contêiner lê
dataset.classify.input_map(lista de condições de iluminação) edataset.classify.image_exta partir dele para expandir cada amostra fraca em uma linha por condição de iluminação. - Diretório do conjunto de dados — a raiz da imagem é anexada ao caminho relativo
input_pathde cada linha (kpi_media_path). - Substituições de esquema —
min_recall,top_k_per_labele, opcionalmente, umlimitefixo são passados como substituições do Hydra (padrões:min_recall=1,0,top_k_per_label=50,threshold=-1,0,o que significa varredura).top_k_per_labeldeve ser um número inteiro positivo — omitir esse parâmetro coloca o contêiner no modo “filtro abaixo do limiar”, o que, commin_recall=1,0,retorna apenas classificações errôneas do tipo PASS e zero linhas do tipo NO_PASS. Consulte Armadilhas comuns.
Configuração
A varredura de limiar, a classificação de vulnerabilidades e a expansão por iluminação são executadas dentro da imagem tao_toolkit.data_services declarada no arquivo versions.yaml. Resolva a URI específica uma vez no início da execução; em seguida, confirme se o Docker, o kit de ferramentas de contêineres da NVIDIA e uma GPU estão presentes e certifique-se de que a imagem esteja armazenada em cache:
# Resolver tao_toolkit.data_services → URI concreta nvcr.io/... a partir do arquivo 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 geralmente é exportado pelo banco de habilidades instalado. Se não estiver definido, aponte-o para a raiz do repositório do banco de habilidades antes da resolução. É necessária uma GPU; interromper o processo logo no início em um host sem GPU evita um erro confuso mais tarde.
Três regras de configuração são fundamentais e fáceis de errar:
- Montagem de caminho — todos os caminhos do host que o contêiner lê ou grava (
inference.csv, YAML de treinamento, raiz da imagem do conjunto de dados, diretório de saída) devem ser montados por bind, o que é mais simples com-v $WORKSPACE:$WORKSPACE -w $WORKSPACE, para que os caminhos absolutos sejam resolvidos de forma idêntica em ambos os lados. - Não passe
--user $(id -u):$(id -g)— isso acionao erro KeyError: 'getpwuid(): uid not found:durante a importação' dos transformadorespelo contêiner; em vez disso,o chownretorna o UID do host posteriormente. -eé obrigatório, não opcional — as imagens atuais exigem isso e encerram comValueError: A subtarefa vcn_aoi requer o seguinte argumento: -e/--experiment_spec_fileantes de analisar as substituições da CLI.
Consulte references/container-setup.md para obter o padrão completo de montagem de caminhos, a justificativa para--user/chown e o comando chown do Alpine, orientações sobre o uso de múltiplos --v e detalhes sobre a exigência de -e .
Método
Toda a tarefa consiste em uma única invocação do `docker run`, seguida por uma breve verificação visual pontual. O contêiner executa as etapas 1 a 4 internamente (varredura de limiares, pontuação de vulnerabilidades, seleção dos K principais, expansão por iluminação). Você realiza a etapa 5 (verificação visual pontual) diretamente com a ferramenta Read.
Etapas 1 a 4 — Execute o contêiner
$DOCKER gap_analysis vcn_aoi \
inference_results_dir=/inference/
Sempre passe
o parâmetro top_k_per_label. Esse é o argumento que muda o contêiner do filtro padrão “amostras abaixo do limite” para o ranking adequado top-K-per-label . Commin_recall=1.0, o limiar é, por definição, igual ou inferior a todas as pontuações NO_PASS; portanto, o filtro “abaixo do limiar” retorna APENAS linhas PASS classificadas incorretamente e zero linhas NO_PASS — o que é inútil como fila de aumento. Comtop_k_per_labeldefinido como um número inteiro positivo (seja na especificação ou como uma substituição do Hydra), o contêiner calcula a fraqueza assinada em relação ao limiar para cada linha e apresenta as K mais fracas por rótulo de verdade fundamental, que é a saída classificada por rótulo consumida pelas etapas posteriores.
Lê o arquivo inference.csv, varre todos os valores únicos de siamese_score mais um valor logo abaixo do mínimo, mantém os candidatos com recall da classe NO_PASS ≥ min_recall (com tolerância de 1e-12 ) e, em seguida, seleciona o limiar com o melhor F1 (desempate: precisão e, em seguida, valor do limiar). Para cada linha, calcula a fraqueza assinada a partir desse limiar (positiva = classificação incorreta, negativa = correta, magnitude = margem). Classifica por fraqueza em ordem decrescente e seleciona os top_k_per_label principais por rótulo de referência; em seguida, expande cada linha fraca em uma linha por condição de iluminação usando dataset.classify.input_map e dataset.classify.image_ext do YAML de treinamento.
Se nenhum limiar candidato atender à meta de recall, o contêiner sai com valor diferente de zero e grava o arquivo unreachable_kpi.txt no diretório results_dir, explicando qual recall o modelo pode realmente atingir. Nesse caso, interrompa a análise após a chamada do Docker, redija um relatório de uma seção explicando que o modelo é fundamentalmente incapaz de atingir o KPI em qualquer ponto de operação e recomende retreinamento ou reetiquetamento — pule a verificação visual aleatória.
O contêiner grava no diretório results_dir:
| Artefato | Conteúdo |
|---|---|
kpi_gaps.parquet |
Os Top-K mais fracos por rótulo, expandidos por iluminação. Colunas: filepath, label, siamese_score, weakness. |
threshold.txt |
Limite de decisão escolhido (único valor de tipo float, texto simples). |
metrics.json |
No limiar escolhido: precisão, recall, f1, matriz de confusão {tp, fp, tn, fn}, além de, por rótulo , {total, média_de_fraqueza, mediana_de_fraqueza, máxima_de_fraqueza, n_de_classificações_erradas}. |
weak_samples_breakdown.txt |
Discriminação das linhas mantidas por rótulo: total, <%> de todas as linhas mantidas, N classificadas incorretamente (fraqueza > 0), N marginais (fraqueza ≤ 0). |
unreachable_kpi.txt |
Somente gravado quando a meta de recall é inatingível. A presença deste arquivo significa: pular a Etapa 5, gerar o relatório resumido, recomendar retreinamento. |
Imprima o resumo da saída padrão do contêiner (limite escolhido, contagem de linhas mantidas, detalhamento por rótulo) na sua própria saída padrão para que o gancho de verificação do script possa verificar a saída gerada pela execução.
Etapa 5 — Verificação visual pontual (pequena, fixa)
Pule esta etapa se o arquivo unreachable_kpi.txt existir. Caso contrário, use a ferramenta Read para visualizar as 5 amostras PASS mais fracas e as 5 amostras NO_PASS mais fracas do arquivo kpi_gaps.parquet (deduplicadas para uma linha por amostra, usando o caminho de arquivo FIRST-lighting), classifique cada uma como exatamente uma das seguintes categorias: rotulagem incorreta / caso limite / qualidade dos dados / sistemática e copie cada imagem visualizada (redimensionada para 128×128 se o PIL estiver disponível; caso contrário, basta copiar) para Essa é a única inspeção de imagens necessária — não visualize dezenas de imagens, não execute agrupamento por modo de falha nem audite imagens de referência (o VCN não possui imagens de referência).
Consulte references/visual-spot-check.md para obter a ordem exata de seleção de amostras, a regra de deduplicação por iluminação, a definição completa de cada categoria de veredicto e os detalhes da cópia de imagens.
Chamada da referência
Cole e edite o espaço de trabalho, os quatro caminhos e os dois parâmetros numéricos; isso executa o processo de ponta a ponta. Capture a saída padrão (stdout) para que o gancho de verificação de script veja as contagens de linhas.
WORKSPACE= # montado de forma idêntica dentro do contêiner
EXP_DIR= # contém inference/inference.csv e train.yaml; deve estar dentro de $WORKSPACE
DATASET_ROOT= # raiz das imagens para as entradas do caminho de entrada do arquivo inference.csv; deve estar dentro de $WORKSPACE
MIN_RECALL=1.0 # padrão de zero erros; reduza se o KPI for menos rigoroso
TOP_K=50 # orçamento de aumento por rótulo
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"
# Grave a especificação da análise de lacunas para esta execução
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"
# O contêiner grava como root com a opção --user desativada; reatribua a propriedade ao UID do host, se necessário.
docker run --rm -v "$WORKSPACE:/w" alpine chown -R "$(id -u):$(id -g)" "/w/$(realpath --relative-to="$WORKSPACE" "$OUT")"
# Saída de verificação para que o hook de verificação de script veja valores reais
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 INACESSÍVEL — consulte", unreachable)
sys.exit(0)
with open(os.path.join(out, "threshold.txt")) as f:
print("limite:", 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
Saídas
Grave tudo em uma pasta com data e hora no diretório de resultados do experimento. As saídas do contêiner vão diretamente para lá; a verificação visual grava em rca_images/; qualquer gancho de empacotamento em tempo de execução pode adicionar artefatos de captura de sessão/configuração após o arquivo RCA_Report.md ser gravado.
/rca_results/AAAA-MM-DD_HHMMSS/
├── RCA_Report.md # Relatório completo de análise de lacunas (você o escreve)
├── kpi_gaps.parquet # Contêiner: os K mais fracos por rótulo, expandidos por iluminação
├── threshold.txt # Contêiner: limiar de decisão escolhido (único número real)
├── metrics.json # Contêiner: matriz de confusão + estatísticas de distribuição por rótulo
├── weak_samples_breakdown.txt # Contêiner: contagem por rótulo / amostras mal classificadas / contagens marginais
├── unreachable_kpi.txt # Contêiner: SOMENTE quando nenhum limiar atinge o min_recall
├── rca_images/ # Você: miniaturas das 10 amostras fracas visualizadas
├── rca_config/ # Copiado automaticamente pelo hook
└── session log/artifacts # Opcional, captura de pacotes dependente do tempo de execução
No início da execução, obtenha o carimbo de data/hora real executando ` date +%Y-%m-%d_%H%M%S ` no Bash. NÃO codifique manualmente nem adivinhe. Se o usuário especificar um caminho de saída personalizado, use-o, mas mantenha a mesma estrutura interna.
Armadilhas comuns
O modo de falha de maior consequência é esquecer o `top_k_per_label` quando` min_recall=1.0`: nessa taxa de recall, o limiar escolhido fica igual ou abaixo de todas as pontuações NO_PASS; portanto, sem top_k_per_label, o contêiner recorre a um filtro de “amostras abaixo do limiar” que retorna APENAS linhas PASS classificadas incorretamente e zero linhas NO_PASS, interrompendo a fila de aumento. Sempre inclua um top_k_per_label positivo explícito (padrão 50) na especificação ou como uma substituição do Hydra.
Consulte references/pitfalls.md para obter a lista de verificação completa, que abrange: esquecimento do `top_k_per_label`; passar o parâmetro `--user`; chamar apenas com substituições do Hydra (sem `-e ); arquivo de especificação fora do `$WORKSPACE`; arquivo de especificação com sentinelas `???` não resolvidas; imagem não baixada / tag incorreta; incompatibilidade de caminho de montagem; arquivo unreachable_kpi.txt gravado; arquivo inference.csv sem as colunas obrigatórias; YAML de treinamento sem dataset.classify.input_map ou image_ext; kpi_media_path não correspondendo aos prefixos de input_path; e nenhuma GPU detectada de dentro do contêiner.
Estrutura do Relatório
Escreva o arquivo RCA_Report.md como uma análise computacional concisa (1.000–1.800 palavras) das lacunas — a profundidade vem de números precisos e de uma lista clara de ações, não de narrativa. O modelo completo do relatório (7 seções: Veredicto, Seleção de Limiares, Distribuição de Pontos Fracos, Amostras Mais Fracas Top-K, Verificação Visual Pontual, Discriminação por Rótulo, Ações Recomendadas — com a matriz de confusão e os layouts das tabelas) está em references/output-template.md. Quando o arquivo unreachable_kpi.txt existir, substitua as seções 3 a 6 por uma única seção curta citando o conteúdo desse arquivo e resuma a seção 7 a uma única recomendação: retreinar ou reclassificar.
Ordem de execução
- Resolva
DS_IMAGEa partir doarquivo versions.yaml(images.tao_toolkit.data_services); em seguida, executedocker info,nvidia-smiedocker image inspect "$DS_IMAGE"(baixando a imagem caso esteja ausente) uma vez para confirmar o ambiente. Aborta com uma mensagem clara se houver alguma falha. - Execute `
date +%Y-%m-%d_%H%M%S` para obter o carimbo de data/hora; crie ``./rca_results/` e ` / - Grave o arquivo
`vcn_aoi_spec.yaml`no diretório com o carimbo de data/hora, preenchendo os campos `min_recall` e`top_k_per_label`. Mantenha-o no diretório`$WORKSPACE`para que o caminho`-e` seja resolvido dentro do contêiner. - Execute
docker run … "$DS_IMAGE" gap_analysis vcn_aoi -e vcn_aoi_spec.yaml inference_results_dir=… train_config=… kpi_media_path=… output_dir=….O contêiner gravaos arquivos kpi_gaps.parquet,threshold.txt,metrics.jsoneweak_samples_breakdown.txtnodiretório results_dir. Imprima o limiar escolhido e as contagens de linhas mantidas na saída padrão (stdout) para que o gancho de verificação do script possa conferir a saída gerada pela execução. - Se
o arquivo unreachable_kpi.txtexistir, pule a Etapa 6 e gere o relatório resumido. Caso contrário, continue. - Selecione 10 amostras fracas (as 5 mais fracas com PASS + as 5 mais fracas com NO_PASS) do
arquivo kpi_gaps.parquet, visualize cada imagem de teste com o comando Read, classifique-as e copie cada uma paraa pasta rca_images/. - Grave
o RCA_Report.mdpor último — gravá-lo aciona o gancho de empacotamento, que copia os logs da sessão e a configuração da habilidade junto com ele.
---
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 os arquivos
1 arquivosInstalar tao-analyze-gaps-visual-changenet
Baixe e extraia os arquivos de habilidades para o diretório .claude/skills/.
Baixar ZIPClone o repositório e copie os arquivos da habilidade para o seu projeto.
git clone https://github.com/NVIDIA/skills/tree/main/skills/tao-analyze-gaps-visual-changenet # Copy SKILL.md to your .claude/skills/ directory
Copiar





Lar
