0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于YOLO-V5的网络结构及实现行人社交距离风险提示

新机器视觉 来源:AI人工智能初学者 作者:ChaucerG 2022-07-06 10:24 次阅读

从代码的角度理解YOLO V5的工作。YOLO V5的网络结构图如下:

1、与YOLO V4的区别

Yolov4在Yolov3的基础上进行了很多的创新。比如输入端采用mosaic数据增强,Backbone上采用了CSPDarknet53、Mish激活函数、Dropblock等方式,Neck中采用了SPP、FPN+PAN的结构,输出端则采用CIOU_Loss、DIOU_nms操作。因此Yolov4对Yolov3的各个部分都进行了很多的整合创新。这里给出YOLO V4的网络结构图:

Yolov5的结构其实和Yolov4的结构还是有一定的相似之处的,但也有一些不同,这里还是按照从整体到细节的方式,对每个板块进行讲解。这里给出YOLO V4的网络结构图:

通过Yolov5的网络结构图可以看到,依旧是把模型分为4个部分,分别是:输入端、Backbone、Neck、Prediction。

1.1、输入端的区别

1 Mosaic数据增强

Mosaic是参考CutMix数据增强的方式,但CutMix只使用了两张图片进行拼接,而Mosaic数据增强则采用了4张图片,随机缩放、随机裁剪、随机排布的方式进行拼接。

主要有几个优点:

1、丰富数据集:随机使用4张图片,随机缩放,再随机分布进行拼接,大大丰富了检测数据集,特别是随机缩放增加了很多小目标,让网络的鲁棒性更好。

2、减少GPU:可能会有人说,随机缩放,普通的数据增强也可以做,但作者考虑到很多人可能只有一个GPU,因此Mosaic增强训练时,可以直接计算4张图片的数据,使得Mini-batch大小并不需要很大,一个GPU就可以达到比较好的效果。

2 自适应锚框计算

在Yolov3、Yolov4中,训练不同的数据集时,计算初始锚框的值是通过单独的程序运行的。但Yolov5中将此功能嵌入到代码中,每次训练时,自适应的计算不同训练集中的最佳锚框值。

比如Yolov5在Coco数据集上初始设定的锚框:

3 自适应图片缩放

在常用的目标检测算法中,不同的图片长宽都不相同,因此常用的方式是将原始图片统一缩放到一个标准尺寸,再送入检测网络中。比如Yolo算法中常用416×416,608×608等尺寸,比如对下面800×600的图像进行变换。

但Yolov5代码中对此进行了改进,也是Yolov5推理速度能够很快的一个不错的trick。作者认为,在项目实际使用时,很多图片的长宽比不同。因此缩放填充后,两端的黑边大小都不同,而如果填充的比较多,则存在信息冗余,影响推理速度。

具体操作的步骤:

1 计算缩放比例

原始缩放尺寸是416×416,都除以原始图像的尺寸后,可以得到0.52,和0.69两个缩放系数,选择小的缩放系数0.52。

2 计算缩放后的尺寸

原始图片的长宽都乘以最小的缩放系数0.52,宽变成了416,而高变成了312。

3 计算黑边填充数值

将416-312=104,得到原本需要填充的高度。再采用numpy中np.mod取余数的方式,得到40个像素,再除以2,即得到图片高度两端需要填充的数值。

1.2、Backbone的区别

1 Focus结构

Focus结构,在Yolov3&Yolov4中并没有这个结构,其中比较关键是切片操作。比如右图的切片示意图,4×4×3的图像切片后变成3×3×12的特征图。以Yolov5s的结构为例,原始608×608×3的图像输入Focus结构,采用切片操作,先变成304×304×12的特征图,再经过一次32个卷积核的卷积操作,最终变成304×304×32的特征图。

需要注意的是:Yolov5s的Focus结构最后使用了32个卷积核,而其他三种结构,使用的数量有所增加,先注意下,后面会讲解到四种结构的不同点。

class Focus(nn.Module):

# Focus wh information into c-space

def __init__(self, c1, c2, k=1):

super(Focus, self).__init__()

self.conv = Conv(c1 * 4, c2, k, 1)

def forward(self, x): # x(b,c,w,h) -》 y(b,4c,w/2,h/2)

return self.conv(torch.cat([x[。.., ::2, ::2], x[。.., 1::2, ::2], x[。.., ::2, 1::2], x[。.., 1::2, 1::2]], 1))

2 CSP结构

Yolov5与Yolov4不同点在于,Yolov4中只有主干网络使用了CSP结构,而Yolov5中设计了两种CSP结构,以Yolov5s网络为例,以CSP1_X结构应用于Backbone主干网络,另一种CSP2_X结构则应用于Neck中。

classConv(nn.Module):
#Standardconvolution
def__init__(self,c1,c2,k=1,s=1,g=1,act=True):#ch_in,ch_out,kernel,stride,groups
super(Conv,self).__init__()
self.conv=nn.Conv2d(c1,c2,k,s,k//2,groups=g,bias=False)
self.bn=nn.BatchNorm2d(c2)
self.act=nn.LeakyReLU(0.1,inplace=True)ifactelsenn.Identity()

defforward(self,x):
returnself.act(self.bn(self.conv(x)))

deffuseforward(self,x):
returnself.act(self.conv(x))


classBottleneck(nn.Module):
#Standardbottleneck
def__init__(self,c1,c2,shortcut=True,g=1,e=0.5):#ch_in,ch_out,shortcut,groups,expansion
super(Bottleneck,self).__init__()
c_=int(c2*e)#hiddenchannels
self.cv1=Conv(c1,c_,1,1)
self.cv2=Conv(c_,c2,3,1,g=g)
self.add=shortcutandc1==c2

defforward(self,x):
returnx+self.cv2(self.cv1(x))ifself.addelseself.cv2(self.cv1(x))


classBottleneckCSP(nn.Module):
#CSPBottleneckhttps://github.com/WongKinYiu/CrossStagePartialNetworks
def__init__(self,c1,c2,n=1,shortcut=True,g=1,e=0.5):#ch_in,ch_out,number,shortcut,groups,expansion
super(BottleneckCSP,self).__init__()
c_=int(c2*e)#hiddenchannels
self.cv1=Conv(c1,c_,1,1)
self.cv2=nn.Conv2d(c1,c_,1,1,bias=False)
self.cv3=nn.Conv2d(c_,c_,1,1,bias=False)
self.cv4=Conv(c2,c2,1,1)
self.bn=nn.BatchNorm2d(2*c_)#appliedtocat(cv2,cv3)
self.act=nn.LeakyReLU(0.1,inplace=True)
self.m=nn.Sequential(*[Bottleneck(c_,c_,shortcut,g,e=1.0)for_inrange(n)])

defforward(self,x):
y1=self.cv3(self.m(self.cv1(x)))
y2=self.cv2(x)
returnself.cv4(self.act(self.bn(torch.cat((y1,y2),dim=1))))

1.3、Neck的区别

Yolov5现在的Neck和Yolov4中一样,都采用FPN+PAN的结构,但在Yolov5刚出来时,只使用了FPN结构,后面才增加了PAN结构,此外网络中其他部分也进行了调整。

35c30642-ec61-11ec-ba43-dac502259ad0.png

Yolov5和Yolov4的不同点在于,Yolov4的Neck中,采用的都是普通的卷积操作。而Yolov5的Neck结构中,采用借鉴CSPNet设计的CSP2结构,加强网络特征融合的能力。

1.4、输出端的区别

1 Bounding box损失函数

而Yolov4中采用CIOU_Loss作为目标Bounding box的损失。而Yolov5中采用其中的GIOU_Loss做Bounding box的损失函数。

35db8000-ec61-11ec-ba43-dac502259ad0.png

35ef7ca4-ec61-11ec-ba43-dac502259ad0.png

defcompute_loss(p,targets,model):#predictions,targets,model
ft=torch.cuda.FloatTensorifp[0].is_cudaelsetorch.Tensor
lcls,lbox,lobj=ft([0]),ft([0]),ft([0])
tcls,tbox,indices,anchors=build_targets(p,targets,model)#targets
h=model.hyp#hyperparameters
red='mean'#Lossreduction(sumormean)

#Definecriteria
BCEcls=nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]),reduction=red)
BCEobj=nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]),reduction=red)

#classlabelsmoothinghttps://arxiv.org/pdf/1902.04103.pdfeqn3
cp,cn=smooth_BCE(eps=0.0)

#focalloss
g=h['fl_gamma']#focallossgamma
ifg>0:
BCEcls,BCEobj=FocalLoss(BCEcls,g),FocalLoss(BCEobj,g)

#peroutput
nt=0#targets
fori,piinenumerate(p):#layerindex,layerpredictions
b,a,gj,gi=indices[i]#image,anchor,gridy,gridx
tobj=torch.zeros_like(pi[...,0])#targetobj

nb=b.shape[0]#numberoftargets
ifnb:
nt+=nb#cumulativetargets
ps=pi[b,a,gj,gi]#predictionsubsetcorrespondingtotargets

#GIoU
pxy=ps[:,:2].sigmoid()*2.-0.5
pwh=(ps[:,2:4].sigmoid()*2)**2*anchors[i]
pbox=torch.cat((pxy,pwh),1)#predictedbox
giou=bbox_iou(pbox.t(),tbox[i],x1y1x2y2=False,GIoU=True)#giou(prediction,target)
lbox+=(1.0-giou).sum()ifred=='sum'else(1.0-giou).mean()#giouloss

#Obj
tobj[b,a,gj,gi]=(1.0-model.gr)+model.gr*giou.detach().clamp(0).type(tobj.dtype)#giouratio

#Class
ifmodel.nc>1:#clsloss(onlyifmultipleclasses)
t=torch.full_like(ps[:,5:],cn)#targets
t[range(nb),tcls[i]]=cp
lcls+=BCEcls(ps[:,5:],t)#BCE

#Appendtargetstotextfile
#withopen('targets.txt','a')asfile:
#[file.write('%11.5g'*4%tuple(x)+'
')forxintorch.cat((txy[i],twh[i]),1)]

lobj+=BCEobj(pi[...,4],tobj)#objloss

lbox*=h['giou']
lobj*=h['obj']
lcls*=h['cls']
bs=tobj.shape[0]#batchsize
ifred=='sum':
g=3.0#lossgain
lobj*=g/bs
ifnt:
lcls*=g/nt/model.nc
lbox*=g/nt

loss=lbox+lobj+lcls
returnloss*bs,torch.cat((lbox,lobj,lcls,loss)).detach()

2 NMS非极大值抑制

Yolov4在DIOU_Loss的基础上采用DIOU_NMS的方式,而Yolov5中采用加权NMS的方式。可以看出,采用DIOU_NMS,下方中间箭头的黄色部分,原本被遮挡的摩托车也可以检出。

在同样的参数情况下,将NMS中IOU修改成DIOU_NMS。对于一些遮挡重叠的目标,确实会有一些改进。

2、YOLOv5社交距离项目

yolov5检测要检测的视频流中的所有人,然后再计算所有检测到的人之间的相互“距离”,和现实生活中用“m”这样的单位衡量距离不一样的是,在计算机中,简单的方法是用检测到的两个人的质心,也就是检测到的目标框的中心之间相隔的像素值作为计算机中的“距离”来衡量视频中的人之间的距离是否超过安全距离。

构建步骤

使用目标检测算法检测视频流中的所有人,得到位置信息和质心位置;

计算所有检测到的人质心之间的相互距离;

设置安全距离,计算每个人之间的距离对,检测两个人之间的距离是否小于N个像素,小于则处于安全距离,反之则不处于。

362564ae-ec61-11ec-ba43-dac502259ad0.png

项目架构:

363b3522-ec61-11ec-ba43-dac502259ad0.png

detect.py代码注释如下:

importargparse

fromutils.datasetsimport*
fromutils.utilsimport*


defdetect(save_img=False):
out,source,weights,view_img,save_txt,imgsz=
opt.output,opt.source,opt.weights,opt.view_img,opt.save_txt,opt.img_size
webcam=source=='0'orsource.startswith('rtsp')orsource.startswith('http')orsource.endswith('.txt')

#Initialize
device=torch_utils.select_device(opt.device)
ifos.path.exists(out):
shutil.rmtree(out)#deleteoutputfolder
os.makedirs(out)#makenewoutputfolder
half=device.type!='cpu'#halfprecisiononlysupportedonCUDA

#下载模型
google_utils.attempt_download(weights)
#加载权重
model=torch.load(weights,map_location=device)['model'].float()
#torch.save(torch.load(weights,map_location=device),weights)#updatemodelifSourceChangeWarning
#model.fuse()
#设置模型为推理模式
model.to(device).eval()
ifhalf:
model.half()#toFP16

#Second-stageclassifier
classify=False
ifclassify:
modelc=torch_utils.load_classifier(name='resnet101',n=2)#initialize
modelc.load_state_dict(torch.load('weights/resnet101.pt',map_location=device)['model'])#loadweights
modelc.to(device).eval()

#设置Dataloader
vid_path,vid_writer=None,None
ifwebcam:
view_img=True
torch.backends.cudnn.benchmark=True#setTruetospeedupconstantimagesizeinference
dataset=LoadStreams(source,img_size=imgsz)
else:
save_img=True
dataset=LoadImages(source,img_size=imgsz)

#获取检测类别的标签名称
names=model.namesifhasattr(model,'names')elsemodel.modules.names
#定义颜色
colors=[[random.randint(0,255)for_inrange(3)]for_inrange(len(names))]

#开始推理
t0=time.time()
#初始化一张全为0的图片
img=torch.zeros((1,3,imgsz,imgsz),device=device)
_=model(img.half()ifhalfelseimg)ifdevice.type!='cpu'elseNone
forpath,img,im0s,vid_capindataset:
img=torch.from_numpy(img).to(device)
img=img.half()ifhalfelseimg.float()#uint8tofp16/32
img/=255.0#0-255to0.0-1.0
ifimg.ndimension()==3:
img=img.unsqueeze(0)

#预测结果
t1=torch_utils.time_synchronized()
pred=model(img,augment=opt.augment)[0]

#使用NMS
pred=non_max_suppression(pred,opt.conf_thres,opt.iou_thres,fast=True,classes=opt.classes,agnostic=opt.agnostic_nms)
t2=torch_utils.time_synchronized()

#进行分类
ifclassify:
pred=apply_classifier(pred,modelc,img,im0s)

people_coords=[]

#处理预测得到的检测目标
fori,detinenumerate(pred):
ifwebcam:
p,s,im0=path[i],'%g:'%i,im0s[i].copy()
else:
p,s,im0=path,'',im0s

save_path=str(Path(out)/Path(p).name)
s+='%gx%g'%img.shape[2:]#printstring
gn=torch.tensor(im0.shape)[[1,0,1,0]]#normalizationgainwhwh
ifdetisnotNoneandlen(det):
#把boxesresize到im0的size
det[:,:4]=scale_coords(img.shape[2:],det[:,:4],im0.shape).round()

#打印结果
forcindet[:,-1].unique():
n=(det[:,-1]==c).sum()#detectionsperclass
s+='%g%ss,'%(n,names[int(c)])#addtostring

#书写结果
for*xyxy,conf,clsindet:
ifsave_txt:
#xyxy2xywh==>把预测得到的坐标结果[x1,y1,x2,y2]转换为[x,y,w,h]其中xy1=top-left,xy2=bottom-right
xywh=(xyxy2xywh(torch.tensor(xyxy).view(1,4))/gn).view(-1).tolist()#normalizedxywh
withopen(save_path[:save_path.rfind('.')]+'.txt','a')asfile:
file.write(('%g'*5+'
')%(cls,*xywh))#labelformat

ifsave_imgorview_img:#Addbboxtoimage
label='%s%.2f'%(names[int(cls)],conf)
iflabelisnotNone:
if(label.split())[0]=='person':
#print(xyxy)
people_coords.append(xyxy)
#plot_one_box(xyxy,im0,line_thickness=3)
plot_dots_on_people(xyxy,im0)

#通过people_coords绘制people之间的连接线
#这里主要分为"LowRisk"和"HighRisk"
distancing(people_coords,im0,dist_thres_lim=(200,250))

#Printtime(inference+NMS)
print('%sDone.(%.3fs)'%(s,t2-t1))

#Streamresults
ifview_img:
cv2.imshow(p,im0)
ifcv2.waitKey(1)==ord('q'):#qtoquit
raiseStopIteration

#Saveresults(imagewithdetections)
ifsave_img:
ifdataset.mode=='images':
cv2.imwrite(save_path,im0)
else:
ifvid_path!=save_path:#newvideo
vid_path=save_path
ifisinstance(vid_writer,cv2.VideoWriter):
vid_writer.release()#releasepreviousvideowriter

fps=vid_cap.get(cv2.CAP_PROP_FPS)
w=int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h=int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
vid_writer=cv2.VideoWriter(save_path,cv2.VideoWriter_fourcc(*opt.fourcc),fps,(w,h))
vid_writer.write(im0)

ifsave_txtorsave_img:
print('Resultssavedto%s'%os.getcwd()+os.sep+out)
ifplatform=='darwin':#MacOS
os.system('open'+save_path)

print('Done.(%.3fs)'%(time.time()-t0))


if__name__=='__main__':
parser=argparse.ArgumentParser()
parser.add_argument('--weights',type=str,default='./weights/yolov5s.pt',help='model.ptpath')
parser.add_argument('--source',type=str,default='./inference/videos/',help='source')#file/folder,0forwebcam
parser.add_argument('--output',type=str,default='./inference/output',help='outputfolder')#outputfolder
parser.add_argument('--img-size',type=int,default=640,help='inferencesize(pixels)')
parser.add_argument('--conf-thres',type=float,default=0.4,help='objectconfidencethreshold')
parser.add_argument('--iou-thres',type=float,default=0.5,help='IOUthresholdforNMS')
parser.add_argument('--fourcc',type=str,default='mp4v',help='outputvideocodec(verifyffmpegsupport)')
parser.add_argument('--device',default='0',help='cudadevice,i.e.0or0,1,2,3orcpu')
parser.add_argument('--view-img',action='store_true',help='displayresults')
parser.add_argument('--save-txt',action='store_true',help='saveresultsto*.txt')
parser.add_argument('--classes',nargs='+',type=int,help='filterbyclass')
parser.add_argument('--agnostic-nms',action='store_true',help='class-agnosticNMS')
parser.add_argument('--augment',action='store_true',help='augmentedinference')
opt=parser.parse_args()
opt.img_size=check_img_size(opt.img_size)
print(opt)

withtorch.no_grad():
detect()

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • gpu
    gpu
    +关注

    关注

    27

    文章

    4415

    浏览量

    126663
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66746
  • 数据集
    +关注

    关注

    4

    文章

    1178

    浏览量

    24348

原文标题:项目实践 | 基于YOLO-V5实现行人社交距离风险提示

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    求助。我国市级电话网络结构

    我国的市级的电话网络结构是一样的么他的结构图是怎么样的
    发表于 11-09 19:43

    linux不同网络结构的不同IP设法

    Linux的装系统设IP,这应该是系统管理员的基本功,可是不同的网络结构有不同的IP设法,您知道吗?
    发表于 07-05 06:52

    神经网络结构搜索有什么优势?

    ,稍有不同就无法复现论文的结果。而网络结构作为一种特殊的超参数,在深度学习整个环节中扮演着举足轻重的角色。在图像分类任务上大放异彩的ResNet、在机器翻译任务上称霸的Transformer等网络结构
    发表于 09-11 11:52

    手绘网络结构

    手绘一些网络结构图,很初级
    发表于 10-25 14:06

    网络结构与IP分组交换技术

    《计算机体系结构网络篇1、2》之 网络结构、IP分组交换技术、IP/MAC映射、NAT转换等...
    发表于 12-23 06:05

    介绍yolo v4版的安装与测试

    You only look once (YOLO)是一款非常著名的物体识别深度学习网络,可实现快速检测的同时还达到较高的准确率。问介绍yolo v
    发表于 02-17 07:06

    YOLOv5网络结构解析

    1、YOLOv5 网络结构解析  YOLOv5针对不同大小(n, s, m, l, x)的网络整体架构都是一样的,只不过会在每个子模块中采用不同的深度和宽度,  分别应对yaml文件中
    发表于 10-31 16:30

    TD-SCDMA网络结构

    TD-SCDMA 系统的网络结构完全遵循3GPP 指定的UMTS 网络结构,可以分为接入网(UTRAN)和核心网(CN)。本章首先介绍UMTS 的物理网络结构模型,根据TD-SCDMA 系统的接入网和核心网组成阐述
    发表于 06-19 14:10 217次下载

    TD-SCDMA R4网络结构和技术要求

    TD-SCDMA R4网络结构和技术要求:核心网演进过程R99网络结构R4网络结构
    发表于 07-30 08:19 14次下载

    环形网络,环形网络结构是什么?

    环形网络,环形网络结构是什么? 这种结构网络形式主要应用于令牌网中,在这种网络结构中各设备是直接通过电缆来串接的,最后形成一个闭环,
    发表于 03-22 11:14 5832次阅读

    4G网络结构及关键技术

    4G网络结构及关键技的精彩讲解
    发表于 11-10 17:19 114次下载
    4G<b class='flag-5'>网络结构</b>及关键技术

    网络结构中链接寿命的研究

    的特性,特别是基于网络拓扑结构的研究,以期改善当前的网络应用并创造新的受欢迎的社交网络应用。然而,大多数的现有研究方法只是研究随着时间积累的
    发表于 11-24 09:50 3次下载
    <b class='flag-5'>网络结构</b>中链接寿命的研究

    使用Python和OpenCV实现行人检测的资料合集免费下载

    本文档的主要内容详细介绍的是使用Python和OpenCV实现行人检测的资料合集免费下载。
    发表于 06-01 17:42 23次下载
    使用Python和OpenCV<b class='flag-5'>实现行人</b>检测的资料合集免费下载

    交换机的三层网络结构介绍

    对于一大型监控项目,其重点就是交换机的选择了,这里我们选用三层网络结构网络结构为接入层‐汇聚层‐核心层。相对两层网络架构,三层架构网络组网规模更大,传输
    的头像 发表于 01-09 10:29 1.1w次阅读

    一种改进的深度神经网络结构搜索方法

    为提升网络结构的寻优能力,提岀一种改进的深度神经网络结构搜索方法。针对网络结构间距难以度量的问题,结合神经网络结构搜索方案,设计基于图的深
    发表于 03-16 14:05 3次下载
    一种改进的深度神经<b class='flag-5'>网络结构</b>搜索方法