【深度学习】DBFace: 源码阅读(三)
7 推断部分推断部分主要是在test.py中主要函数其实很短如下代码其实被我改了一部分和原始的github上可能有点区别mean[0.408,0.447,0.47]std[0.289,0.274,0.278]# trial_name small-H-dense-wide64-UCBA-keep12-noext-ignoresmall2trial_namemv2-320x320-without-wf_20200811jobdirfjobs/{trial_name}imagecommon.imread(imgs/selfie.jpg)modelDBFace(has_landmarkTrue,wide64,has_extTrue,upmodeDeCBA)model.load(f{jobdir}/models/74.pth)model.eval()model.cuda()outseval_tool.detect_image(model,image,mean,std,0.2)outsnms(outs,0.2)print(objs %d%len(outs))forobjinouts:common.drawbbox(image,obj)common.imwrite(f{jobdir}/result.jpg,image)print(ok)model.load()下载对应的模型推断最主要的函数是outseval_tool.detect_image(model,image,mean,std,0.2)我们来看下detect_image函数defdetect_image(model,image,mean,std,threshold0.4):# pad主要是因为网络推断中stride32所以为了保证可以上采样回去需要进行pad操作imagecommon.pad(image)#预处理操作image((image/255-mean)/std).astype(np.float32)imageimage.transpose(2,0,1)imagetorch.from_numpy(image).unsqueeze(0).cuda()# 推断center,box,landmarkmodel(image)#得到结果回归框中心点的heatmap通过sigmoid来得到0-1centercenter.sigmoid()boxtorch.exp(box)# debug# center F.max_pool2d(center, kernel_size3, padding1, stride1)returndetect_images_giou_with_netout(center,box,landmark,threshold)我们再来看下detect_images_giou_with_netout这个函数defdetect_images_giou_with_netout(output_hm,output_tlrb,output_landmark,threshold0.4,ibatch0):stride4_,num_classes,hm_height,hm_widthoutput_hm.shape hmoutput_hm[ibatch].reshape(1,num_classes,hm_height,hm_width)tlrboutput_tlrb[ibatch].cpu().data.numpy().reshape(1,num_classes*4,hm_height,hm_width)# landmark output_landmark[ibatch].cpu().data.numpy().reshape(1, num_classes * 10, hm_height, hm_width)landmarkoutput_landmark[ibatch].cpu().data.numpy().reshape(1,num_classes*50,hm_height,hm_width)# 使用最大池化来筛选值nmskey_nms(hm,3)# 选出top值2000人脸较多的情况下值可以大一些但是如果人脸比较少或者图像比较小建议还是小一些kscore,kinds,kcls,kys,kxs_topk(nmskey,2000)kyskys.cpu().data.numpy().astype(np.int)kxskxs.cpu().data.numpy().astype(np.int)kclskcls.cpu().data.numpy().astype(np.int)key[[],[],[],[]]forindinrange(kscore.shape[1]):scorekscore[0,ind]ifscorethreshold:key[0].append(kys[0,ind])key[1].append(kxs[0,ind])key[2].append(score)key[3].append(kcls[0,ind])imboxs[]ifkey[0]isnotNoneandlen(key[0])0:ky,kxkey[0],key[1]classeskey[3]scoreskey[2]foriinrange(len(kx)):class_classes[i]cx,cykx[i],ky[i]x1,y1,x2,y2tlrb[0,class_*4:(class_1)*4,cy,cx]x1,y1,x2,y2(np.array([cx,cy,cx,cy])np.array([-x1,-y1,x2,y2]))*stride# 根据关键点个数进行修改# x5y5 landmark[0, 0:10, cy, cx]# x5y5 np.array(common.exp(x5y5 * 4))# x5y5 (x5y5 np.array([cx] * 5 [cy] * 5)) * stride# boxlandmark list(zip(x5y5[:5], x5y5[5:]))x5y5landmark[0,0:50,cy,cx]#注意这个expx5y5np.array(common.exp(x5y5*4))x5y5(x5y5np.array([cx]*25[cy]*25))*stride boxlandmarklist(zip(x5y5[:25],x5y5[25:]))imboxs.append(common.BBox(labelstr(class_),xyrbcommon.floatv([x1,y1,x2,y2]),scorescores[i].item(),landmarkboxlandmark))returnimboxs最后将返回得到的候选框和关键点坐标在通过nms进行处理defnms(objs,iou0.5):ifobjsisNoneorlen(objs)1:returnobjs objssorted(objs,keylambdaobj:obj.score,reverseTrue)keep[]flags[0]*len(objs)forindex,objinenumerate(objs):ifflags[index]!0:continuekeep.append(obj)forjinrange(index1,len(objs)):ifflags[j]0andobj.iou(objs[j])iou:flags[j]1returnkeep使用NMS来去除冗余的框得到最后的结果当中其实有些细节例如关键点的后处理要进行expdefexp(v):ifisinstance(v,tuple)orisinstance(v,list):return[exp(item)foriteminv]elifisinstance(v,np.ndarray):returnnp.array([exp(item)foriteminv],v.dtype)gate1basenp.exp(1)ifabs(v)gate:returnv*baseifv0:returnnp.exp(v)else:return-np.exp(-v)为什么呢我们来看下作者是怎么解释的第三篇还是有些细节是需要注意的后面一篇写下转caffemodel还是其他呢。。。