目标检测:YOLO V3 案例

1.数据获取

根据要实现的业务场景,需要收集⼤量的图像数据,⼀般来说包含两⼤来 源,⼀部分是⽹络数据,可以是开源数据,也可以通过百度、Google图⽚ 爬⾍得到,另⼀部分是⽤户场景的视频录像,这⼀部分的数据量会更⼤。 对于开源数据我们不需要进⾏标注,⽽爬取的数据和视频录像需要进⾏标 注,这时我们可以使⽤开源⼯具labelImg进⾏标注。

2.将数据转换为TFRecord⽂件

对于中⼤数据集来说,Google官⽅推荐先将数据集转化为TFRecord数据, 这样可加快在数据读取, 预处理中的速度。接下来我们就将VOC数据集转 换为Records格式。

from dataset.vocdata_tfrecord import load_labels,write_to_tfrecord
import os

# 指定要写入的数据集路径
datapath = './dataset/VOCdevkit/VOC2007'

# 获取所有的XML标注文件
all_xml = load_labels(datapath,'train')

# 指定tfrecord的存储位置
tfrecord_path = './dataset/voc_train.tfrecords_1'

# 获取图像的路径
img_path = os.path.join(datapath,'JPEGImages')

# 将数据写入到tfrecord文件中
write_to_tfrecord(all_xml,tfrecord_path,img_path)

从TFrecord⽂ 件中将数据读取出来

from dataset.get_tfdata import getdata

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

datasets = getdata('dataset/voc_train.tfrecords_1')

# 1.获取类别信息
from utils.config_utils import read_class_names
classes = read_class_names('config/classname')

# 2.创建画布
plt.figure(figsize=(15,10))
# 3.获取数据遍历
i = 0
for image,width,height,boxes,boxes_category in datasets.take(3):
    # 4.划分不同的坐标轴subplot()
    plt.subplot(1,3,i+1)
    # 5.显示图像:plt.imshow()
    plt.imshow(image)
    # 6.显示box,遍历所有的bbox,rectange进行绘制
    ax = plt.gca()
    for j in range(boxes.shape[0]):
        rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
        ax.add_patch(rect)
        # 7.显示类别
        label_id = boxes_category[j]
        label = classes.get(label_id.numpy())
        ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
    i+=1
plt.show()

 

3. 数据处理

yoloV3模型的输⼊图像的⼤⼩是32的倍数,所以我们需要对图像进⾏处 理。在这⾥我们将图像的尺度调整为416x416的⼤⼩,为了保持⻓宽⽐, 我将四周为0的像素以灰度值128进⾏填充。

from dataset.preprocess import preprocess

# 2.创建画布
plt.figure(figsize=(15,10))
# 3.获取数据遍历
i = 0
for image,width,height,boxes,boxes_category in datasets.take(3):
    # 进行数据处理
    image,boxes = preprocess(image,boxes)
    # 4.划分不同的坐标轴subplot()
    plt.subplot(1,3,i+1)
    # 5.显示图像:plt.imshow()
    plt.imshow(image[0])
    # 6.显示box,遍历所有的bbox,rectange进行绘制
    ax = plt.gca()
    for j in range(boxes.shape[0]):
        rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
        ax.add_patch(rect)
        # 7.显示类别
        label_id = boxes_category[j]
        label = classes.get(label_id.numpy())
        ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
    i+=1
plt.show()

4.模型构建

yoloV3的模型结构如下所示:整个v3结构⾥⾯,没有池化层和全连接层, ⽹络的下采样是通过设置卷积的stride为2来达到的,每当通过这个卷积层 之后图像的尺⼨就会减⼩到⼀半。

在构建⽹络时,使⽤model.yoloV3来进⾏构建: 

# 导⼊⼯具包
from model.yoloV3 import YOLOv3 
# 模型实例化:指定输⼊图像的⼤⼩,和类别数 
yolov3 = YOLOv3((416,416,3),80) 
# 获取模型架构 
yolov3.summary() 

5.模型训练 

5.1损失函数的计算

# 导⼊所需的⼯具包
from core.loss import Loss 
# 实例化 
yolov3_loss = Loss((416,416,3),80) 

# 损失输⼊ 
yolov3_loss.inputs 

# 损失输出 
yolov3_loss.outputs 

5.2 正负样本的设定

正样本:⾸先计算⽬标中⼼点落在哪个grid上,然后计算这个grid对 应的3个先验框(anchor)和⽬标真实位置的IOU值,取IOU值最⼤的 先验框和⽬标匹配。那么该anchor 就负责预测这个⽬标,那这个 anchor就作为正样本,将其置信度设为1,其他的⽬标值根据标注信 息设置。

负样本:所有不是正样本的anchor都是负样本,将其置信度设为0, 参与损失计算,其它的值不参与损失计算,默认为0。

对于每⼀个anchor我们都要4+1+80维的⽬标值,其中前4维是坐标值,正 样本是GT的bbox框的值,第5维是置信度,正样本设置为1,负样本设置 为0,最后的80是类别数,正样本对应的类别设置为1,其余为0,若使⽤ voc数据集类别数是20 。

from core.bbox_target import bbox_to_target

# 获取数据进行目标值设置
for image,width,height,boxes,labels in datasets.take(1):
    # 获取目标值
    label1,label2,label3 = bbox_to_target(boxes,labels,num_classes=20)

正样本的anchor的置信度为1,所以我们通过置信度为1来获取正样本 

import tensorflow as tf
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle

# 获取正样本索引
tf.where(tf.equal(label2[...,4],1))

# 1.获取类别信息
from utils.config_utils import read_class_names
classes = read_class_names('config/classname')
# 2.创建画布
plt.figure(figsize=(15,10))
# 3.获取数据遍历
for image,width,height,boxes,boxes_category in datasets.take(1):
    # 4.显示图像:plt.imshow()
    plt.imshow(image)
    # 5.显示box,遍历所有的bbox,rectange进行绘制
    ax = plt.gca()
    for j in range(boxes.shape[0]):
        rect = Rectangle((boxes[j, 0], boxes[j, 1]), boxes[j, 2] -boxes[j, 0], boxes[j, 3]-boxes[j, 1], color='r', fill=False)
        ax.add_patch(rect)
        # 6.显示类别
        label_id = boxes_category[j]
        label = classes.get(label_id.numpy())
        ax.text(boxes[j, 0], boxes[j, 1] + 8, label,color='w', size=11, backgroundcolor="none")
    # 7.绘制正样本的anchor的目标值
    anchor = label2[25, 25,2,0:4].numpy()
    rect2 = Rectangle((anchor[0]-anchor[2]/2, anchor[1]-anchor[3]/2), anchor[2], anchor[3],color='g', fill=False)
    ax.add_patch(rect2)
plt.show()

 5.3 模型训练

前⾯我们已经详细介绍了⽹络模型架构,在⽹络预测前我们需要对⽹络进 ⾏训练,接下来使⽤端到端的⽅式进⾏模型训练,基本步骤是:①加载数据集:我们在这⾥使⽤VOC数据集,所以需要从TFrecord⽂件 中加载VOC数据集②模型实例化:加载yoloV3模型和损失函数的实现 ③模型训练:计算损失函数,使⽤反向传播算法对模型进⾏训练。

# 5.3.1 获取数据集
# 导⼊
from dataset.preprocess import dataset 
# 设置batch_size 
batch_size=1
# 获取训练集数据,并指定batchsize,返回训练集数据 
trainset = dataset('dataset/voc_train.tfrecords',batch_size)

# 5.3.2 加载模型
# V3模型的实例化,指定输⼊图像的⼤⼩,即⽬标检测的类别个数 
yolov3 = YOLOv3((416, 416, 3,), 20) 
yolov3_loss = Loss((416,416,3), 20) 

# 5.3.3 模型训练
# 1.定义优化器
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1,momentum=0.9)
# 2.设置epoch
for epoch in range(2):
    for (batch,inputs) in enumerate(trainset):
        images,labels = inputs
        # 3.计算损失函数进行参数更新
        # 3.1 定义上下文环境
        with tf.GradientTape() as tape:            
            # 3.2 将图像送入网络中
            outputs = yolov3(images)
            # 3.3 计算损失函数
            loss = yolov3_loss([*outputs, *labels])
            # 3.4 计算梯度
            grads = tape.gradient(loss, yolov3.trainable_variables)
            # 3.5 梯度更新
            optimizer.apply_gradients(zip(grads, yolov3.trainable_variables))
            print(loss)
yolov3.save('yolov3.h5')

 6.模型预测

我们使⽤训练好的模型进⾏预测,在这⾥我们通过yoloV3模型进⾏预测, 并将预测结果绘制在图像上。⾸先导⼊⼯具包,预训练好的模型是使⽤ coco数据集进⾏训练的,所以指定相应的类别信息:

# 读取图像,绘图的工具包
import cv2
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
# yoloV3的预测器
from core.predicter import Predictor

# coco数据集中的类别信息
classes = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 
           'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 
           'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog',
           'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe',
           'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 
           'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 
           'skateboard', 'surfboard','tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 
           'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 
           'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 
           'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 
           'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 
           'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']

# 1.读取要进行目标检测的图像
img = cv2.imread("image.jpg")
# 2.实例化,并加载预训练模型
predictor = Predictor(class_num=80, yolov3="weights/yolov3.h5")
# 3.获取检测结果
boundings = predictor.predict(img)
# 4.将检测结果绘制在图像上
# 4.1 绘制图像
plt.imshow(img[:,:,::-1])
# 4.2 绘制检测结果
# 获取坐标区域
ax = plt.gca()
# 4.2 遍历检测框,将检测框绘制在图像上
for bounding in boundings:
    # 绘制框
    rect = Rectangle((bounding[0].numpy(), bounding[1].numpy()), bounding[2].numpy(
    ) - bounding[0].numpy(), bounding[3].numpy()-bounding[1].numpy(), color='r', fill=False)
    # 将框显示在图像上
    ax.add_patch(rect)
    # 显示类别信息
    # 获取类别信息的id
    label_id = bounding[5].numpy().astype('int32')
    # 获取类别
    label = classes[label_id]
    # 将标注信息添加在图像上
    ax.text(bounding[0].numpy(), bounding[1].numpy() + 8,
            label, color='w', size=11, backgroundcolor="none")

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值