Files
arm_dev 2b77ec127d P4:权重/标签模块 —— 旁挂标签文件 + PT→ONNX→TRT 转换工具 + 归档归位
痛点:TensorRT 10.13 的 Python API 没有元数据读写,engine 一转就把类名丢了;
推理侧只能退化成 str(cid)("0"、"1"),界面上看不出是什么类,属于静默失效。
同时旧的 export_yolo_trt.sh 只能手工搬文件、手工改 site.yaml、标签无处安放。

标签子系统(model_labels.py)
- 旁挂标签文件 <模型名>.labels.yaml,放在权重旁边,文本、可手改、进 git
  (二进制权重不进 git,标签是配置所以进)
- 读取优先级:旁挂文件 > ONNX 元数据 > 模型元数据 > 占位符 class_N
  占位符是故意的:缺标签时要一眼看出来,而不是悄悄退回 cid
- 解析器容忍多种写法:dict / list / 逗号串 / 逐行文本 / Python repr 串

布局与转换(weights_layout.py + weights.py + weights.sh)
- models/<分组>/<模型名>.{pt,onnx,engine} + 同名 .labels.yaml
- convert:PT→ONNX→TensorRT,支持自定义名字、自动归位、固化标签
- staging/:非标准格式先进这里,转换后源文件归档到 staging/done/
- list / labels / doctor / show 四个子命令
- doctor --check-engines 能查出 engine 与 TensorRT 版本不匹配(反序列化返回空)

推理侧接入
- yolo_detector / onnx_workpiece / hole_detect_hough 统一走 read_labels()
- 画框标签不再硬编码 "gongjian",改用实际类名

顺手修掉的真实问题
- setup.py 撞上断掉的符号链接会让整包构建失败,报错还指向 build/ 里的幽灵文件
  (源文件被挪走后 build/ 里留下的断链被 os.walk 列出来)。加 _existing() 过滤。
- P3 遗漏:site.yaml / export_site_env.py / run_handeye.sh / handeye_teach.py /
  handeye_calibrate.py 里的 handeye 工作目录仍是 /tmp/handeye_calib*,
  与已迁到 handeye/ 的其余路径不一致。统一到 handeye/tmp/<臂号>。
- site.yaml 的 hole_weights / hole_detect.weights 原指向不存在的 best.pt,
  改为实际存在的 detect_best_1.onnx;active.pt 符号链接已废弃并清理。
- weights.sh labels 原先不接受 "分组/模型名" 写法,而 list 输出正是这个形式,
  照着敲会报"找不到模型"。补上,并让报错直接给出可复制的全名。

测试:225 项通过(新增 test_model_labels.py / test_weights_layout.py)。
真实 ONNX→engine 端到端转换已验过。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 12:39:18 +08:00

70 lines
2.5 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 权重模块的统一入口(薄封装)。
#
# bash ~/ros2/scripts/weights.sh list
# bash ~/ros2/scripts/weights.sh labels detect_best_0
# bash ~/ros2/scripts/weights.sh labels detect_best_0 --set "工件,通止规"
# bash ~/ros2/scripts/weights.sh convert staging/best_v3.pt --name workpiece
# bash ~/ros2/scripts/weights.sh doctor --check-engines
#
# 本脚本只做三件事:准备环境(ROS + TensorRT 动态库)→ 挑一个能用的 python → 转发。
# 真正的逻辑在 scripts/weights.py。
#
# 完全等价的老命令 export_yolo_trt.sh 仍然可用(它是本脚本的转发壳)。
set -eo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# 用户显式指定解释器时优先用它;否则试 ros_flexiv。
# 本模块需要的重依赖(ultralytics / onnx / tensorrt / onnxruntime)都在那里。
pick_python() {
if [[ -n "${WEIGHTS_PY:-}" ]]; then
echo "${WEIGHTS_PY}"; return 0
fi
local cands=(
"${HOME}/anaconda3/envs/ros_flexiv/bin/python"
"$(command -v python3 || true)"
)
for c in "${cands[@]}"; do
[[ -n "${c}" && -x "${c}" ]] || continue
# list/labels/show 只需要 yaml;convert/doctor 才需要 tensorrt。
# 这里统一要求 yaml,避免半路才发现解释器不对。
if "${c}" -c 'import yaml' >/dev/null 2>&1; then
echo "${c}"; return 0
fi
done
return 1
}
PY="$(pick_python)" || {
echo "错误: 找不到可用的 python(需要能 import yaml)。" >&2
echo " 可用 WEIGHTS_PY=/path/to/python 指定。" >&2
exit 1
}
# TensorRT 的 pip 版把 .so 放在非标准位置,TensorRT 的 Python API 和运行时都要用。
# export_yolo_trt.sh 里也是这么做的;这里保持同样做法。
TRT_LIBS="$("${PY}" - <<'PY' 2>/dev/null || true
import pathlib
try:
import tensorrt
except Exception:
raise SystemExit(0)
p = pathlib.Path(tensorrt.__file__).resolve().parent
cands = [p, p.parent / "tensorrt_libs", p.parent / "nvidia" / "tensorrt" / "lib"]
print(":".join(str(x) for x in cands if x.exists()))
PY
)"
[[ -n "${TRT_LIBS}" ]] && export LD_LIBRARY_PATH="${TRT_LIBS}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
# 不让 Ultralytics 自己去 pip 装东西(会卡住或破坏环境)。
export YOLO_AUTOINSTALL=false
# site.yaml 里的 yolo.imgsz 作为 convert 的默认尺寸。
if [[ -f "${ROOT}/scripts/lib/load_site_config.sh" ]]; then
# shellcheck disable=SC1091
source "${ROOT}/scripts/lib/load_site_config.sh" >/dev/null 2>&1 || true
fi
exec "${PY}" "${ROOT}/scripts/weights.py" "$@"