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
    +关注

    关注

    28

    文章

    4735

    浏览量

    128917
  • 代码
    +关注

    关注

    30

    文章

    4786

    浏览量

    68552
  • 数据集
    +关注

    关注

    4

    文章

    1208

    浏览量

    24694

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

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

收藏 人收藏

    评论

    相关推荐

    助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4

    开发板,通过底板和丰富接口的载板设计,非常适合高效的嵌入式低功耗数据处理。 Yolo V4 网络结构图 Tiny Yolo V4
    发表于 12-06 17:18

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

    我国的市级的电话网络结构是一样的么他的结构图是怎么样的
    发表于 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

    TD-SCDMA网络结构

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

    DeviceNet 网络结构

    DeviceNet 网络结构 基于现场总线的开放的自动化系统底层结构近年来发展起来的现场总线技术以其灵活的控制方式信息共享和低成本等特点被广泛的用于复的
    发表于 03-22 15:46 30次下载

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

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

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

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

    概率模型的大规模网络结构发现方法

    随着万维网和在线社交网站的发展,规模大、结构复杂、动态性强的大规模网络应用而生.发现这些网络的潜在结构,是分析和理解
    发表于 02-12 10:48 1次下载

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

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

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

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

    卷积神经网络结构

    Learning)的应用,通过运用多层卷积神经网络结构,可以自动地进行特征提取和学习,进而实现图像分类、物体识别、目标检测、语音识别和自然语言翻译等任务。 卷积神经网络结构包括:输
    的头像 发表于 08-17 16:30 1222次阅读

    如何优化PLC的网络结构

    优化PLC的网络结构可以提高通信的效率和稳定性。以下是一些优化PLC网络结构的方法: (1)设计合理的拓扑结构:根据应用需求和设备分布情况,设计合理的网络拓扑
    的头像 发表于 12-23 08:15 691次阅读
    如何优化PLC的<b class='flag-5'>网络结构</b>?