关于 tao-analyze-gaps-visual-changenet
分析 NVIDIA TAO VCN Classify 推理结果、找出各真实标签下薄弱样本的 TAO skill。它按样本相对决策阈值的有符号距离排序,并按光照条件展开结果,供数据增强或重标注审查。
主要功能
- 01扫描分数以选择决策阈值
- 02按真实标签排列薄弱样本
- 03按光照条件展开样本
- 04生成差距分析产物与报告
- 05抽查有代表性的薄弱图像
适用场景
- 01寻找适合数据增强的薄弱样本
- 02审查待重标注的候选图像
- 03检查召回率目标是否可达
MCP 相关
此 skill 在 Docker 容器中使用 TAO data-services 分析 VCN 推理结果。它读取推理 CSV,并生成供后续工作流使用的差距分析结果。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nvidia/ skills --skill tao-analyze-gaps-visual-changenet安装后在 Claude Code 中输入/tao-analyze-gaps-visual-changenet确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BENCHMARK.mdskill-card.mdskill.oms.sigconfig/skillspector-baseline.yamlevals/evals.jsonhooks/_parse-stdin.shrca-artifacts-check.shrca-label-coverage.shrca-package.shrca-script-check.shrca-section-check.shreferences/container-setup.mdoutput-template.mdpitfalls.mdvisual-spot-check.mdtests/test_rca_artifacts_hook.py详细介绍
TAO VCN Classify Gap Analysis Skill
独立安装? 如果此会话并非由 TAO skill bank 插件初始化,请先运行
tao-setup技能(主机预检、凭据、跨技能发现)。
你是 NVIDIA TAO VCN Classify(Visual Component Net)推理结果分析师。你的任务是通过测量样本在错误方向上偏离决策阈值的有符号距离,找出每个真实标签下最弱的样本,然后将它们提交给下游流程,用于数据增强或重新标注。
此技能刻意保持轻量。VCN 的分类头是单分数二元边界(通过 siamese_score 区分 PASS 与 NO_PASS),因此该分析是计算型的,而非调查型的。所有计算都通过一次直接的 docker run 调用完成,使用固定版本的 TAO data-services 镜像(见 Setup)。容器的入口点接受 <category> <action> [hydra overrides...];我们传入 gap_analysis vcn_aoi key=value …。每个覆盖项都是一个裸 Hydra key=value,用于有选择地覆盖脚本的 GapAnalysisConfig schema(默认值已内置于容器中;请使用下方挂载最简配置的 --cfg=job 配方查看默认值)。(容器内没有 dataset 关键字——它是 TAO 启动器的 pillar 前缀,在此处会被移除。)你不需要委派分析、多阶段图像审查或组件类型聚类——VCN 不提供这些维度。容器运行完成后,只需查看少量有代表性的弱样本,以评估这些差距。
不同 data-services 容器版本的 CLI 参数可能有所变化。如果 gap_analysis vcn_aoi 调用因参数解析失败,请在每个镜像上使用挂载到主机路径的最简配置查看实际 schema:
SPEC_DIR="$(mktemp -d)"
printf '%s\n' 'min_recall: 0.99' 'top_k_per_label: 5' > "$SPEC_DIR/vcn_aoi_spec.yaml"
docker run --rm -v "$SPEC_DIR:/w:ro" "$DS_IMAGE" gap_analysis vcn_aoi \
-e /w/vcn_aoi_spec.yaml --cfg=job
-e 路径必须能在容器内解析,因此配置文件必须位于挂载到 /w 的目录下。重试前,请核对并更新重命名的键(例如 inference_csv 与 inference_results_dir、output_dir 与 results_dir)。输出 parquet 文件名为 kpi_gaps.parquet。
输入
- 实验结果目录 — 包含 TAO VCN Classify 推理生成的
inference/inference.csv。必需列:input_path、object_name、label、siamese_score。传入目录(例如inference/latest/),而不是 CSV 文件——容器会读取inference_results_dir/inference.csv。 - 训练代码/配置目录 — 包含 VCN 训练 YAML。容器会从中读取
dataset.classify.input_map(光照条件列表)和dataset.classify.image_ext,以便将每个弱样本扩展为每种光照条件对应的一行。 - 数据集目录 — 图像根目录,会添加到每行相对
input_path前面(kpi_media_path)。 - Schema 覆盖项 —
min_recall、top_k_per_label,以及可选的固定threshold,均以 Hydra 覆盖项形式传入(默认值:min_recall=1.0、top_k_per_label=50、threshold=-1.0,表示进行扫描)。top_k_per_label必须是正整数——省略该项会使容器切换到“阈值以下筛选”模式;当min_recall=1.0时,该模式只会返回 PASS 误分类样本,不会返回 NO_PASS 行。请参阅 Common pitfalls。
设置
阈值扫描、弱项排序和按光照条件展开都在下方固定版本的 TAO 数据服务镜像中运行。确认 Docker、NVIDIA 容器工具包和 GPU 均已就绪,并确保镜像已缓存:
# Resolve the pinned TAO data-services container URI from the release manifest.
DS_IMAGE="$(scripts/resolve_versions_key.py 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"
必须有 GPU;在没有 GPU 的主机上尽早中止,可避免稍后出现令人困惑的错误。
有三项关键设置规则很容易弄错:
- 路径挂载 — 容器读取或写入的每个主机路径(
inference.csv、训练 YAML、数据集图像根目录、输出目录)都必须进行绑定挂载。最简单的方式是使用-v $WORKSPACE:$WORKSPACE -w $WORKSPACE,这样两侧的绝对路径就能保持一致。 - 不要传入
--user $(id -u):$(id -g)— 这会在容器导入transformers时触发KeyError: 'getpwuid(): uid not found: <uid>';应改为之后将输出文件chown回主机 UID。 - 必须提供
-e <spec>,不能省略 — 当前镜像强制要求此参数,并会在解析 CLI 覆盖项之前退出,报错ValueError: The subtask vcn_aoi requires the following argument: -e/--experiment_spec_file。
完整的路径挂载模式、--user/chown 的原因和 alpine chown 命令、多项 -v 的使用说明,以及 -e <spec> 要求的详情,请参阅 references/container-setup.md。
方法
整个技能只需调用一次 docker run,然后进行简短的目视抽查。容器会在内部完成步骤 1–4(阈值扫描、弱项评分、Top-K 选择、按光照条件展开)。你直接使用 Read 工具完成步骤 5(目视抽查)。
步骤 1–4 — 运行容器
$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
始终传入
top_k_per_label。 此参数会将容器从默认的“低于阈值的样本”筛选模式切换为正确的按标签 Top-K 排序模式。在min_recall=1.0时,阈值按定义不高于每个 NO_PASS 分数,因此低于阈值筛选只会返回误分类的 PASS 行,而不会返回任何 NO_PASS 行——这对扩充队列毫无用处。将top_k_per_label设为正整数(在规范中设置或通过 Hydra 覆盖均可)后,容器会计算每一行相对于阈值的带符号弱点,并按每个真实标签显示 K 个最弱样本,供下游步骤使用按标签排序的输出。
读取 inference.csv,遍历每个唯一的 siamese_score 以及一个略低于最小值的值,保留 NO_PASS 类召回率 ≥ min_recall(容差为 1e-12)的候选项,然后选择 F1 最佳的阈值(平局时依次按精确率、阈值取值决胜)。针对每一行,计算相对于该阈值的带符号弱点(正值 = 误分类,负值 = 分类正确,绝对值 = 间隔)。按弱点降序排序,并为每个真实标签取前 top_k_per_label 行,然后使用训练 YAML 中的 dataset.classify.input_map 和 dataset.classify.image_ext,将每个弱样本扩展为每种光照条件一行。
如果没有候选阈值满足召回率目标,容器将以非零状态退出,并在 results_dir 中写入 unreachable_kpi.txt,说明模型实际能达到的召回率。在这种情况下,Docker 调用后立即停止分析,撰写一节报告,说明模型在任何工作点都无法达到 KPI,并建议重新训练或重新标注——跳过视觉抽查。
TAO 7.2 工件约定:
容器生成的必需工件:
| 工件 | 内容 |
|---|---|
kpi_gaps.parquet | 按标签取 Top-K 个最弱样本,并按光照条件扩展。列:filepath、label、siamese_score、weakness。 |
threshold.txt | 选定的决策阈值(单个浮点数,纯文本)。 |
weak_samples_breakdown.txt | 按标签统计保留行:总数 <count>、占所有保留行的比例 <%>、误分类数量 N(weakness > 0)、边缘样本数量 N(weakness ≤ 0)。 |
容器返回后,必须生成包含七个必需部分的 RCA_Report.md。若运行成功且 KPI 可达,还必须在视觉抽查期间生成 rca_images/。容器不会生成这两种由 Agent 负责的工件。
当召回率目标不可达时,容器会写入故障工件 unreachable_kpi.txt。该文件存在意味着:跳过步骤 5,撰写精简报告,并建议重新训练。TAO 7.2 vcn_aoi 操作不会生成 metrics.json;该文件不属于 7.2 约定。请根据完整的 inference.csv 和 threshold.txt 中选定的值计算报告指标。
将容器的 stdout 摘要(选定的阈值、保留行数、按标签的细分统计)打印到你自己的 stdout,以便脚本检查钩子验证运行确实产生了输出。
步骤 5 — 视觉抽查(小规模、固定数量)
如果 unreachable_kpi.txt 存在,则跳过此步骤。否则,使用 Read 工具查看 kpi_gaps.parquet 中最弱的 5 个 PASS 样本和最弱的 5 个 NO_PASS 样本(去重为每个样本一行,使用第一个光照条件下的 filepath),将每个样本准确归类为以下类别之一:错误标注 / 边缘案例 / 数据质量问题 / 系统性问题,并将每张查看过的图像复制(如果有 PIL,则调整为 128×128,否则直接复制)到 <results_dir>/rca_images/。这是唯一需要进行的图像检查——不要查看几十张图像、执行故障模式聚类或审核黄金样本(VCN 没有黄金图像)。
有关确切的样本选择排序、按光照条件去重规则、每种判定类别的完整定义以及图像复制细节,请参阅 references/visual-spot-check.md。
参考调用
粘贴并编辑工作区、四个路径和两个数值参数;这样即可端到端运行。捕获 stdout,以便脚本检查钩子能看到行数。
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="$(scripts/resolve_versions_key.py 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 --shm-size=8g \
-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. Report metrics are
# derived from inference.csv because metrics.json is not part of the 7.2 contract.
python3 - "$OUT" "$EXP_DIR/inference/latest/inference.csv" << 'PYEOF'
import os, sys
import pandas as pd
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:
threshold = float(f.read().strip())
inference = pd.read_csv(sys.argv[2])
actual_no_pass = inference["label"].eq("NO_PASS")
predicted_no_pass = inference["siamese_score"].ge(threshold)
tp = int((actual_no_pass & predicted_no_pass).sum())
fp = int((~actual_no_pass & predicted_no_pass).sum())
tn = int((~actual_no_pass & ~predicted_no_pass).sum())
fn = int((actual_no_pass & ~predicted_no_pass).sum())
precision = tp / (tp + fp) if tp + fp else 0.0
recall = tp / (tp + fn) if tp + fn else 0.0
f1 = 2 * precision * recall / (precision + recall) if precision + recall else 0.0
print(f"threshold={threshold} precision={precision:.4f} recall={recall:.4f} f1={f1:.4f}")
print(f"confusion_matrix: tp={tp} fp={fp} tn={tn} fn={fn}")
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
输出
将所有内容写入实验结果目录下带时间戳的文件夹。容器要求的输出会直接写入该文件夹;你需要写入 RCA_Report.md,如果 KPI 可达,还要写入 rca_images/。运行时打包钩子添加的任何会话/配置文件都是可选附加项,不属于 TAO 7.2 差距分析产物规范。
<experiment_result_dir>/rca_results/YYYY-MM-DD_HHMMSS/
├── kpi_gaps.parquet # Container: top-K weakest per label, expanded per lighting
├── threshold.txt # Container: chosen decision threshold (single float)
├── weak_samples_breakdown.txt # Container: per-label count/misclassified/marginal counts
├── RCA_Report.md # You: required seven-section gap analysis report
├── rca_images/ # You: required on reachable runs; spot-check thumbnails
├── unreachable_kpi.txt # Container: ONLY when no threshold meets min_recall
└── <optional packaging extras> # Runtime-dependent; outside the 7.2 contract
运行开始时,在 Bash 中运行 date +%Y-%m-%d_%H%M%S 获取真实时间戳。不要硬编码或猜测。如果用户指定了自定义输出路径,则使用该路径,但保持相同的内部结构。
常见陷阱
影响最大的单一故障模式是:当 min_recall=1.0 时忘记设置 top_k_per_label:此时选定的阈值低于或等于每个 NO_PASS 分数,因此如果没有 top_k_per_label,容器会回退到“阈值以下样本”筛选器,该筛选器只会返回分类错误的 PASS 行,不会返回任何 NO_PASS 行,从而破坏增强队列。请务必在规范文件或 Hydra 覆盖项中显式设置一个正数 top_k_per_label(默认值为 50)。
完整检查清单见 references/pitfalls.md,内容包括:忘记设置 top_k_per_label;传入 --user;只使用 Hydra 覆盖项调用(没有 -e <spec>);规范文件位于 $WORKSPACE 之外;规范文件中有尚未解析的 ??? 占位符;镜像未拉取/标签错误;路径挂载不匹配;已写入 unreachable_kpi.txt;inference.csv 缺少必需列;训练 YAML 缺少 dataset.classify.input_map 或 image_ext;kpi_media_path 与 input_path 前缀不匹配;以及容器内部检测不到 GPU。
报告结构
将 RCA_Report.md 写成一份精炼的计算型差距分析(1000–1800 字)——深度来自准确的数据和清晰的行动清单,而不是叙述。完整的报告模板(7 个部分:结论、阈值选择、弱点分布、Top-K 最弱样本、视觉抽查、按标签拆分、建议行动——含混淆矩阵和表格布局)见 references/output-template.md。如果存在 unreachable_kpi.txt,则用一个简短部分引用该文件内容来替换第 3–6 部分,并将第 7 部分缩减为一条建议:重新训练或重新标注。
执行顺序
- 将
DS_IMAGE设置为固定版本的数据服务 URI(见 Setup),然后运行docker info、nvidia-smi和docker image inspect "$DS_IMAGE"(如果镜像不存在则拉取),以确认环境。若任何一项失败,则输出清晰的消息并中止。 - 运行
date +%Y-%m-%d_%H%M%S获取时间戳;创建<experiment_result_dir>/rca_results/<timestamp>/。 - 在带时间戳的目录中写入
vcn_aoi_spec.yaml,并填入min_recall和top_k_per_label。将它放在$WORKSPACE下,以便容器内的-e路径能够解析。 - 运行
docker run … "$DS_IMAGE" gap_analysis vcn_aoi -e vcn_aoi_spec.yaml inference_results_dir=… train_config=… kpi_media_path=… output_dir=…。容器会将kpi_gaps.parquet、threshold.txt和weak_samples_breakdown.txt写入results_dir。将选定阈值和保留行数打印到 stdout,以便脚本检查钩子验证本次运行已产生输出。 - 如果存在
unreachable_kpi.txt,则跳过第 6 步并撰写精简报告。否则继续。 - 从
kpi_gaps.parquet中挑选 10 个弱样本(5 个最弱的 PASS + 5 个最弱的 NO_PASS),使用 Read 查看每张测试图像、进行分类,并将每张图像复制到rca_images/。 - 最后撰写
RCA_Report.md——撰写该文件会触发打包钩子,将会话日志和技能配置一并复制。