开放能力
开发平台
行业应用
生态合作
开发与教学
资讯 社区 控制台
技术能力
语音技术
文字识别
人脸与人体
图像技术
语言与知识
视频技术
AR与VR
数据智能
场景方案
部署方案
行业应用
智能教育
智能医疗
智能零售
智能工业
企业服务
智能政务
信息服务
智能园区

Notebook建模示例

本文以物体检测任务类型为例,从启动Notebook到引入数据、训练模型,再到保存模型的全流程。

启动Notebook

step1:在左侧导航栏中选择开发->Notebook开发

173.png

step2:选择开发语言、AI框架、资源规格与工作目录后启动Notebook

训练物体检测模型

下载 PaddleDetection 套件

打开进入 Notebook,点击进入终端,本文以 PaddleDetection 代码库 release/2.3 分支为例,输入如下命令克隆PaddleDetection代码库并切换至release/2.3分支。整个过程需要数十秒,请耐心等待。

# gitee 国内下载比较快
git clone https://gitee.com/paddlepaddle/PaddleDetection.git -b release/2.3  
# github
# git clone https://github.com/PaddlePaddle/PaddleDetection.git -b release/2.3

安装环境

在终端环境中,安装该版本的 PaddleDetection 代码包依赖的 paddlepaddle-gpu,执行如下命令:

python -m pip install paddlepaddle-gpu==2.1.3.post101 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html

安装完成后,使用 python 或 python3 进入python解释器,输入 import paddle ,再输入 paddle.utils.run_check()如果出现 PaddlePaddle is installedsuccessfully!,说明成功安装。

准备训练数据

训练数据是模型生产的重要条件,优质的数据集可以很大程度上的提升模型训练效果,准备数据可以参考链接。本文所用的安全帽检测数据集可前往此链接进行下载:下载链接

step1:导入用户数据

目前在 Notebook 中不能直接访问您在 飞桨EasyDL 中创建的数据集,需要通过在终端输入数据所在路径。

step2:数据转换

PaddleDetection 训练所需要的数据格式与 飞桨EasyDL 默认的数据格式有所不同,所以需要利用脚本将导入的数据转为 PaddleDetection 支持的数据格式,并进行3:7切分。

PaddleDetection 默认支持的标注格式为 COCO格式,转换脚本如下:

import os
import cv2
import json
import glob
import codecs
import random
from pycocotools.coco import COCO

def parse_bml_json(json_file):
    """
    解析标注文件
    :return:
    """
    annos = json.loads(codecs.open(json_file).read())
    labels = annos['labels']
    bboxes = []
    for label in labels:
        x1 = label["x1"]
        y1 = label["y1"]
        x2 = label["x2"]
        y2 = label["y2"]
        id = label["name"]
        bboxes.append([x1, y1, x2, y2, id])
    return bboxes





def bbox_transform(box):
    """
    x1, y1, x2, y2 转为 x1, y1, width, height
    :return
    """
    box = list(map(lambda x: float(x), box))
    box[2] = box[2] - box[0]
    box[3] = box[3] - box[1]
    return box





def parse_label_list(src_data_dir, save_dir):
    """
    遍历标注文件,获取label_list
    :return:
    """
    label_list = []
    anno_files = glob.glob(src_data_dir + "*.json")
    for anno_f in anno_files:
        annos = json.loads(codecs.open(anno_f).read())
        for lb in annos["labels"]:
            label_list.append(lb["name"])
    label_list = list(set(label_list))
    with codecs.open(os.path.join(save_dir, "label_list.txt"), 'w', encoding="utf-8") as f:
        for id, label in enumerate(label_list):
            f.writelines("%s:%s\n" % (id, label))
    return len(label_list), label_list





def bml2coco(src_dir, coco_json_file):
    """
    将标注格式转为COCO标注格式
    :return:
    """
    coco_images = []
    coco_annotations = []

    image_id = 0
    anno_id = 0
    image_list = glob.glob(src_dir + "*.[jJPpBb][PpNnMm]*")
    for image_file in image_list:
        anno_f = image_file.split(".")[0] + ".json"
        if not os.path.isfile(anno_f):
            continue
        bboxes = parse_bml_json(anno_f)
        im = cv2.imread(image_file)
        h, w, _ = im.shape
        image_i = {"file_name": os.path.basename(image_file), "id": image_id, "width": w, "height": h}
        coco_images.append(image_i)
        for id, bbox in enumerate(bboxes):
            # bbox : [x1, y1, x2, y2, label_name]
            anno_i = {"image_id": image_id, "bbox": bbox_transform(bbox[:4]), 'category_id': label_list.index(bbox[4]),
                      'id': anno_id, 'area': 1.1, 'iscrowd': 0, "segmentation": None}
            anno_id += 1
            coco_annotations.append(anno_i)

        image_id += 1

    coco_categories = [{"id": id, "name": label_name} for id, label_name in enumerate(label_list)]
    coco_dict = {"info": "info", "licenses": "BMLCloud", "images": coco_images, "annotations": coco_annotations,
                 "categories": coco_categories}
    with open(coco_json_file, 'w', encoding="utf-8") as fin:
        json.dump(coco_dict, fin, ensure_ascii=False)





def split_det_origin_dataset(
        origin_file_path,
        train_file_path,
        eval_file_path,
        ratio=0.7):
    """
    按比例切分物体检测原始数据集
    :return:
    """
    coco = COCO(origin_file_path)
    img_ids = coco.getImgIds()
    items_num = len(img_ids)
    train_indexes, eval_indexes = random_split_indexes(items_num, ratio)
    train_items = [img_ids[i] for i in train_indexes]
    eval_items = [img_ids[i] for i in eval_indexes]

    dump_det_dataset(coco, train_items, train_file_path)
    dump_det_dataset(coco, eval_items, eval_file_path)

    return items_num, len(train_items), len(eval_items)





def random_split_indexes(items_num, ratio=0.7):
    """
    按比例分割整个list的index
    :return:分割后的两个index子列表
    """
    offset = round(items_num * ratio)
    full_indexes = list(range(items_num))
    random.shuffle(full_indexes)
    sub_indexes_1 = full_indexes[:offset]
    sub_indexes_2 = full_indexes[offset:]

    return sub_indexes_1, sub_indexes_2





def dump_det_dataset(coco, img_id_list, save_file_path):
    """
    物体检测数据集保存
    :return:
    """
    imgs = coco.loadImgs(img_id_list)
    img_anno_ids = coco.getAnnIds(imgIds=img_id_list, iscrowd=0)
    instances = coco.loadAnns(img_anno_ids)
    cat_ids = coco.getCatIds()
    categories = coco.loadCats(cat_ids)
    common_dict = {
        "info": coco.dataset["info"],
        "licenses": coco.dataset["licenses"],
        "categories": categories
    }
    img_dict = {
        "image_nums": len(imgs),
        "images": imgs,
        "annotations": instances
    }
    img_dict.update(common_dict)

    json_file = open(save_file_path, 'w', encoding='UTF-8')
    json.dump(img_dict, json_file)





class_nums, label_list = parse_label_list("/home/work/data/${dataset_id}/", "/home/work/PretrainedModel/")
bml2coco("/home/work/data/${dataset_id}/", "/home/work/PretrainedModel/org_data_list.json")
split_det_origin_dataset("/home/work/PretrainedModel/org_data_list.json", "/home/work/PretrainedModel/train_data_list.json", "/home/work/PretrainedModel/eval_data_list.json")

将上述脚本存放为 convert.py 代码脚本,并将脚本最后两行的 "/home/work/data/${dataset_id}/" 均替换为所指定数据集路劲,在终端中运行即可。 运行代码。

python covert.py

注意:如果报错 No module named 'pycocotools',需要通过如下命令安装相关依赖包,再运行 covert.py 代码。

pip install pycocotools

运行 covert.py 代码成功之后将在 PretrainedModel/ 文件夹下生成对应的数据文件,包括 label_list.txttrain_data_list.jsoneval_data_list.jsonorg_data_list.json

训练模型

开发者准备好训练数据和安装环境之后即可开始训练物体检测模型。

step1:在终端中打开 PaddleDetection 目录

cd /PaddleDetection

step2:修改yaml配置文件

在PaddleDetection 2.0后续版本,采用了模块解耦设计,用户可以组合配置模块实现检测器,并可自由修改覆盖各模块配置,本文以 configs/yolov3/yolov3_darknet53_270e_coco.yml 为例:

yolov3_darknet53_270e_coco.yml 主配置入口文件
coco_detection.yml 主要说明了训练数据和验证数据的路径
runtime.yml 主要说明了公共的运行参数,比如说是否使用GPU、每多少个epoch存储checkpoint等
optimizer_270e.yml 主要说明了学习率和优化器的配置。
yolov3_darknet53.yml 主要说明模型、和主干网络的情况。
yolov3_reader.yml 主要说明数据读取器配置,如batch size,并发加载子进程数等,同时包含读取后预处理操作,如resize、数据增强等等

需要修改/覆盖的参数均可写在主配置入口文件中,主要修改点为训练、验证数据集路径、运行epoch数、学习率等,修改后的主配置文件如下(注释行即为需要修改的点):

_BASE_: [
  '../datasets/coco_detection.yml',
  '../runtime.yml',
  '_base_/optimizer_270e.yml',
  '_base_/yolov3_darknet53.yml',
  '_base_/yolov3_reader.yml',
]

snapshot_epoch: 5
weights: output/yolov3_darknet53_270e_coco/model_final

# 预训练权重地址
pretrain_weights: https://paddledet.bj.bcebos.com/models/yolov3_darknet53_270e_coco.pdparams

# coco_detection.yml
num_classes: 2 #实际类别数
TrainDataset:
  !COCODataSet
    image_dir: data/${dataset_id}/   # 图片地址
    anno_path: PretrainedModel/train_data_list.json # 标注文件
    dataset_dir: /home/work/ # 数据集根目录
    data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']

EvalDataset:
  !COCODataSet
    image_dir: data/${dataset_id}/   # 图片地址
    anno_path: PretrainedModel/eval_data_list.json   # 标注文件
    dataset_dir: /home/work/   # 数据集根目录

# optimizer_270e.yml
epoch: 50 # 迭代轮数
LearningRate:
  base_lr: 0.0001 # 学习率
  schedulers:
  - !PiecewiseDecay
    gamma: 0.1
    milestones:
    - 30
    - 45
  - !LinearWarmup
    start_factor: 0.
    steps: 400

step3:训练模型

在终端中执行以下命令,开始模型训练。

cd /PaddleDetection/
python tools/train.py -c configs/yolov3/yolov3_darknet53_270e_coco.yml --eval 

注意:如果报错 No module named 'lap' 和 No module named 'motmetrics' ,则需要通过如下命令安装相关依赖包,再运行 coversion.py 代码。(如果缺失其他模块,也可用类似命令下载安装)

pip install lap motmetrics

step4:模型评估

在终端中执行以下命令,开始模型评估。

python tools/eval.py -c configs/yolov3/yolov3_darknet53_270e_coco.yml \
                     -o weights=output/yolov3_darknet53_270e_coco/model_final

运行完成输出如下结果:

176.png

step5:模型预测

在终端中执行以下命令,开始模型预测(注意修改图片路径)。

python tools/infer.py -c configs/yolov3/yolov3_darknet53_270e_coco.yml \
                    --infer_img=/home/work/data/${task_id}/xxx.jpeg \
                    --output_dir=infer_output/ \
                    --draw_threshold=0.5 \
                    -o weights=output/yolov3_darknet53_270e_coco/model_final

step6:导出模型

在终端中执行以下命令,将最佳模型转为可以用于发布的 inference 模型

python tools/export_model.py -c configs/yolov3/yolov3_darknet53_270e_coco.yml \
           --output_dir=/home/work/PretrainedModel/ \
           -o weights=output/yolov3_darknet53_270e_coco/model_final

在终端中执行以下命令,将导出模型移至 /PretrainedModel/ 目录。

mv /PretrainedModel/yolov3_darknet53_270e_coco/* /home/work/PretrainedModel/
上一篇
Notebook简介
下一篇
Http服务运行端注意事项