feat(scripts): 重训后同时维护 current.pt 与 best.pt
current.pt 指向最新一次训练的结果(后端与 push_predictions 都读它), best.pt 指向历史上 mAP50 最高的那版,留作回退与对照。 数据集每次重训都在变,这个比较只是粗略参考而非严格的同条件对比,所以只用来 维护 best.pt 这个指针,不拦截 current.pt 的切换。 用服务器上三次真实训练验证过:首次建立、更好时更新、更差时保持不变。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fad1fe9fbb
commit
6e746b7351
@@ -83,9 +83,12 @@ Label Studio 里:Settings → **Model** → Connect Model,URL 填 `http://lo
|
||||
`ANNOTATION_CREATED`,`UPDATED` / `DELETED` 是对已有标注的修改,不该把阈值顶到;
|
||||
- 已有重训在跑时重复点击会被忽略,不会叠起多个训练。
|
||||
|
||||
重训脚本做四件事:导出标注 → `build_yolo_dataset.py` 装配 → `detect.py` 训练 →
|
||||
把 `runs/detect/current.pt` 软链接指向新权重并重启本服务。启动脚本默认读这个软链接,
|
||||
所以换模型不用改任何脚本。**权重只在进程启动时加载一次**,这也是重训末尾要重启服务的原因。
|
||||
重训脚本做五件事:导出标注 → `build_yolo_dataset.py` 装配 → `tile_dataset.py` 切成固定
|
||||
边长的片 → `detect.py` 训练 → 更新软链接并重启本服务。
|
||||
|
||||
两个软链接:**`current.pt`** 指向最新一次训练的结果(本服务与 `push_predictions.py` 都读它),
|
||||
**`best.pt`** 指向历史上 mAP50 最高的那版,留作回退与对照。换模型不用改任何脚本。
|
||||
**权重只在进程启动时加载一次**,这也是重训末尾要重启服务的原因。
|
||||
|
||||
训练进度看 `$RETRAIN_LOG`(默认 `/tmp/retrain.log`);Label Studio 网页端不显示训练进度。
|
||||
|
||||
|
||||
@@ -71,9 +71,31 @@ echo "--- 4/5 训练 -> $WORK_DIR"
|
||||
--set data.yaml="$TRAIN_DATA" $IMGSZ_SET $EXTRA_SET
|
||||
|
||||
echo "--- 5/5 切换权重"
|
||||
# 指向最新权重的稳定软链接:启动脚本与 push_predictions 都读它,换模型不用改任何脚本
|
||||
# 两个稳定软链接,换模型不用改任何脚本:
|
||||
# current.pt —— 最新一次训练的结果,后端与 push_predictions 都读它
|
||||
# best.pt —— 历史上 mAP50 最高的那版,留作回退与对照
|
||||
ln -sfn "$WORK_DIR/weights/best.pt" "$REPO/runs/detect/current.pt"
|
||||
|
||||
map50_of() { # $1 = 指向某次训练 weights/best.pt 的路径
|
||||
local metrics
|
||||
metrics="$(dirname "$(dirname "$1")")/metrics.json"
|
||||
[ -f "$metrics" ] || return 1
|
||||
"$PYTHON" -c "import json,sys; print(json.load(open(sys.argv[1]))[\"map50\"])" "$metrics"
|
||||
}
|
||||
|
||||
NEW_MAP=$(map50_of "$WORK_DIR/weights/best.pt" || echo "")
|
||||
OLD_BEST=$(readlink -f "$REPO/runs/detect/best.pt" 2>/dev/null || echo "")
|
||||
OLD_MAP=$([ -n "$OLD_BEST" ] && map50_of "$OLD_BEST" || echo "")
|
||||
|
||||
# 数据集每次重训都在变,这个比较只是粗略参考,不是严格的同条件对比
|
||||
if [ -z "$OLD_MAP" ] || [ -z "$NEW_MAP" ] || \
|
||||
awk "BEGIN{exit !($NEW_MAP >= $OLD_MAP)}"; then
|
||||
ln -sfn "$WORK_DIR/weights/best.pt" "$REPO/runs/detect/best.pt"
|
||||
echo " best.pt 更新为本次(mAP50 ${NEW_MAP:-未知},此前 ${OLD_MAP:-无})"
|
||||
else
|
||||
echo " best.pt 保持不变(本次 mAP50 $NEW_MAP < 此前 $OLD_MAP)"
|
||||
fi
|
||||
|
||||
if [ "$RESTART_BACKEND" = "1" ]; then
|
||||
echo "--- 重启 ML backend"
|
||||
# 必须显式传 YOLO_WEIGHTS 并清掉继承来的变量:本脚本可能是旧后端的子进程,
|
||||
@@ -90,6 +112,8 @@ fi
|
||||
|
||||
echo "===== [$(date '+%F %T')] 重训完成:$WORK_DIR ====="
|
||||
echo "指标见 $WORK_DIR/metrics.json,曲线见 $WORK_DIR/results.png"
|
||||
echo "current.pt -> $(readlink "$REPO/runs/detect/current.pt")"
|
||||
echo "best.pt -> $(readlink "$REPO/runs/detect/best.pt")"
|
||||
if [ "$TILE_SIZE" -gt 0 ]; then
|
||||
echo "推理请用同样的尺寸:--tile-size $TILE_SIZE --tile-overlap $TILE_OVERLAP"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user