文章目录进入yolo环境现有资源如何使用这些.pt文件验证小模型对数据集的分割效果——predict验证小模型对数据集的分割效果——val现有资源前期工作开始验证结果分析先算四种像素统计量异常数据进入yolo环境source~/yolov8_env/bin/activate现有资源同事训练的小模型同事提供的数据集ubuntu20.04搭建yolo运行环境best.pt epoch10.pt epoch20.pt epoch30.pt epoch40.pt epoch5.pt epoch0.pt epoch15.pt epoch25.pt epoch35.pt epoch45.pt last.ptbest.pt 是什么表示在整个训练过程中在验证集上表现最好的那个模型。通常 Ultralytics 会根据验证指标来判断“最好”对分割任务一般重点看验证集上的综合指标比如 mAP。所以它不一定是最后一次训练得到的但通常是最推荐拿来推理 / 验证 / 部署的last.pt 是什么表示训练结束时最后一个 epoch 的模型。也就是说无论最后效果是不是最好训练停下来的那一刻保存的就是 last.pt。它适合继续训练resume看最终训练停在哪个状态和 best.pt 做比较epoch0.pt / epoch5.pt / epoch10.pt … 是什么这些就是训练过程中某些特定 epoch 的检查点checkpoint。比如epoch0.pt第 0 轮训练后保存epoch5.pt第 5 轮后保存epoch10.pt第 10 轮后保存…epoch45.pt第 45 轮后保存如何使用这些.pt文件看效果 / 做推理优先用 best.pt 怀疑后期过拟合想对比拿best.pt、last.pt、epoch20.pt、epoch45.pt 分别试想继续训练一般用 last.pt 或某个epochXX.ptyolo tasksegment modeval \验证小模型对数据集的分割效果——predict【得到每张图片的分割效果图】yolotasksegmentmodepredict\model/home/xxx/AI/segment/train/weights/best.pt\source/home/xxx/AI/dataset\saveTrue观察以下文件夹里的图像的分割是否合理/home/xxx/AI/dataset/runs验证小模型对数据集的分割效果——val现有资源同事的数据集和对应的只有二值的png图片bianjie1_1.png 和 ./label/bianjie1_1.png经过验证 ./label/bianjie1_1.png是二值mask图片只有0和1其中1代表grass前期工作需要数据集配置文件 xxx.yaml文件配置yaml文件中的# Classes 和 path 和 train:需要已经手动标定的mask和被验证的数据集因为mask不是标准的yolo格式所以需要自己写代码进行验证开始验证frompathlibimportPathimportnumpyasnpfromPILimportImagefromultralyticsimportYOLO# # Config# MODEL_PATH/home/xxx/AI/segment/train/weights/best.ptIMAGE_DIRPath(/home/xxx/AI/dataset/bianjie1)LABEL_DIRIMAGE_DIR/labelIMAGE_SUFFIX.png# According to your model names:# 0: grassGRASS_CLASS_ID0# Prediction confidence thresholdCONF_THRES0.25# # Helpers# defload_gt_mask(label_path:Path)-np.ndarray: Ground truth: 1 grass 0 non-grass Returns boolean mask of shape (H, W), True for grass. gtnp.array(Image.open(label_path))ifgt.ndim!2:raiseValueError(fGT mask is not single-channel:{label_path})returngt1defresize_bool_mask(mask:np.ndarray,target_hw:tuple[int,int])-np.ndarray: Resize boolean mask to target size using nearest-neighbor. target_hw (H, W) h,wtarget_hw imgImage.fromarray(mask.astype(np.uint8)*255)imgimg.resize((w,h),Image.NEAREST)arrnp.array(img)returnarr0defbuild_pred_grass_mask(result,target_hw:tuple[int,int])-np.ndarray: From one Ultralytics result, merge all predicted masks with class GRASS_CLASS_ID into one binary mask. Returns boolean mask of shape target_hw. h,wtarget_hw pred_masknp.zeros((h,w),dtypebool)ifresult.masksisNoneorresult.boxesisNone:returnpred_mask cls_arrresult.boxes.cls.cpu().numpy().astype(int)conf_arrresult.boxes.conf.cpu().numpy()masks_arrresult.masks.data.cpu().numpy()# shape: [N, Hm, Wm]fori,(cls_id,conf)inenumerate(zip(cls_arr,conf_arr)):ifcls_id!GRASS_CLASS_ID:continueifconfCONF_THRES:continuemmasks_arr[i]0.5ifm.shape!(h,w):mresize_bool_mask(m,(h,w))pred_mask|mreturnpred_maskdefcalc_metrics(pred:np.ndarray,gt:np.ndarray)-dict: pred, gt are boolean masks of same shape tpnp.logical_and(pred,gt).sum()fpnp.logical_and(pred,~gt).sum()fnnp.logical_and(~pred,gt).sum()tnnp.logical_and(~pred,~gt).sum()precisiontp/(tpfp)if(tpfp)0else0.0recalltp/(tpfn)if(tpfn)0else0.0ioutp/(tpfpfn)if(tpfpfn)0else0.0f12*precision*recall/(precisionrecall)if(precisionrecall)0else0.0return{tp:int(tp),fp:int(fp),fn:int(fn),tn:int(tn),precision:float(precision),recall:float(recall),iou:float(iou),f1:float(f1),}# # Main# defmain():modelYOLO(MODEL_PATH)image_pathssorted([pforpinIMAGE_DIR.glob(f*{IMAGE_SUFFIX})ifp.is_file()])ifnotimage_paths:raiseFileNotFoundError(fNo images found in{IMAGE_DIR})total_tptotal_fptotal_fntotal_tn0per_image_metrics[]print(fFound{len(image_paths)}images.)print(fUsing model:{MODEL_PATH})print(fEvaluating grass class id {GRASS_CLASS_ID})print(-*80)foridx,img_pathinenumerate(image_paths,start1):label_pathLABEL_DIR/img_path.nameifnotlabel_path.exists():print(f[WARN] Missing label for{img_path.name}, skip.)continue# Load GTgt_maskload_gt_mask(label_path)h,wgt_mask.shape# Predict one imageresultsmodel.predict(sourcestr(img_path),tasksegment,confCONF_THRES,verboseFalse,saveFalse)resultresults[0]pred_maskbuild_pred_grass_mask(result,(h,w))mcalc_metrics(pred_mask,gt_mask)total_tpm[tp]total_fpm[fp]total_fnm[fn]total_tnm[tn]per_image_metrics.append(m)print(f[{idx:03d}/{len(image_paths)}]{img_path.name}| fIoU{m[iou]:.4f}, P{m[precision]:.4f}, fR{m[recall]:.4f}, F1{m[f1]:.4f})print(-*80)# Global metrics from total pixelsglobal_precisiontotal_tp/(total_tptotal_fp)if(total_tptotal_fp)0else0.0global_recalltotal_tp/(total_tptotal_fn)if(total_tptotal_fn)0else0.0global_ioutotal_tp/(total_tptotal_fptotal_fn)if(total_tptotal_fptotal_fn)0else0.0global_f1(2*global_precision*global_recall/(global_precisionglobal_recall)if(global_precisionglobal_recall)0else0.0)# Mean per-image metricsifper_image_metrics:mean_iounp.mean([x[iou]forxinper_image_metrics])mean_precisionnp.mean([x[precision]forxinper_image_metrics])mean_recallnp.mean([x[recall]forxinper_image_metrics])mean_f1np.mean([x[f1]forxinper_image_metrics])else:mean_ioumean_precisionmean_recallmean_f10.0print(Global pixel-level metrics:)print(f IoU :{global_iou:.6f})print(f Precision:{global_precision:.6f})print(f Recall :{global_recall:.6f})print(f F1 :{global_f1:.6f})print(\nMean per-image metrics:)print(f IoU :{mean_iou:.6f})print(f Precision:{mean_precision:.6f})print(f Recall :{mean_recall:.6f})print(f F1 :{mean_f1:.6f})print(\nConfusion totals:)print(f TP:{total_tp})print(f FP:{total_fp})print(f FN:{total_fn})print(f TN:{total_tn})if__name____main__:main()验证结果[001/293] bianjie1_1.png | IoU0.9418, P0.9950, R0.9462, F10.9700[002/293] bianjie1_10.png | IoU0.9825, P0.9977, R0.9847, F10.9912[003/293] bianjie1_100.png | IoU0.9597, P0.9735, R0.9854, F10.9794[004/293] bianjie1_101.png | IoU0.9663, P0.9958, R0.9703, F10.9829[005/293] bianjie1_102.png | IoU0.9739, P0.9952, R0.9786, F10.9868[006/293] bianjie1_103.png | IoU0.9765, P0.9879, R0.9883, F10.9881[007/293] bianjie1_104.png | IoU0.0000, P0.0000, R0.0000, F10.0000[008/293] bianjie1_105.png | IoU0.0000, P0.0000, R0.0000, F10.0000[009/293] bianjie1_106.png | IoU0.9671, P0.9964, R0.9705, F10.9833[010/293] bianjie1_107.png | IoU0.9510, P0.9717, R0.9781, F10.9749[011/293] bianjie1_108.png | IoU0.9736, P0.9927, R0.9807, F10.9866[012/293] bianjie1_109.png | IoU0.9758, P0.9952, R0.9804, F10.9878[013/293] bianjie1_11.png | IoU0.9739, P0.9908, R0.9828, F10.9868[014/293] bianjie1_110.png | IoU0.9639, P0.9987, R0.9650, F10.9816[015/293] bianjie1_111.png | IoU0.9778, P0.9934, R0.9842, F10.9888[016/293] bianjie1_112.png | IoU0.9739, P0.9866, R0.9870, F10.9868[017/293] bianjie1_113.png | IoU0.9653, P0.9977, R0.9675, F10.9823[018/293] bianjie1_114.png | IoU0.9302, P0.9880, R0.9408, F10.9638[019/293] bianjie1_115.png | IoU0.9703, P0.9941, R0.9760, F10.9849[020/293] bianjie1_116.png | IoU0.9699, P0.9834, R0.9860, F10.9847[021/293] bianjie1_117.png | IoU0.9652, P0.9913, R0.9735, F10.9823[022/293] bianjie1_118.png | IoU0.0000, P0.0000, R0.0000, F10.0000[023/293] bianjie1_119.png | IoU0.9754, P0.9989, R0.9765, F10.9876[024/293] bianjie1_12.png | IoU0.9714, P0.9869, R0.9841, F10.9855[025/293] bianjie1_120.png | IoU0.9494, P0.9801, R0.9680, F10.9740[026/293] bianjie1_121.png | IoU0.0000, P0.0000, R0.0000, F10.0000[027/293] bianjie1_122.png | IoU0.9655, P0.9973, R0.9681, F10.9825[028/293] bianjie1_123.png | IoU0.9679, P0.9801, R0.9873, F10.9837[029/293] bianjie1_124.png | IoU0.9737, P0.9959, R0.9776, F10.9867[030/293] bianjie1_125.png | IoU0.9533, P0.9978, R0.9553, F10.9761[031/293] bianjie1_126.png | IoU0.9562, P0.9882, R0.9673, F10.9776[032/293] bianjie1_127.png | IoU0.9598, P0.9739, R0.9851, F10.9795[033/293] bianjie1_128.png | IoU0.9472, P0.9923, R0.9542, F10.9729[034/293] bianjie1_129.png | IoU0.9744, P0.9973, R0.9770, F10.9870[035/293] bianjie1_13.png | IoU0.9716, P0.9990, R0.9725, F10.9856[036/293] bianjie1_130.png | IoU0.9639, P0.9772, R0.9860, F10.9816[037/293] bianjie1_131.png | IoU0.9761, P0.9978, R0.9782, F10.9879[038/293] bianjie1_132.png | IoU0.0000, P0.0000, R0.0000, F10.0000[039/293] bianjie1_133.png | IoU0.9491, P0.9628, R0.9852, F10.9739[040/293] bianjie1_134.png | IoU0.9550, P0.9987, R0.9562, F10.9770[041/293] bianjie1_135.png | IoU0.9732, P0.9941, R0.9788, F10.9864[042/293] bianjie1_136.png | IoU0.9482, P0.9990, R0.9491, F10.9734[043/293] bianjie1_137.png | IoU0.0000, P0.0000, R0.0000, F10.0000[044/293] bianjie1_138.png | IoU0.9606, P0.9996, R0.9610, F10.9799[045/293] bianjie1_139.png | IoU0.9667, P0.9985, R0.9681, F10.9831[046/293] bianjie1_14.png | IoU0.9373, P0.9846, R0.9513, F10.9677[047/293] bianjie1_140.png | IoU0.9795, P0.9940, R0.9853, F10.9896[048/293] bianjie1_141.png | IoU0.9625, P0.9986, R0.9639, F10.9809[049/293] bianjie1_142.png | IoU0.9702, P0.9956, R0.9744, F10.9849[050/293] bianjie1_143.png | IoU0.9797, P0.9944, R0.9851, F10.9897结果分析先算四种像素统计量tpnp.logical_and(pred,gt).sum()fpnp.logical_and(pred,~gt).sum()fnnp.logical_and(~pred,gt).sum()tnnp.logical_and(~pred,~gt).sum()含义TP预测是 grass真值也是 grassFP预测是 grass但真值不是 grassFN预测不是 grass但真值是 grassTN预测不是 grass真值也不是 grassPrecisionprecision tp / (tp fp)模型预测成 grass 的地方有多少是真的 grass。Recallrecall tp / (tp fn)真值里的 grass有多少被模型找到了。IoUiou tp / (tp fp fn)预测区域和真值区域的交并比。F1f1 2 * precision * recall / (precision recall)Precision 和 Recall 的综合指标。异常数据发现在黄草区域的草的识别有问题尤其是光线不好的时候会和附近的暗灰色水泥地混合识别成路面后续需要改善