【华为云】手把手教你用华为云Modelarts基于YOLO V3算法实现物体检测(附模型源代码)

一、华为云平台简介

华为云用在线的方式将华为30多年在ICT基础设施领域的技术积累和产品解决方案开放给客户,致力于提供稳定可靠、安全可信、可持续创新的云服务,做智能世界的“黑土地”,推进实现“用得起、用得好、用得放心”的普惠AI。华为云作为底座,为华为全栈全场景AI战略提供强大的算力平台和更易用的开发平台。在这里插入图片描述
ModelArts是华为云产品中面向开发者的一站式AI开发平台,为机器学习与深度学习提供海量数据预处理及半自动化标注、大规模分布式Training、自动化模型生成,及端-边-云模型按需部署能力,帮助用户快速创建和部署模型,管理全周期AI工作流。
在这里插入图片描述

二、用华为云Modelarts基于YOLO V3算法实现物体检测(文章最后附源码)

在Modelarts中,可以为我们提供强大的算力和平台环境,省去了我们需要在本地配置安装环境的繁杂过程,也解决了因我们自己电脑配置不够而影响计算速度或者是无法开展深度学习实验的瓶颈,为学习者提供了进行手把手实验的可能,而不仅仅是停留在理论层面。

我们将聚焦于用YOLO V3算法实现物体检测,在ModelArts的Notebook开发环境中实现用YOLO V3算法构建一个物体检测的神经网络模型,并在该环境中实现对物体检测神经网络模型的训练与测试,最终达到实现物体检测的实验目的。
在这里插入图片描述

三、基于YOLO V3算法实现物体检测实验流程

1.准备实验环境与创建开发环境
2.下载数据与训练代码
3.准备数据
4.Yolo_v3模型训练
5.Yolo_v3模型测试

3.1进入ModelArts

进入华为云Modelarts主页,输入自己的账号密码。
在这里插入图片描述
点击进入“进入控制台
在这里插入图片描述
在左侧开发环境处,点击Notebook:

点击“创建”,填写配置信息:
名称:自定义(此处我设置的是 notebook-object_detection_yolo)
工作环境:Python3
资源池:公共资源池
类型:GPU
规格:体验规格GPU(这样就不要花费)
存储配置:云硬盘
在这里插入图片描述
按“下一步”确认信息无误,点击“提交”即可:
可以看到自己配置的环境:
在这里插入图片描述
至此,我们所需要的环境都已经配置完成。

3.2 进入Notebook进行开发

点击进入创建的 notebook-object_detection_yolo中,给该文档改名为notebook_yolo_v3。
点击选择右侧的“New”,点击选择TensorFlow 1.13.1开发环境后,进入下面的页面:
在这里插入图片描述
对notebook环境进行测试,输入 print(‘hello world!’)
能输出,则说明环境没问题,可以继续开发。
在这里插入图片描述

3.3 数据和代码下载

有很多开源的数据集可以用来进行目标检测任务的训练,如COCO数据集,PASCAL VOC数据集,BDD100K等,可以根据不同的需求和偏好进行选择
本文的操作实验将使用PASCAL VOC2007数据集进行模型构建

数据集:
Notebook案例: COCO数据集中抽取的200+张图片及标注信息
ModelArts预置算法案例:PASCAL VOC2007数据集

在notebook中,运行下面代码,进行数据和代码的下载和解压
本案例使用coco数据,共80个类别。

from modelarts.session import Session
sess = Session()

if sess.region_name == 'cn-north-1':
    bucket_path="modelarts-labs/notebook/DL_object_detection_yolo/yolov3.tar.gz"
elif sess.region_name == 'cn-north-4':
    bucket_path="modelarts-labs-bj4/notebook/DL_object_detection_yolo/yolov3.tar.gz"
else:
    print("请更换地区到北京一或北京四")

sess.download_data(bucket_path=bucket_path, path="./yolov3.tar.gz")

# 解压文件
!tar -xf ./yolov3.tar.gz

# 清理压缩包
!rm -r ./yolov3.tar.gz

下载后的代码和数据保存在了之前设置的云硬盘(EVS)中。
这里是已经下载好的文件目录:
在这里插入图片描述

3.4 准备数据

运行以下代码,进行文件路径定义:

from train import get_classes, get_anchors
# 数据文件路径
data_path = "./coco/coco_data"
# coco类型定义文件存储位置
classes_path = './model_data/coco_classes.txt'
# coco数据anchor值文件存储位置
anchors_path = './model_data/yolo_anchors.txt'
# coco数据标注信息文件存储位置
annotation_path = './coco/coco_train.txt'
# 预训练权重文件存储位置
weights_path = "./model_data/yolo.h5"
# 模型文件存储位置
save_path = "./result/models/"

classes = get_classes(classes_path)
anchors = get_anchors(anchors_path)
# 获取类型数量和anchor数量变量
num_classes = len(classes)
num_anchors = len(anchors)

读取标注数据:

import numpy as np

# 训练集与验证集划分比例
val_split = 0.1
with open(annotation_path) as f:
    lines = f.readlines()
np.random.seed(10101)
np.random.shuffle(lines)
np.random.seed(None)
num_val = int(len(lines)*val_split)
num_train = len(lines) - num_val

数据读取函数,构建数据生成器。每次读取一个批次的数据至内存训练,并做数据增强。

def data_generator(annotation_lines, batch_size, input_shape, data_path,anchors, num_classes):
    n = len(annotation_lines)
    i = 0
    while True:
        image_data = []
        box_data = []
        for b in range(batch_size):
            if i==0:
                np.random.shuffle(annotation_lines)
            image, box = get_random_data(annotation_lines[i], input_shape, data_path,random=True) # 随机挑选一个批次的数据
            image_data.append(image)
            box_data.append(box)
            i = (i+1) % n
        image_data = np.array(image_data)
        box_data = np.array(box_data)
        y_true = preprocess_true_boxes(box_data, input_shape, anchors, num_classes) # 对标注框预处理,过滤异常标注框
        yield [image_data, *y_true], np.zeros(batch_size)

def data_generator_wrapper(annotation_lines, batch_size, input_shape, data_path,anchors, num_classes):
    n = len(annotation_lines)
    if n==0 or batch_size<=0: return None
    return data_generator(annotation_lines, batch_size, input_shape, data_path,anchors, num_classes)

3.5 Yolov3模型训练

使用Keras深度学习框架搭建YOLOv3神经网络。
可以进入相应的文件夹路径查看源码实现。
在这里插入图片描述
构建神经网络
可以在./yolo3/model.py文件中查看细节

import keras.backend as K
from yolo3.model import preprocess_true_boxes, yolo_body, yolo_loss
from keras.layers import Input, Lambda
from keras.models import Model
# 初始化session
K.clear_session()

# 图像输入尺寸
input_shape = (416, 416)
image_input = Input(shape=(None, None, 3))
h, w = input_shape
# 设置多尺度检测的下采样尺寸
y_true = [Input(shape=(h//{0:32, 1:16, 2:8}[l], w//{0:32, 1:16, 2:8}[l], num_anchors//3, num_classes+5)) 
          for l in range(3)]

# 构建YOLO模型结构
model_body = yolo_body(image_input, num_anchors//3, num_classes)

# 将YOLO权重文件加载进来,如果希望不加载预训练权重,从头开始训练的话,可以删除这句代码
model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)

# 定义YOLO损失函数
model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',
    arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.5})([*model_body.output, *y_true])

# 构建Model,为训练做准备
model = Model([model_body.input, *y_true], model_loss)

可通过如下代码,打印模型各层结构,带您了解模型细节:

# 打印模型各层结构
model.summary()

输出各层模型如下:
在这里插入图片描述
训练回调函数定义

from keras.callbacks import ReduceLROnPlateau, EarlyStopping

# 定义回调方法
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1) # 学习率衰减策略
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1) # 早停策略

开始训练模型

from keras.optimizers import Adam
from yolo3.utils import get_random_data 

# 设置所有的层可训练
for i in range(len(model.layers)):
    model.layers[i].trainable = True
    
# 选择Adam优化器,设置学习率
learning_rate = 1e-4
model.compile(optimizer=Adam(lr=learning_rate), loss={'yolo_loss': lambda y_true, y_pred: y_pred}) 

# 设置批大小和训练轮数
batch_size = 16
max_epochs = 2
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
# 开始训练
model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, data_path,anchors, num_classes),
    steps_per_epoch=max(1, num_train//batch_size),
    validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, data_path,anchors, num_classes),
    validation_steps=max(1, num_val//batch_size),
    epochs=max_epochs,
    initial_epoch=0,
    callbacks=[reduce_lr, early_stopping])

在这里,如果你对该模型有一定了解,你可以自己优化调参。
为了演示,我只进行了两个轮次迭代,通过训练集的loss和验证集的loss来观察模型的训练情况,你也可以自己来设置训练结束的规则,最简单暴力的就是给定迭代的轮次。结果如下:
在这里插入图片描述
保存模型

import os
os.makedirs(save_path)
# 保存模型
model.save_weights(os.path.join(save_path, 'trained_weights_final.h5'))

至此,我们模型训练部分已经完成。

3.6 模型测试

打开一张测试图片

from PIL import Image
import numpy as np
# 测试文件路径
test_file_path = './test.jpg'
# 打开测试文件
image = Image.open(test_file_path)
image_ori = np.array(image)
image_ori.shape

原图片shape:(640, 481, 3)
继续输入“image”可看到打开的是哪张图片:
在这里插入图片描述

图片预处理

from yolo3.utils import letterbox_image

new_image_size = (image.width - (image.width % 32), image.height - (image.height % 32))
boxed_image = letterbox_image(image, new_image_size)
image_data = np.array(boxed_image, dtype='float32')
image_data /= 255.
image_data = np.expand_dims(image_data, 0)
image_data.shape

处理后的图片shape:(1, 640, 480, 3)

import keras.backend as K
sess = K.get_session()

构建模型

from yolo3.model import yolo_body
from keras.layers import Input
# coco数据anchor值文件存储位置
anchor_path = "./model_data/yolo_anchors.txt"
with open(anchor_path) as f:
    anchors = f.readline()
anchors = [float(x) for x in anchors.split(',')]
anchors = np.array(anchors).reshape(-1, 2)
yolo_model = yolo_body(Input(shape=(None,None,3)), len(anchors)//3, num_classes)

加载模型权重,或将模型路径替换成上一步训练得出的模型路径

# 模型权重存储路径
weights_path = "./model_data/yolo.h5"
yolo_model.load_weights(weights_path)

定义IOU以及score:

IOU: 将交并比大于IOU的边界框作为冗余框去除
score:将预测分数大于score的边界框筛选出来

iou = 0.45
score = 0.8

构建输出[boxes, scores, classes]

from yolo3.model import yolo_eval
input_image_shape = K.placeholder(shape=(2, ))
boxes, scores, classes = yolo_eval(
    yolo_model.output, 
    anchors,
    num_classes,
    input_image_shape,
    score_threshold=score, 
    iou_threshold=iou)

3.7 进行预测

out_boxes, out_scores, out_classes = sess.run(
    [boxes, scores, classes],
    feed_dict={
        yolo_model.input: image_data,
        input_image_shape: [image.size[1], image.size[0]],
        K.learning_phase(): 0
    })
class_coco = get_classes(classes_path)
out_coco = []
for i in out_classes:
    out_coco.append(class_coco[i])
print(out_boxes)
print(out_scores)
print(out_coco)

运行后,可以得到[boxes, scores, classes]如下输出:
在这里插入图片描述

3.8 将预测结果绘制在图片上

将在图片中检测到的结果,进行可视化,在图片中标示出来:

from PIL import Image, ImageFont, ImageDraw

font = ImageFont.truetype(font='font/FiraMono-Medium.otf',
                    size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))

thickness = (image.size[0] + image.size[1]) // 300

for i, c in reversed(list(enumerate(out_coco))):
    predicted_class = c
    box = out_boxes[i]
    score = out_scores[i]

    label = '{} {:.2f}'.format(predicted_class, score)
    draw = ImageDraw.Draw(image)
    label_size = draw.textsize(label, font)

    top, left, bottom, right = box
    top = max(0, np.floor(top + 0.5).astype('int32'))
    left = max(0, np.floor(left + 0.5).astype('int32'))
    bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
    right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
    print(label, (left, top), (right, bottom))

    if top - label_size[1] >= 0:
        text_origin = np.array([left, top - label_size[1]])
    else:
        text_origin = np.array([left, top + 1])

    for i in range(thickness):
        draw.rectangle(
            [left + i, top + i, right - i, bottom - i],
            outline=225)
    draw.rectangle(
        [tuple(text_origin), tuple(text_origin + label_size)],
        fill=225)
    draw.text(text_origin, label, fill=(0, 0, 0), font=font)
    del draw

可以得到识别结果如下:
在这里插入图片描述
在这里插入图片描述
至此,实验全部完成。

四、说用

Notebook源码和操作流程,可以访问我的gitee下载

大家使用的云端资源记得全部删除如ModelArts创建的Notebook开发环境需要删除,并停用访问密钥,以免造成不必要的花费。

同时,学生注册还可以领许多优惠券,利用优惠券去购买ModelArts套餐,基本可以全免费使用。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值