关于 tao-mine-aoi-images
该技能将目标图像与候选源图像嵌入,再通过近邻搜索筛选相似图像,输出去重后的 Parquet 文件,供 VCN AOI 后续训练使用。迭代流程还可按历史记录排除已选样本。
主要功能
- 01为目标和源图像生成嵌入
- 02按近邻搜索相似源图像
- 03按标签过滤并去重结果
- 04迭代时排除历史已选样本
- 05输出 Parquet 与挖掘摘要
适用场景
- 01从候选池为目标图像寻找相似样本
- 02按标签限制图像匹配
- 03为迭代训练避免重复采样
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nvidia/ skills --skill tao-mine-aoi-images安装后在 Claude Code 中输入/tao-mine-aoi-images确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
BENCHMARK.mdskill-card.mdskill.oms.sigconfig/skillspector-baseline.yamlevals/evals.jsonhooks/_parse-stdin.shmining-artifacts-check.shmining-package.shmining-script-check.shmining-section-check.shreferences/outputs-and-reporting.mdreference-invocation.mdsetup.mdtroubleshooting.mdscripts/filter_mined_history.pytests/test_filter_mined_history.py详细介绍
DEFT 挖掘与嵌入技能
独立安装? 如果此会话并非由 TAO 技能库插件初始化,请先运行
tao-setup技能(主机预检、凭据、跨技能发现)。
你是 VCN AOI 的 DEFT 先嵌入后挖掘工作流的操作者。你的任务是获取一份弱目标图像的 parquet(差距分析或路由输出)和一个源池,然后生成一份去重后的挖掘源图像 parquet,其中的图像与目标相似,可供下一轮训练使用。迭代式 DEFT 调用方还会运行随附的历史感知后处理步骤,以避免再次选择先前迭代中已选取的样本。
该工作流固定且确定:嵌入目标图像,嵌入源池,挖掘最近邻,然后(对于迭代式工作流)移除先前挖掘出的样本。 每个 GPU 步骤的输出 parquet 都是下一步骤的输入;历史感知选择是主机端后处理步骤,不会再次执行 k-NN 搜索。工作流没有聚类环节或人工参与的选择步骤——挖掘深度取决于选择合适的编码器,以及设置足够大的 topn,以便历史过滤后仍有新候选项。
整个技能只是围绕固定版本的 TAO 数据服务镜像发起三次直接 docker run 调用,再加上一个可选的、随附的主机端 Python 后处理器,用于迭代历史处理(请参阅 versions.yaml,运行时会在 Setup 中解析)。容器的入口点接受 <category> <action> -e <spec.yaml> [hydra overrides...]——嵌入时传入 embedding image_embeddings -e <embedding_spec.yaml> …,挖掘时传入 tmm nearest_neighbors -e <mining_spec.yaml> …。-e 标志指向一个 YAML 文件,其中提供该子任务架构的默认值;其后的内容都是独立的 Hydra 覆盖项(key=value),用于按运行选择性地覆盖规范文件中的字段。(容器内没有 dataset 关键字——它是 TAO 启动器的 pillar 前缀,此处会将其省略。)如果镜像尚未缓存,请拉取一次:docker pull "$DS_IMAGE"(请先按照 Setup 解析 $DS_IMAGE)。
不同版本的数据服务可能会更改架构键名(RCA 技能遇到过 inference_csv → inference_results_dir、output_dir → results_dir 的更名)。不确定时,请针对每个镜像检查一次实际架构:docker run --rm "$DS_IMAGE" embedding image_embeddings --cfg=job 和 ... tmm nearest_neighbors --cfg=job。
输入
- 目标 parquet — 差异分析输出,通常是
tao-route-visual-changenet-samples生成的mining_gaps.parquet(如果跳过路由,则使用tao-analyze-gaps-visual-changenet生成的kpi_gaps.parquet)。必需的列:filepath。如果还包含label,挖掘时即可进行标签感知筛选;否则,挖掘任务会静默跳过筛选。 - 源池 — 用于挖掘的候选图像 parquet,包含
filepath列。如果用户只有 CSV,请在步骤 2 之前将其转换为包含相同列的 parquet。要进行标签感知筛选,源池还必须包含label列。 - 嵌入规范文件 — YAML 文件,包含
model、model_path、batch_size,并且(仅当model_path是 TAO.pth/.ckpt文件时)包含model_config_path。步骤 1 和步骤 2 共用此文件;每次运行的input_parquet/output_parquet通过 Hydra 覆盖项提供。两个嵌入步骤必须使用同一个规范文件——不同编码器生成的嵌入不可比较,而编码器不匹配是“挖出的图像看起来毫不相关”报告最常见的原因。 - 挖掘规范文件 — YAML 文件,包含
topn、knn_metric、filter_by_label,以及(很少更改的)source_embed_column_name/target_embed_column_name。运行时通过 Hydra 覆盖项提供source_parquet/target_parquet/output_parquet。SigLIP 和 CLIP 嵌入应使用knn_metric: cosine。当filter_by_label: true但任一嵌入 parquet 缺少label列时,容器会记录警告并继续执行,不进行筛选。 - 挖掘历史记录(仅限迭代工作流) — 运行级结果目录下的一个 JSON 台账,以及每次迭代对应的历史摘要。两个文件均由
scripts/filter_mined_history.py管理。它通过规范化后的filepath标识样本,验证所有先前输出的哈希,并拒绝存在迭代间隙或重复选择的情况。恢复运行时,切勿手动编辑或重建此台账。
设置
请使用下面固定版本的 TAO data-services URI,然后先确认 Docker、NVIDIA 容器工具包和 GPU 均已就绪,再执行其他操作。编码器前向传递和 cuML/cuDF k-NN 搜索都需要 GPU;没有 CUDA,两步都会失败。
# 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"
容器读取或写入的所有主机路径都必须进行绑定挂载。最可预测的做法是以内外路径完全相同的方式挂载工作区根目录,然后对三次调用复用同一个 $DOCKER 别名:
WORKSPACE=<absolute path that contains all parquets, outputs, and the source-pool images>
DOCKER="docker run --gpus all --rm --shm-size=8g -v $WORKSPACE:$WORKSPACE -w $WORKSPACE $DS_IMAGE"
不要传递 --user $(id -u):$(id -g) —— 这会在任何工作开始前、导入 transformers 时触发 getpwuid() KeyError。容器以 root 身份运行;之后再将输出文件的所有者改回主机 UID。
每次迭代编写一次这两个规范文件,并将其放在 $WORKSPACE 下,这样 -e 参数在挂载路径的内外两侧都能解析;每次运行的值不要放入规范文件,而应通过 Hydra 覆盖项传递。如果源池是 CSV,请预先将其转换为 parquet(保留 filepath,并在存在时保留 label)。默认的 embedding_spec.yaml 使用 model: SigLIP、model_path: google/siglip-base-patch16-224、batch_size: 64;默认的 mining_spec.yaml 使用 topn: 5、knn_metric: cosine、filter_by_label: "false"(需加引号——该架构会将其读取为字符串)。迭代式 DEFT 工作流沿用 topn: 5 默认值;若用户指定了明确的值,则应保留。只有当历史摘要显示狭窄邻域中已有选择占主导时,才增加该值。
完整的环境说明、TAO_SKILL_BANK_PATH 处理方法、路径挂载的原因、getpwuid 的 chown 解决方法、CSV 转 parquet 代码片段,以及规范文件的原样编写代码块,请参阅 references/setup.md。
方法
依次运行 3 条命令。每条命令输出的 parquet 都是下一条命令的输入。将它们作为普通 Bash 命令运行;Setup 中的 $DOCKER 别名会处理容器、GPU 和挂载。每次调用的格式都相同:先用 -e <spec> 指定内置默认值,再添加少量针对本次运行的 Hydra 覆盖项。
步骤 1 — 嵌入目标图像
$DOCKER embedding image_embeddings \
-e <embedding_spec.yaml> \
input_parquet=<target_parquet> \
output_parquet=<target_embeddings_parquet>
读取差距分析/路由输出,并写入一个 parquet,其中包含 filepath、embedding 以及从输入逐字保留的其他元数据列(例如 label、siamese_score、weakness)。将输出架构(pd.read_parquet(...).columns)打印到 stdout,以便脚本检查钩子确认嵌入列存在。
如果需要在某次运行中覆盖 model/model_path/batch_size,又不想编辑 spec,可将它们作为 Hydra 覆盖项追加(例如 model_path=...)。
步骤 2 — 嵌入源池
$DOCKER embedding image_embeddings \
-e <embedding_spec.yaml> \
input_parquet=<source_pool_parquet> \
output_parquet=<source_embeddings_parquet>
命令格式与步骤 1 相同,但应用于源池。使用与步骤 1 完全相同的 embedding_spec.yaml,且不要在此处以不同方式覆盖 model/model_path/batch_size——两个步骤的编码器配置不匹配会导致嵌入不可比较。
步骤 3 — 挖掘最近邻
$DOCKER tmm nearest_neighbors \
-e <mining_spec.yaml> \
source_parquet=<source_embeddings_parquet> \
target_parquet=<target_embeddings_parquet> \
output_parquet=<mined_parquet>
针对每个目标嵌入,根据所选度量找出距离最近的 topn 个源嵌入,跨目标去重,并写入仅包含一列(filepath)的 parquet,其中列出挖掘到的唯一源路径。对于单次运行,这可以是最终的 mined.parquet;对于 DEFT 迭代,请将其写为 mined_candidates.parquet,以便为步骤 4 保留不可变的候选集。容器还会在输出 parquet 旁生成 mining_summary.txt,其中包含:查询数、邻居数、移除的重复项,以及(启用标签过滤时)保留与丢弃的配对数。进行扫描时,可通过行内 Hydra 覆盖项调整 topn、knn_metric 或 filter_by_label——无需重写 spec。
当 filter_by_label=true 但其中一个嵌入 parquet 缺少 label 列时,容器会记录警告并继续运行,但不进行过滤。如果挖掘输出看起来比预期大,或包含跨标签配对,请先检查 docker 日志中是否有该警告,再判断任务是否正常执行。
请参阅 references/reference-invocation.md,其中提供了最简的复制并编辑式端到端操作方案(解析 $DS_IMAGE、写入两个 spec、运行全部三个步骤、chown 输出文件并打印行数),可将其作为单个流式 Bash 块运行。
步骤 4 — 考虑历史记录的筛选(仅限迭代式 DEFT)
在任何标签/相似度保留筛选之后运行,以确保输入代表实际符合训练条件的候选项:
python3 skills/data/tao-mine-aoi-images/scripts/filter_mined_history.py \
--candidate-parquet <mined_candidates.parquet> \
--output-parquet <mined.parquet> \
--history-file <run_results_dir>/mining_history.json \
--summary <iteration_dir>/mining_history_summary.json \
--iteration <N> \
--topn <topn>
输出会保留候选项的顺序和架构,但只包含此前已提交迭代中未选中的文件路径。账本会记录所选路径、候选项/输出哈希、计数和 topn;只有在验证这些制品后,--resume 才会复用已提交的迭代。零行输出表示当前 k-NN 候选集中没有新样本,这是有效结果。调用方需决定是否由其他生成器(例如 AnomalyGen)继续执行该迭代,或直接停止。当摘要报告的 historical_candidate_rate 较高时,请增大 topn 或扩展源池;如果每次迭代检索到的都是相同的低质量邻域,历史筛选无法凭空增加多样性。
输出和报告
将所有内容写入实验 / 迭代目录下带时间戳的文件夹。通过在 Bash 中运行 date +%Y-%m-%d_%H%M%S 获取实际时间戳——不要硬编码或猜测。如果用户指定了自定义输出路径,直接使用该路径,但保持相同的内部布局。写入 Mining_Report.md 时,打包钩子会自动添加 mining_config/ 和 claude_session.jsonl。
经过历史记录筛选的最终挖掘 parquet 是迭代式下游训练阶段使用的产物。请保留历史筛选前的候选 parquet、每次迭代的历史摘要,以及运行级别的 mining_history.json,并与两个嵌入 parquet 一起保存;这些文件有助于区分“k-NN 未找到任何内容”和“k-NN 返回的样本已在先前迭代中使用”。
完整的输出目录布局和 Mining_Report.md 原样模板(Verdict、Inputs、Encoder Consistency、Mining Run、Per-Label Breakdown、Output Sanity、Recommended Actions;保持 600–1200 词)请参见 references/outputs-and-reporting.md。
常见陷阱
最常见的失败是两个嵌入步骤使用的编码器不匹配——这是挖掘输出无效最常见的原因;两个步骤必须使用同一个 embedding_spec.yaml。其他常见陷阱包括:传入 --user(导致 getpwuid KeyError)、跳过嵌入步骤、缺少 label 列导致 filter_by_label=true 静默无操作、规格文件位于 $WORKSPACE 之外、未解决的 ??? 占位符、缺少 model_config_path 的 TAO 检查点、直接输入 CSV 源数据池、主机 / 容器路径不匹配、没有 GPU、尚未拉取的镜像或 :latest 镜像标签、topn × N_targets ≫ source size(这是预期情况——报告实际挖掘数量),以及 topn 过窄,导致历史筛选后无法得到任何新样本。
完整的陷阱列表及对应的确切错误、原因和修复方法,请参见 references/troubleshooting.md。
执行顺序
- 将
DS_IMAGE设为固定版本的数据服务 URI(参见 Setup),然后运行docker info、nvidia-smi和docker image inspect "$DS_IMAGE"(如果镜像不存在则先拉取)一次,以确认环境。任何一项失败时,都应输出清晰的消息并中止。 - 运行
date +%Y-%m-%d_%H%M%S获取时间戳;创建<output_dir>/mining_results/<timestamp>/。 - 在带时间戳的目录中写入
embedding_spec.yaml和mining_spec.yaml,填入编码器选择和挖掘参数。将这些文件放在$WORKSPACE下,以便-e路径能在容器内解析。 - 如果源数据池是 CSV,先将其转换为 parquet(保留
filepath和label)。 - 通过
docker run … embedding image_embeddings -e embedding_spec.yaml input_parquet=… output_parquet=…运行步骤 1(嵌入目标数据)。将输出 parquet 的行数和列名打印到标准输出。 - 使用与步骤 1 完全相同的
embedding_spec.yaml运行步骤 2(嵌入源数据池)。打印输出行数和列名。 - 通过
docker run … tmm nearest_neighbors -e mining_spec.yaml source_parquet=… target_parquet=… output_parquet=…运行步骤 3(挖掘最近邻)。确认mining_summary.txt已写入原始 / 候选 parquet 所在目录。 - 对于迭代式 DEFT 调用方,应用所有已配置的保留筛选器,然后使用当前迭代编号、记录的
topn、运行级别的账本路径和一个单独的最终mined.parquet运行步骤 4。切勿将原始候选 parquet 直接用于累积训练。 - 如果目标嵌入 parquet 和最终挖掘输出都包含
label,则通过 filepath 连接二者,计算按标签划分的明细(第 5 节)。 - 最后写入
Mining_Report.md——写入该文件会触发打包钩子,将会话日志和技能配置一并复制。