文章目录
0 简介
今天学长向大家分享一个毕业设计项目
毕业设计 基于深度学习的驾驶行为检测(玩手机)
项目运行效果:
毕业设计 深度学习的驾驶行为检测(玩手机)
🧿 项目分享:见文末!
1 系统设计原则
为了使本次设计的吸烟检测系统具有更好的实用性、准确性和稳定性,同时能够让相关操作人员在使用时感受到便捷并且容易上手,在设计本系统时,主要遵循了以下五项基本原则:
(1)规范性原则:
在系统开发的过程当中所用到的控制协议、传输协议,编码类型等都应该符合国家标准和行业标准。在代码撰写时,应该符合一般的技术规范。
(2)模块化设计原则
模块化设计是指在系统设计时,尽可能的将多个基本功能设计为多个独立运行的模块,并且每一个模块只负责一件事情。这样就可以让系统结构更加清晰,同时在实际的运行过程中可以实现不同模块之间的调用,大大增加了系统的灵活性。这样做既可以用有限的模块来最大限度的完成用户的要求,同时对系统后期的维护以及功能的增加都非常有利。
(3)可操作性与可维护性原则
一个好的系统应该具有很好的可操作性,所以在符合用户使用习惯的基础上,对每一个具体操作进行简化。同时,为了使系统可以更加便于维护,在系统设计的过程当中,应该提前想清楚各个功能模块之间的难点与逻辑,这样才能在日后的维护当中减少工作量。
(4)可拓展性原则
系统开发将多个基本功能尽可能的设计为多个独立运行的模块,大大增加了系统的可拓展性。与此同时,开发过程当中,前端和后端的功能是分开进行的,通过提前设计好的可供数据传输的接口,以 JSON 数据格式在各个模块之间进行数据交换操作,使前后端之间具有解耦关系,这样做可以保证了系统具有比较良好的可扩展能力和稳定能力。
(5)经济性原则
在系统设计的时候,首先是要考虑用户的具体需求,设计实用的功能,发挥系统的最大性能。但是在满足用户所需的功能后,也应该尽可能的减少开发成本,采用更加经济的技术设备,不能只是一味地追求更高级更复杂的设计
玩手机检测结果可视化:
2 Yolov5算法
4.1 简介
YOLO系列是基于深度学习的回归方法。该系列陆续诞生出YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5。YOLOv5算法,它是一种单阶段目标检测的算法,该算法可以根据落地要求灵活地通过chaneel和layer的控制因子来配置和调节模型,所以在比赛和落地中应用比较多。同时它有YOLOv5x、YOLOv5l、YOLOv5m、YOLOv5s四种模型。
具有以下优点:
- 在pytorch环境下编写;
- 可以很容易编译成ON⁃NX和Core ML;
- 运行速度很快,每秒可以达到140FPS的速度;
- 模型精度高;
- 集成了YOLOv3和YOLOv4的部分优秀特性,进行了推陈出新的改进。
2.2 相关技术
Mosaic数据增强
Mosaic数据增强技术采用了四张图片的随机缩放、随机剪裁、随机排布的方式对数据进行拼接,相比CutMix数据增强多用了两张图片。在目标识别过程中,要识别的目标有大目标、中等目标、小目标,并且三种目标的占比例不均衡,其中,小目标的数量是最多的,但是出现的频率很低,这种情况就会导致在bp时对小目标的优化不足,模型正确识别小目标的难度比识别中、大目标的难度要大很多,于是对于小目标来说很容易出现误检和漏检的情况。Mosaic数据增强技术做出改进后,上述的问题得到有效的解决。
该技术的优点是:
- 丰富了数据集,采用“三个随机”的方式对数据进行拼接丰富了检测的数据集,尤其是随机缩放增加了很多小目标,克服了小目标的不足,让网络的鲁棒性得到提高;
- 减少GPU的使用,在Mosaic增强训练时,四张图片拼接在一起,GPU可以直接计算四张图片的数据,让Mini-batch的大小减少了很多,这使得一个GPU就可以达到比较可观的效果。
自适应anchor
自适应anchor是check_anchors函数通过遗传算法与Kmeans迭代算出的最大可能召回率的anchor组合。在网络模型的训练过程中,网络在初始化的锚框的基础上输出预测框,然后与真实框groundtruth进行对比,计算两个框之间的差值,再根据差值进行反向更新,迭代网络参数,最后求出最佳的锚框值。自适应的anchor能够更好地配合网络训练,提高模型的精度,减少对anchor的设计难度,具有很好的实用性。
自适应图片缩放
为了提高模型的推理速度,YOLOv5提出自适应图片缩放,根据长宽比对图像进行缩放,并添加最少的黑边,减少计算量。该方法是用缩放后的长边减去短边再对32进行取余运算,求出padding。在训练时并没有采用缩减黑边的方法,该方法只是在测试模型推理的时候才使用,这样提高了目标检测的准确率和速度。
Focus结构
该结构采用切片操作,将特征切片成四份,每一份将当成下采样的特征,然后在channel维度进行concat。例如:原始6086083的数据图片,经过切片操作先变成30430412的特征图,再经过一次32个卷积核的卷积操作,变成30430432的特征图。
CSP结构
YOLOv5中的CSP[5]结构应用于两处,一处是CSP1_X结构应用于Backbone的主干网络中,另一处的CSP2_X结构应用于Neck中,用于加强网络的特征融合的能力。CSPNet主要从网络结构设计的角度解决推理中从计算量很大的问题。该结构的优点有:1)增强CNN的学习能力,使得模型在轻量化的同时保持较高的准确性;2)减低计算的瓶颈问题;3)减低内存的分险。
PFN+PAN结构
这个结构是FPN和PAN的联合。FPN是自顶向下的,将高层的特征信息通过上采样的方式进行传递融合,得到进行预测的特征图,而PAN正好与FPN的方向是相反的方向,它是自底向上地采取特征信息。两个结构各自从不同的主干层对不同的检测层进行参数聚合。两个结构的强强联合让得到的特征图的特征更加明显和清楚。
Bounding box的损失函数
Bounding box损失函数[6]增加了相交尺度的衡量方式,有效缓解了当两个框不相交和两个框大小完全相同的两种特殊情况。因为当预测框和目标框不相交时,IOU=0,无法反应两个框距离的远近的时候,此时的损失函数不可导;两个框大小完全相同,两个IOU也相同,IOU_LOSS无法区分以上两种特殊情况。
nms非极大值抑制
在目标检测过程的后续处理中,对于大量的目标框的筛选问题,通常会进行nms操作,以此来达到一个不错的效果。YO⁃LOv5算法同样采用了加权的nms操作。
3 数据集处理及实验
数据集准备
由于目前针对吸烟图片并没有现成的数据集,我们使用Python爬虫利用关键字在互联网上获得的图片数据,编写程序爬了1w张,筛选下来有近1000张可用,以及其他途径获取到的,暂时可用数据集有5k张,
深度学习图像标注软件众多,按照不同分类标准有多中类型,本文使用LabelImg单机标注软件进行标注。LabelImg是基于角点的标注方式产生边界框,对图片进行标注得到xml格式的标注文件,由于边界框对检测精度的影响较大因此采用手动标注,并没有使用自动标注软件。
考虑到有的朋友时间不足,博主提供了标注好的数据集和训练好的模型,需要请联系。
数据标注简介
通过pip指令即可安装
pip install labelimg
在命令行中输入labelimg即可打开
4 部分核心代码
# data/smoke.yaml# COCO 2017 dataset http://cocodataset.org# Download command: bash yolov5/data/get_coco2017.sh# Train command: python train.py --data ./data/coco.yaml# Dataset should be placed next to yolov5 folder:# /parent_folder# /coco# /yolov5# train and val datasets (image directory or *.txt file with image paths)
train: data\train.txt # 上面我们生成的train,根据自己的路径进行更改
val: data\test.txt # 上面我们生成的test#test: ../coco/test-dev2017.txt # 20k images for submission to https://competitions.codalab.org/competitions/20794# number of classes
nc:1#训练的类别# class names
names:['smoke']# Print classes# with open('data/coco.yaml') as f:# d = yaml.load(f, Loader=yaml.FullLoader) # dict# for i, x in enumerate(d['names']):# print(i, x)
# model/yolov5s.yaml# parameters
nc:1# number of classes
depth_multiple:0.33# model depth multiple
width_multiple:0.50# layer channel multiple# anchors
anchors:-[116,90,156,198,373,326]# P5/32-[30,61,62,45,59,119]# P4/16-[10,13,16,30,33,23]# P3/8# YOLOv5 backbone
backbone:# [from, number, module, args][[-1,1, Focus,[64,3]],# 0-P1/2[-1,1, Conv,[128,3,2]],# 1-P2/4[-1,3, BottleneckCSP,[128]],[-1,1, Conv,[256,3,2]],# 3-P3/8[-1,9, BottleneckCSP,[256]],[-1,1, Conv,[512,3,2]],# 5-P4/16[-1,9, BottleneckCSP,[512]],[-1,1, Conv,[1024,3,2]],# 7-P5/32[-1,1, SPP,[1024,[5,9,13]]],]# YOLOv5 head
head:[[-1,3, BottleneckCSP,[1024,False]],# 9[-1,1, Conv,[512,1,1]],[-1,1, nn.Upsample,[None,2,'nearest']],[[-1,6],1, Concat,[1]],# cat backbone P4[-1,3, BottleneckCSP,[512,False]],# 13[-1,1, Conv,[256,1,1]],[-1,1, nn.Upsample,[None,2,'nearest']],[[-1,4],1, Concat,[1]],# cat backbone P3[-1,3, BottleneckCSP,[256,False]],[-1,1, nn.Conv2d,[na *(nc +5),1,1]],# 18 (P3/8-small)[-2,1, Conv,[256,3,2]],[[-1,14],1, Concat,[1]],# cat head P4[-1,3, BottleneckCSP,[512,False]],[-1,1, nn.Conv2d,[na *(nc +5),1,1]],# 22 (P4/16-medium)[-2,1, Conv,[512,3,2]],[[-1,10],1, Concat,[1]],# cat head P5[-1,3, BottleneckCSP,[1024,False]],[-1,1, nn.Conv2d,[na *(nc +5),1,1]],# 26 (P5/32-large)[[],1, Detect,[nc, anchors]],# Detect(P5, P4, P3)]
# 训练部分主函数if __name__ =='__main__':
check_git_status()
parser = argparse.ArgumentParser()
parser.add_argument('--epochs',type=int, default=300)
parser.add_argument('--batch-size',type=int, default=16)
parser.add_argument('--cfg',type=str, default='models/yolov5s.yaml',help='*.cfg path')
parser.add_argument('--data',type=str, default='data/smoke.yaml',help='*.data path')
parser.add_argument('--img-size', nargs='+',type=int, default=[640,640],help='train,test sizes')
parser.add_argument('--rect', action='store_true',help='rectangular training')
parser.add_argument('--resume', action='store_true',help='resume training from last.pt')
parser.add_argument('--nosave', action='store_true',help='only save final checkpoint')
parser.add_argument('--notest', action='store_true',help='only test final epoch')
parser.add_argument('--noautoanchor', action='store_true',help='disable autoanchor check')
parser.add_argument('--evolve', action='store_true',help='evolve hyperparameters')
parser.add_argument('--bucket',type=str, default='',help='gsutil bucket')
parser.add_argument('--cache-images', action='store_true',help='cache images for faster training')
parser.add_argument('--weights',type=str, default='',help='initial weights path')
parser.add_argument('--name', default='',help='renames results.txt to results_name.txt if supplied')
parser.add_argument('--device', default='0',help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--adam', action='store_true',help='use adam optimizer')
parser.add_argument('--multi-scale', action='store_true',help='vary img-size +/- 50%')
parser.add_argument('--single-cls', action='store_true',help='train as single-class dataset')
opt = parser.parse_args()
opt.weights = last if opt.resume else opt.weights
opt.cfg = check_file(opt.cfg)# check file
opt.data = check_file(opt.data)# check fileprint(opt)
opt.img_size.extend([opt.img_size[-1]]*(2-len(opt.img_size)))# extend to 2 sizes (train, test)
device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size)if device.type=='cpu':
mixed_precision =False# Trainifnot opt.evolve:
tb_writer = SummaryWriter(comment=opt.name)print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/')
train(hyp)# Evolve hyperparameters (optional)else:
tb_writer =None
opt.notest, opt.nosave =True,True# only test/save final epochif opt.bucket:
os.system('gsutil cp gs://%s/evolve.txt .'% opt.bucket)# download evolve.txt if existsfor _ inrange(10):# generations to evolveif os.path.exists('evolve.txt'):# if evolve.txt exists: select best hyps and mutate# Select parent(s)
parent ='single'# parent selection method: 'single' or 'weighted'
x = np.loadtxt('evolve.txt', ndmin=2)
n =min(5,len(x))# number of previous results to consider
x = x[np.argsort(-fitness(x))][:n]# top n mutations
w = fitness(x)- fitness(x).min()# weightsif parent =='single'orlen(x)==1:# x = x[random.randint(0, n - 1)] # random selection
x = x[random.choices(range(n), weights=w)[0]]# weighted selectionelif parent =='weighted':
x =(x * w.reshape(n,1)).sum(0)/ w.sum()# weighted combination# Mutate
mp, s =0.9,0.2# mutation probability, sigma
npr = np.random
npr.seed(int(time.time()))
g = np.array([1,1,1,1,1,1,1,0,.1,1,0,1,1,1,1,1,1,1])# gains
ng =len(g)
v = np.ones(ng)whileall(v ==1):# mutate until a change occurs (prevent duplicates)
v =(g *(npr.random(ng)< mp)* npr.randn(ng)* npr.random()* s +1).clip(0.3,3.0)for i, k inenumerate(hyp.keys()):# plt.hist(v.ravel(), 300)
hyp[k]= x[i +7]* v[i]# mutate# Clip to limits
keys =['lr0','iou_t','momentum','weight_decay','hsv_s','hsv_v','translate','scale','fl_gamma']
limits =[(1e-5,1e-2),(0.00,0.70),(0.60,0.98),(0,0.001),(0,.9),(0,.9),(0,.9),(0,.9),(0,3)]for k, v inzip(keys, limits):
hyp[k]= np.clip(hyp[k], v[0], v[1])# Train mutation
results = train(hyp.copy())# Write mutation results
print_mutation(hyp, results, opt.bucket)# Plot results# plot_evolution_results(hyp)
项目运行效果:
毕业设计 深度学习的驾驶行为检测(玩手机)
最后
🧿 项目分享:见文末!
版权归原作者 iuerfee 所有, 如有侵权,请联系我们删除。