上海网站开发建设wordpress摘要过滤
2026/4/18 12:44:26 网站建设 项目流程
上海网站开发建设,wordpress摘要过滤,python设计模式,网站设计的公司排名一、前言#xff1a;YOLOv5后处理到底要做什么#xff1f; 你复习的这份笔记核心是解决「模型输出→实际检测框」的转换问题#xff1a; YOLOv5模型的输出是一个[n, 85]的张量#xff08;n是预测框数量#xff0c;85中心坐标cx/cy 宽高w/h 目标置信度obj 80类分类概率YOLOv5后处理到底要做什么你复习的这份笔记核心是解决「模型输出→实际检测框」的转换问题YOLOv5模型的输出是一个[n, 85]的张量n是预测框数量85中心坐标cx/cy 宽高w/h 目标置信度obj 80类分类概率后处理的核心任务解码把[cx, cy, w, h]转换成实际的检测框坐标[left, top, right, bottom]并过滤低置信度的框NMS非极大值抑制去掉同一目标的重复检测框比如一个人被多个框框住只留置信度最高的加速目标CPU版后处理在检测框数量大时速度慢用CUDA核函数并行处理每个预测框把后处理时间从“毫秒级”压到“微秒级”。二、核心概念先搞懂YOLOv5后处理的基础规则用「招聘筛选」比喻帮你理解后处理步骤技术逻辑生活化比喻解码1. 计算置信度obj×类概率2. 过滤置信度低于阈值比如0.25的框3. 把cx/cy/w/h转成左上/右下坐标1. 看简历的“综合评分”obj基础分类概率岗位匹配分2. 淘汰综合分低于60分的候选人3. 把候选人的“模糊地址”转成“精确地址”NMS1. 按置信度排序2. 去掉和高置信度框重叠度IoU超过阈值比如0.45的重复框1. 按综合分从高到低排候选人2. 淘汰和第一名重复的候选人比如同一个人投了多个岗位三、后处理案例拆解CPU版→GPU版笔记里先讲CPU版易理解、打基础再讲GPU版并行加速我们逐段拆解。3.1 先明确YOLOv5输出的格式约定模型输出的每个预测框是85个数值顺序是[cx, cy, width, height, objectness, class1, class2, ..., class80]objectness这个框里“有目标”的概率0~1class1~class80这个框属于80类COCO数据集中某一类的概率最终置信度 objectness × 最高类概率比如obj0.8类概率0.9→置信度0.72。3.2 CPU_decode后处理的“手工筛选版”CPU版是后处理的“基础实现”核心是「逐框处理有序去重」先看代码结构再拆解关键逻辑。3.2.1 核心代码// 先定义Box结构体存检测框的坐标、置信度、类别structBox{floatleft,top,right,bottom,confidence;floatlabel;Box(floatl,floatt,floatr,floatb,floatc,floatlb):left(l),top(t),right(r),bottom(b),confidence(c),label(lb){}};vectorBoxcpu_decode(float*predict,introws,intcols,floatconfidence_threshold0.25f,floatnms_threshold0.45f){vectorBoxboxes;intnum_classescols-5;// 85-580类// 第一步解码过滤低置信度框for(inti0;irows;i){float*pitempredicti*cols;// 当前预测框的首地址floatobjnesspitem[4];// 目标置信度if(objnessconfidence_threshold)// 过滤低obj框减少后续计算continue;// 找概率最高的类别float*pclasspitem5;intlabelstd::max_element(pclass,pclassnum_classes)-pclass;floatprobpclass[label];floatconfidenceprob*objness;// 最终置信度if(confidenceconfidence_threshold)// 二次过滤continue;// 把cx/cy/w/h转成左上/右下坐标floatcxpitem[0];floatcypitem[1];floatwidthpitem[2];floatheightpitem[3];floatleftcx-width*0.5;floattopcy-height*0.5;floatrightcxwidth*0.5;floatbottomcyheight*0.5;boxes.emplace_back(left,top,right,bottom,confidence,(float)label);}// 第二步NMS去重// 1. 按置信度降序排序std::sort(boxes.begin(),boxes.end(),[](Boxa,Boxb){returna.confidenceb.confidence;});std::vectorboolremove_flags(boxes.size(),false);// 标记是否要移除std::vectorBoxbox_result;box_result.reserve(boxes.size());// 预分配内存提升性能// 定义IoU计算函数计算两个框的重叠度autoiou[](constBoxa,constBoxb){floatcross_leftstd::max(a.left,b.left);floatcross_topstd::max(a.top,b.top);floatcross_rightstd::min(a.right,b.right);floatcross_bottomstd::min(a.bottom,b.bottom);floatcross_areastd::max(0.0f,cross_right-cross_left)*std::max(0.0f,cross_bottom-cross_top);// 重叠面积floata_area(a.right-a.left)*(a.bottom-a.top);floatb_area(b.right-b.left)*(b.bottom-b.top);floatunion_areaa_areab_area-cross_area;// 并集面积returnunion_area0?0:cross_area/union_area;// IoU重叠面积/并集面积};// 2. 遍历框标记重复框for(inti0;iboxes.size();i){if(remove_flags[i])continue;// 已标记移除跳过autoiboxboxes[i];box_result.emplace_back(ibox);// 保留当前最高置信度框for(intji1;jboxes.size();j){if(remove_flags[j])continue;autojboxboxes[j];if(ibox.labeljbox.labeliou(ibox,jbox)nms_threshold){remove_flags[j]true;// 同类高IoU标记移除}}}returnbox_result;}3.2.2 关键解读新手必懂性能优化点笔记重点提前过滤先过滤objness低的框避免后续计算类别概率、坐标转换“先筛掉明显不合格的再细看”预分配内存box_result.reserve(boxes.size())——避免vector频繁扩容提升速度标志位去重用remove_flags标记要移除的框而非直接删除删除会导致数组移位效率低。核心逻辑总结解码逐框算置信度→过滤→转坐标NMS排序→逐框对比IoU→标记重复框→保留未标记的框。3.3 GPU_decode后处理的“流水线工厂版”GPU版的核心是「并行处理每个预测框」——启动和预测框数量相等的线程每个线程处理一个框的解码再用并行NMS去重。3.3.1 第一步decode_kernel解码核函数每个线程负责一个预测框的解码核心解决“并发写入结果”的问题用原子操作atomicAdd。核心代码// 定义常量每个检测框保存的元素数left,top,right,bottom,confidence,label,keepflagconstintNUM_BOX_ELEMENT7;constintMAX_OBJECTS1000;// 最大检测框数量static__global__voiddecode_kernel(float*predict,intnum_bboxes,intnum_classes,floatconfidence_threshold,float*invert_affine_matrix,float*parray,intmax_objects,intNUM_BOX_ELEMENT){// 1. 计算当前线程的全局索引对应第几个预测框intpositionblockDim.x*blockIdx.xthreadIdx.x;if(positionnum_bboxes)return;// 超出预测框数量退出// 2. 取当前预测框的首地址float*pitempredict(5num_classes)*position;floatobjectnesspitem[4];if(objectnessconfidence_threshold)return;// 3. 找概率最高的类别float*class_confidencepitem5;floatconfidence*class_confidence;intlabel0;for(inti1;inum_classes;i,class_confidence){if(*class_confidenceconfidence){confidence*class_confidence;labeli;}}// 4. 计算最终置信度二次过滤confidence*objectness;if(confidenceconfidence_threshold)return;// 5. 原子操作获取当前框的结果索引解决并发写入冲突intindexatomicAdd(parray,1);// parray[0]存框的数量原子加1返回旧值if(indexmax_objects)return;// 超过最大框数退出// 6. 转换坐标floatcx*pitem;floatcy*pitem;floatwidth*pitem;floatheight*pitem;floatleftcx-width*0.5f;floattopcy-height*0.5f;floatrightcxwidth*0.5f;floatbottomcyheight*0.5f;// 7. 保存结果parray[1 index*7]开始存当前框的信息float*pout_itemparray1index*NUM_BOX_ELEMENT;*pout_itemleft;*pout_itemtop;*pout_itemright;*pout_itembottom;*pout_itemconfidence;*pout_itemlabel;*pout_item1;// 1保留0移除}关键解读新手必懂线程索引position blockDim.x * blockIdx.x threadIdx.x——每个线程对应一个预测框比如num_bboxes2000就启动2000个线程原子操作atomicAddparray是GPU上的数组格式为[count, box1, box2, ...]第一个元素存有效框数量后面存框信息atomicAdd(parray, 1)多个线程同时写parray[0]时保证“加1”操作不冲突比如线程A和B同时加1结果是2而不是1index是当前框在结果数组中的位置比如parray[0]初始是0线程A执行后index0parray[0]变成1线程B执行后index1parray[0]变成2和CPU版的区别不用逐框循环CPU是for循环GPU是并行线程结果保存到连续数组而非vectorGPU上用数组更高效暂时不做NMS先解码保存所有有效框。3.3.2 第二步fast_nms_kernel并行NMS核函数GPU版NMS不用排序CPU版要排序直接并行对比每个框和其他框的IoU核心是“快但极端情况可能少框”。核心代码// 先定义IoU计算函数GPU版__device__floatbox_iou(floatleft1,floattop1,floatright1,floatbottom1,floatleft2,floattop2,floatright2,floatbottom2){floatcross_leftmax(left1,left2);floatcross_topmax(top1,top2);floatcross_rightmin(right1,right2);floatcross_bottommin(bottom1,bottom2);floatcross_areamax(0.0f,cross_right-cross_left)*max(0.0f,cross_bottom-cross_top);floatarea1max(0.0f,right1-left1)*max(0.0f,bottom1-top1);floatarea2max(0.0f,right2-left2)*max(0.0f,bottom2-top2);floatunion_areaarea1area2-cross_area;returnunion_area0?0:cross_area/union_area;}static__global__voidfast_nms_kernel(float*bboxes,intmax_objects,floatthreshold,intNUM_BOX_ELEMENT){// 1. 计算当前线程索引对应第几个有效框intpositionblockDim.x*blockIdx.xthreadIdx.x;intcountmin((int)*bboxes,max_objects);// 有效框数量if(positioncount)return;// 2. 取当前框的信息float*pcurrentbboxes1position*NUM_BOX_ELEMENT;for(inti0;icount;i){float*pitembboxes1i*NUM_BOX_ELEMENT;if(iposition||pcurrent[5]!pitem[5])continue;// 跳过自己/不同类的框// 3. 对比置信度如果其他框置信度更高计算IoUif(pitem[4]pcurrent[4]){if(pitem[4]pcurrent[4]iposition)continue;// 置信度相同保留索引小的floatioubox_iou(pcurrent[0],pcurrent[1],pcurrent[2],pcurrent[3],pitem[0],pitem[1],pitem[2],pitem[3]);if(iouthreshold){pcurrent[6]0;// 标记为移除return;}}}}关键解读新手必懂fast NMS的核心逻辑每个线程处理一个有效框对比它和所有其他框如果存在“同类别置信度更高IoU超阈值”的框就标记当前框为移除pcurrent[6]0不用排序直接并行对比速度比CPU版快10倍以上为什么极端情况少框比如有3个重叠框置信度都是0.8线程处理顺序不同可能导致全部被标记移除实测中这种情况极少不影响实际使用mAP测试要用人CPU NMS的原因mAP平均精度需要精确的框筛选结果GPU版fast NMS的“少量漏框”会影响精度计算实际部署时用GPU版快测试精度时用CPU版准。3.3.3 GPU_decode的完整流程// 伪代码GPU后处理的整体调用vectorBoxgpu_decode(float*predict_cpu,introws,intcols){// 1. CPU→GPU拷贝模型输出float*predict_gpunullptr;checkRuntime(cudaMalloc(predict_gpu,rows*cols*sizeof(float)));checkRuntime(cudaMemcpy(predict_gpu,predict_cpu,rows*cols*sizeof(float),cudaMemcpyHostToDevice));// 2. GPU分配结果数组[count, box1, box2,...]float*parray_gpunullptr;intparray_size1MAX_OBJECTS*NUM_BOX_ELEMENT;checkRuntime(cudaMalloc(parray_gpu,parray_size*sizeof(float)));checkRuntime(cudaMemset(parray_gpu,0,parray_size*sizeof(float)));// 初始化count0// 3. 启动解码核函数dim3block_size(256);// 每个block256个线程dim3grid_size((rows255)/256);// 向上取整decode_kernelgrid_size,block_size(predict_gpu,rows,cols-5,0.25f,nullptr,parray_gpu,MAX_OBJECTS,NUM_BOX_ELEMENT);// 4. 启动fast NMS核函数intcountmin((int)*parray_gpu,MAX_OBJECTS);grid_size(count255)/256;fast_nms_kernelgrid_size,block_size(parray_gpu,MAX_OBJECTS,0.45f,NUM_BOX_ELEMENT);// 5. GPU→CPU拷贝结果解析成Box结构体float*parray_cpunewfloat[parray_size];checkRuntime(cudaMemcpy(parray_cpu,parray_gpu,parray_size*sizeof(float),cudaMemcpyDeviceToHost));vectorBoxresult;countmin((int)parray_cpu[0],MAX_OBJECTS);for(inti0;icount;i){float*pboxparray_cpu1i*NUM_BOX_ELEMENT;if(pbox[6]1){// 保留的框result.emplace_back(pbox[0],pbox[1],pbox[2],pbox[3],pbox[4],pbox[5]);}}// 6. 释放内存checkRuntime(cudaFree(predict_gpu));checkRuntime(cudaFree(parray_gpu));delete[]parray_cpu;returnresult;}四、补充知识笔记里的实战技巧变量控制法调试神器用PyTorch推理后把输出转成numpy→tobytes→保存到文件C读取文件数据做后处理不用搭TensorRT环境就能调试快速对比CPU/GPU结果是否一致GPU后处理的性能优化线程块大小设为32的倍数比如256符合GPU warp32线程的执行规则尽量减少GPU和CPU之间的数据拷贝解码、NMS都在GPU上做最后只拷贝结果fast NMS的取舍部署优先用GPU fast NMS快精度测试用CPU标准NMS准极端情况漏框的问题可通过调整NMS阈值比如从0.45降到0.4缓解。图2-3 PyTorch效果图2-4 自定义实现后处理的效果五、总结核心要点回顾YOLOv5后处理分两步解码过滤转坐标 NMS去重CPU版逐框处理GPU版并行处理每个框GPU解码的核心是atomicAdd解决多线程并发写入结果的冲突问题GPU NMS用fast NMS不用排序并行对比IoU速度快但极端情况可能少框部署时性价比极高。这份案例是YOLOv5 TensorRT部署的核心环节——把预处理之前的warpAffine和后处理都放到GPU上实现“模型推理前后处理”全GPU加速这也是高性能部署的关键。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询