chainer-目标检测-SSD


前言

  通俗的讲就是在一张图像里边找感兴趣的物体,并且标出物体在图像上的位置,在后续很多应用中,都需要目标检测做初步识别结构后做处理,比如目标跟踪,检测数量,检测有无等。


一、数据集的准备

  首先我是用的是halcon数据集里边的药片,去了前边的100张做标注,后面的300张做测试,其中100张里边选择90张做训练集,10张做验证集。

1.标注工具的安装

pip install labelimg

进入cmd,输入labelimg,会出现如图的标注工具:
在这里插入图片描述

2.数据集的准备

首先我们先创建3个文件夹,如图:
在这里插入图片描述
DataImage:100张需要标注的图像
DataLabel:空文件夹,主要是存放标注文件,这个在labelimg中生成标注文件
test:存放剩下的300张图片,不需要标注
DataImage目录下和test目录的存放样子是这样的(以DataImage为例):
在这里插入图片描述

3.标注数据

  首先我们需要在labelimg中设置图像路径和标签存放路径,如图:
在这里插入图片描述
  然后先记住快捷键:w:开始编辑,a:上一张,d:下一张。这个工具只需要这三个快捷键即可完成工作。
  开始标注工作,首先按下键盘w,这个时候进入编辑框框的模式,然后在图像上绘制框框,输入标签(框框属于什么类别),即可完成物体1的标注,一张物体可以多个标注和多个类别,但是切记不可摸棱两可,比如这张图像对于某物体标注了,另一张图像如果出现同样的就需要标注,或者标签类别不可多个,比如这个图象A物体标注为A标签,下张图的A物体标出成了B标签,最终的效果如图:
在这里插入图片描述
最后标注完成会在DataLabel中看到标注文件,json格式:
在这里插入图片描述

4.解释xml文件的内容

在这里插入图片描述
xml标签文件如图,我们用到的就只有object对象,对其进行解析即可。

二、基于chainer的目标检测构建-SSD

1.引入第三方标准库

import sys,os,warnings,json,time,cv2,random,base64
sys.path.append('.')
os.environ["CHAINER_TYPE_CHECK"] = "0"
warnings.filterwarnings("ignore")
from PIL import Image,ImageFont,ImageDraw
import numpy as np
import chainer
import chainer.functions as F
from chainer import optimizers
from chainer.training import StandardUpdater, extensions
from chainer.datasets import TransformDataset

2.数据加载器

  读取数据文件夹,这里为的是加载每一张图像以及对应的xml文件,并且解析成自定义格式即可,如图:
读取数据文件夹及内容
  这里解释一下,IMGDir代表存放图像文件的路径,XMLDir代表存放标签文件的路径,train_split=0.9代表训练集和验证集9:1


  数据格式使用yolo格式,在每次迭代的过程中才开始加载图像以及xml文件,节省内存,如图:
在这里插入图片描述
这里的输入data_list是前边CreateDataList_Detection函数的返回,分为训练和验证集合,这里是一个迭代器


下面这里主要是做一些数据增强的操作:
在这里插入图片描述
此步骤在训练的时候不是必要的。

3.模型构建

本次使用的SSD目标检测算法,我们先看一张图:
在这里插入图片描述
  我们这里的SSD目标检测,所使用的主干网络是VGG,因此我们根据这个结构对目标检测SSD进行构建,从图像上可知,SSD从vgg的conv4_3开始,做一些修改,增加了额一些卷积层,也就是后面的往下进行图像的压缩,最后到了11256,可以对输入的图片进行不断的特征提取,以上就是SSD的特征提取网络部分;
  其次就是用先验框对下边进行检测,如:
  从3838512,下面的每个格子(38*38),每个格子有4个先验框,因此下面就会有5776个先验框,以此类推,一张图像检测下来之后一共会有8732个先验框,这里的框代表是:里面我们所需要的物体,我们需要对其进行选择。
  下面NMS极大值抑制,可以最终取得物体。
网络输出:
一个是回归系数结果:8732 x 4 调整参数 ,这里的4代表的位置
一个是分类系数结果:8732 x (num_classes+1),代表框属于哪一个类别,以及是否有物体,最后使用softmax得出概率。

4.模型代码

首先SSD分为SSD300以及SSD512,如图:
在这里插入图片描述
以300为例子,以下部分为主干网络的特征提取,这里分为2个,一个是标准的VGG网络结构,一个是进入SSD的后续的继续特征提取部分:
在这里插入图片描述
在这里插入图片描述
SSD的body部分:
在这里插入图片描述

5.整体代码构建

1.chainer初始化

self.image_size = image_size if (image_size == 300 or image_size == 512) else 300
if USEGPU =='-1':
     self.gpu_devices = -1
 else:
     self.gpu_devices = int(USEGPU)
     chainer.cuda.get_device_from_id(self.gpu_devices).use()

2.数据集以及模型构建

train_data_list, self.val_data_list, self.classes_names = CreateDataList_Detection(os.path.join(DataDir,'DataImage'),os.path.join(DataDir,'DataLabel'),train_split)
        
self.model = get_ssd(self.image_size,classes_names=self.classes_names,alpha=self.alpha)
self.train_chain = MultiboxTrainChain(self.model)
if self.gpu_devices>=0:
    self.model.to_gpu()
        
train = TransformDataset(VOCBboxDataset(data_list=train_data_list,classes_names=self.classes_names),Detection_Transform(self.model.coder, self.model.insize, self.model.mean))
self.train_iter = chainer.iterators.SerialIterator(train, self.batch_size)
test = VOCBboxDataset(data_list=self.val_data_list,classes_names=self.classes_names)
self.test_iter = chainer.iterators.SerialIterator(test, self.batch_size, repeat=False, shuffle=False)

3.模型训练

这里与分类网络一样需要先理解chainer的工作原理:
在这里插入图片描述  从图中我们可以了解到,首先我们需要设置一个Trainer,这个可以理解为一个大大的训练板块,然后做一个Updater,这个从图中可以看出是把训练的数据迭代器和优化器链接到更新器中,实现对模型的正向反向传播,更新模型参数。然后还有就是Extensions,此处的功能是在训练的中途进行操作可以随时做一些回调(描述可能不太对),比如做一些模型评估,修改学习率,可视化验证集等操作。
  因此我们只需要严格按照此图建设训练步骤基本上没有什么大问题,下面一步一步设置

设置优化器:

optimizer = optimizers.MomentumSGD(lr=learning_rate, momentum=0.9)
optimizer.setup(self.train_chain)
optimizer.add_hook(chainer.optimizer.WeightDecay(rate=0.0005))

设置update和trainer:

updater = StandardUpdater(self.train_iter, optimizer, device=self.gpu_devices)
trainer = chainer.training.Trainer(updater, (TrainNum, 'epoch'), out=ModelPath)

Extensions功能设置:

# 修改学习率
trainer.extend(
    extensions.ExponentialShift('lr', 0.9, init=learning_rate),
    trigger=chainer.training.triggers.ManualScheduleTrigger([50,80,150,200,280,350], 'epoch'))
# 每过一次迭代验证集跑一次
trainer.extend(
    DetectionVOCEvaluator(self.test_iter, self.train_chain.model, use_07_metric=True, label_names=self.classes_names),
    trigger=chainer.training.triggers.ManualScheduleTrigger([each for each in range(1,TrainNum)], 'epoch'))
# 可视化验证集效果
trainer.extend(Detection_VIS(
    self.model, 
    self.val_data_list,
    self.classes_names, image_size=self.image_size,
    trigger=chainer.training.triggers.ManualScheduleTrigger([each for each in range(1,TrainNum)], 'epoch'), 
    device=self.gpu_devices,ModelPath=ModelPath,predict_score=0.5
))
# 模型保存
trainer.extend(
    extensions.snapshot_object(self.model, 'Ctu_best_Model.npz'),
    trigger=chainer.training.triggers.MaxValueTrigger('validation/main/map',trigger=chainer.training.triggers.ManualScheduleTrigger([each for each in range(1,TrainNum)], 'epoch')),
)
# 日志及文件输出
log_interval = 0.1, 'epoch' 
trainer.extend(chainer.training.extensions.LogReport(filename='ctu_log.json',trigger=log_interval))
trainer.extend(chainer.training.extensions.observe_lr(), trigger=log_interval)
trainer.extend(extensions.dump_graph("main/loss", filename='ctu_net.net'))

最后配置完之后只需要一行代码即可开始训练

trainer.run()

6、模型预测

  模型预测主要还是输入为opencv格式,在数据预处理之前与前面数据加载时做的操作一致就行,直接上代码:
在这里插入图片描述

三、训练预测代码

  因为本代码是以对象形式编写的,因此调用起来也是很方便的,如下显示:

# 训练代码
ctu = Ctu_Detection(USEGPU='0',image_size=300)
ctu.InitModel(r'/home/ctu/Ctu_Project/DL_Project/DataDir/DataSet_Detection_VOC',train_split=0.99,alpha=1,batch_size = 1,Pre_Model=None)
ctu.train(TrainNum=150,learning_rate=0.0001, ModelPath='result_Model')

# 预测代码
ctu = Ctu_Detection(USEGPU='0')
ctu.LoadModel('./Model/result_Model_DetYP')
cv2.namedWindow("result", 0)
cv2.resizeWindow("result", 640, 480)
for root, dirs, files in os.walk(r'/home/ctu/Ctu_Project/DL_Project/DataDir/DataSet_Detection_YaoPian/DataImage'):
    for f in files:
        img_cv = ctu.read_image(os.path.join(root, f))
        if img_cv is None:
            continue
        result = ctu.predict_simple(predict_cvs,0.0)
        print(result['time'])
        for each_bbox in result['bboxes_result']:
            print(each_bbox)
        cv2.imshow("result", result['imges_result'])
        cv2.waitKey()

四、效果

训练时的可视化,数据是验证集数据(没有参与过训练的数据),左边代表检测的效果,右边为标注的效果图,可以清晰看到对比,如图:
在这里插入图片描述
在这里插入图片描述

总结

本文章主要是基于chainer的目标检测SSD的基本实现思路和步骤

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux创始人LinusTorvalds有一句名言:Talk is cheap, Show me the code.(冗谈不够,放码过来!)。 代码阅读是从入门到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。  YOLOv3是一种基于深度学习的端到端实时目标检测方法,以速度快见长。YOLOv3的实现Darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。  本课程将解析YOLOv3的实现原理和源码,具体内容包括: YOLO目标检测原理  神经网络及Darknet的C语言实现,尤其是反向传播的梯度求解和误差计算 代码阅读工具及方法 深度学习计算的利器:BLAS和GEMM GPU的CUDA编程方法及在Darknet的应用 YOLOv3的程序流程及各层的源码解析本课程将提供注释后的Darknet的源码程序文件。  除本课程《YOLOv3目标检测:原理与源码解析》外,本人推出了有关YOLOv3目标检测的系列课程,包括:   《YOLOv3目标检测实战:训练自己的数据集》  《YOLOv3目标检测实战:交通标志识别》  《YOLOv3目标检测:原理与源码解析》  《YOLOv3目标检测:网络模型改进方法》 建议先学习课程《YOLOv3目标检测实战:训练自己的数据集》或课程《YOLOv3目标检测实战:交通标志识别》,对YOLOv3的使用方法了解以后再学习本课程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的广东仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值