目录
数据集创建:使用ResNet50预置算法基于海量数据训练美食分类模型
序
参加了华为云AI青年班及黑客松大赛,学习了如何操作华为云 ModelArts 控制台实现自己的模型管理、OBS数据存储系统管理(可下载 OBS Browser+,方便上传下载数据,但不用的时候还是要及时关掉,个人感觉比较占用CPU处理)、模型调优等。
![黑客松比赛结果](https://img-blog.csdnimg.cn/20200514113820798.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d3dDcy,size_16,color_FFFFFF,t_70)
以下通过一些典型内容总结了 华为云 ModelArts 控制台 的主要功能。OBS 数据存储、模型调优等如果认为有必要会再写出来,其实,OBS桶就是一个有收费的存储站,用它可以很方便和 ModelArts 里面的数据文件‘通信’---比如,训练模型的输出、数据集的调用。
具体相关的文件我上传了资源,有兴趣的去我CSDN主页下载即可。
首先是注册华为云账号,注册过程不多解释,按提示走即可;然后,进入华为云 ModelArts 控制台,官网进去-->产品-->EI企业智能-->EI基础平台-->AI开发平台ModelArts-->进入控制台;接着便可进行下面的系列内容。
训练作业创建:垃圾分类训练作业实验
1. 登陆华为云 ModelArts 控制台,训练管理 --> 训练作业--> 创建。
可以设置的参数有:
- 作业名称:trainjob-name
- 算法来源:(多种可选,华为云预置了一些经典算法,如yolo3等;也可管理自己的算法;或者自定义算法来源,本项目使用‘常用框架’)‘常用框架’ 的 tensorflow
- 数据来源:obs桶目录下存储的的数据文件【注意,路径下直接是训练数据文件,否则可能运行失败】;
- 代码目录:obs桶目录下存储的代码文件;
- 启动文件:代码目录下的.py文件;
- 训练输出位置:obs桶目录下设置的output文件(自己在OBS桶下面新建一个即可)。
- 运行参数:新增两=类别个数、配置路径【obs桶目录下存储的代码文件下的配置文件】。
- num_classes=8 和 8个类别
- deploy_script_path= obs://wt.wang-garbage-trainjob/garbage_src/deploy_scripts/
- 作业日志路径:obs://wt.wang-garbage-trainjob/log_wwt/
2. 训练作业任务提交后,可以在训练管理-训练作业,中查看‘配置信息’ ‘日志’ ‘资源占用情况‘。
3. 训练作业完毕,进入模型管理-->模型-->‘导入‘模型,(名称:model-name;版本号; 元模型来源:训练作业的对应版本; 部署类型:在线服务),设置完点击’立即创建‘
4. 部署上线,选择‘在线服务‘中’部署‘(名称:service-name; 公共资源池-我的模型-模型版本-计算节点规格),部署任务提交。
5. 部署成功后,进行预测。用本地测试图像进行测试,完成后关闭在线服务。
Notes : deploy_script_path 路径下包含的两个配置文件的名称不能改变,为“config.json” 和 “customize_service.py”,需要自己编写,编写方式可以参考上传资源里面的代码文件书写方式。
相关步骤的图示过程如下。
---------------训练作业创建设置----------------
此处的数据来源错误,应该再往下一层进入训练文件夹。
---------------训练作业创建完成:查看运行情况----------------
运行失败,改变训练数据文件路径,重新运行,成功。
---------------训练作业创建设置:常用框架展示例子----------------
---------------代码文件----------------
---------------数据文件----------------
---------------查看训练作业运行情况----------------
---------------成功部署后的测试例子----------------
自动学习创建:垃圾分类
1. 登陆OBS桶,建桶,上传数据集(查看我的CSDN资源页面,对应该标题名称“自动学习创建:垃圾分类”)。
2. 登陆华为云 ModelArts 控制台,自动学习 --> 图像分类 --> 创建项目。
3. 接着,根据下面图示过程,标注数据、训练、部署、测试即可。
Note:完成后记得释放资源,避免收费。
---------------自动学习创建项目----------------
---------------创建完成后,进入运行页面,同步、标注数据----------------
---------------标注完数据后,进入模型训练,可以自己根据情况选择合适的资源,数据集切分比例---------------
---------------自动学习训练完成后,点击“模型部署”----------------
---------------自动学习部署成功,即可预测----------------
自动学习创建:零代码美食分类模型开发
和自动学习的垃圾分类项目类似。(查看我的CSDN资源页面,对应该标题名称“自动学习创建:零代码美食分类模型开发”)。
ModelArts控制台:自动学习-图像分类:exeML-proj-name
- 数据集输入输出位置指定【obs目录】后,完成项目创建。
- 进入项目exeML-proj-name,进行数据标注,标注完开始训练,(训练设置指定版本号、训练验证数据比例、预期推理硬件、最大推理时长、最大训练时长、计算规格)。
- 训练结束后,部署上线,部署成功后,进行服务测试,用本地测试图像进行测试,完成后关闭在线服务。
---------------自动学习,美食数据已经上传资源---------------
---------------自动学习部署成功,即可预测----------------
数据集创建:使用ResNet50预置算法基于海量数据训练美食分类模型
---------------目前为止(2020.5.13),华为预置算法截图----------------
1. 首先需要将数据集上传到OBS桶中。接着在ModelArt创建数据集。(查看我的CSDN资源页面,对应该标题名称“数据集创建:使用ResNet50预置算法基于海量数据训练美食分类模型.zip”)。
2. 登陆ModelArts控制台,数据管理-->数据集-->创建数据集,名称为 dataset-name,参数设置如下
- 数据集输入输出位置:指定【obs目录】后,标注场景选‘图片‘,标注类型选’图像分类‘;完成数据集创建。
3. 点击进入创建的数据集,开始标注、发布数据集、并进行一键上线。
4. “开始标注” 数据。‘同步数据源‘(数据集输入输出位置的同步)后,手工标注没有标签的数据,也可以用自动标注(自动标注需要自己先标注一部分,且自动标注后会提示确认自动标注的是否正确,错了可以修改);
5.“发布”数据集,(版本号、版本格式、训练验证比例),发布后可以用版本管理查看。6. 数据集中 “一键模式上线”任务创建。参数设置如下:
- 名称:auto-deploy-name
- 训练预置算法:ResNet_v1_50
- 运行参数:默认,有需要可以自己改。
- 训练输出位置:obs路径。训练输出位置用来保存训练输得到的模型和TensorBoard日志。
- 作业路径位置:obs路径。自己建立。
- 训练资源池:公共;类型:GPU;规格:
CPU
:
8
核
64GiB GPU
:
1 * nvidia-p100 16GiB
;计算节点个数:
1
;
部署资源池:公共;计算节点规格:限时免费
CPU
;计算节点个数:
1.
如果是多个计算节点,就是多实例部署,可以提高API的并发数。
7. 提交后,等待,一条龙过程有:初始化训练-生成模型-部署-完成。中途可以进入相应详情页查看训练详情、模型详情、部署/服务详情等。
- 比如,查看训练作详情。ModelArts --> 训练管理-->训练作业 auto-deploy-name点击进入。查看配置信息、日志、资源占用情况。进行在线服务测试。用本地测试图像进行测试,完成后关闭在线服务。
点击部署服务测试页面右侧的“调用接口指南” 进入如下链接:https://support.huaweicloud.com/engineers-modelarts/modelarts_23_0063.html
---------------自动学习,美食数据已经上传CSDN资源---------------
---------------创建数据集---------------
---------------对创建的数据集,进行任务创建:一键模型上线.---------------
----------------一键模型上线过程中,可以根据过程自由查看生成的模型、部署详情页面等---------------
---------------自动学习部署成功,即可预测---------------
完了后同样关闭在线服务,避免持续扣费。需要时,重新启动。
训练作业创建:猫狗识别(智能标注、TensorBoard)
1. 训练作业步骤,首先新建OBS桶,把写的代码文件、相关数据上传。
- .py代码脚本上传到obs项目文件夹新建的codes目录。
- 下载猫狗数据集.tar.gz,无需解压上传到obs项目文件夹新建的data目录。
- 创建训练作业,步骤同本doc第一节,不过这儿不用新增运行参数。
- 后续同第一个训练作业创建的项目。
智能标注
---------------智能标注:数据准备,上传到桶---------------
(查看我的CSDN资源页面,资源标题名称“训练作业创建:猫狗识别.zip”)
注意:OBS桶名全局唯一,如果创建桶时桶名冲突,需要选择其他桶名。
上传刚刚下载的猫狗图片,并新建一个输出文件output 和 一个用于数据标注输出的文件data_label_out。
---------------智能标注:ModelArts 创建数据集,手工标注一些,剩余点击智能标注,后续观察校正即可---------------
Notes:智能标注这个功能个人感觉并不好用。也可能是我没用好。
智能标注作业完成后,我们需要人工仔细确认每张图片的智能标注的结果。对标注正确的图片进行接纳;对标注错误的进行纠正。修改后,再次智能标注。依据之前处理智能标注结果的流程,处理第二次的智能标注作业。依次地,处理完所有。
训练作业
(查看我的CSDN资源页面,代码"dog_and_cat_train.py"在资源标题名称“训练作业创建:猫狗识别.zip”,数据集因为太大了,CSDN有限制,没有上传,感兴趣的可以从其他来源搜索获取。)
---------------数据(无需解压)、代码上传到桶---------------
和之前步骤一样,创建训练作业。
---------------训练作业创建---------------
---------------查看训练作业运行结果---------------
训练作业页面,点击作业名称,进入作业详情界面。可以查看到训练作业的详情。
---------------创建可视化作业(TensorBoard)查看训练过程---------------
查看loss,accuracy等参数的变化信息。
在训练详情页面右上侧,点击“创建可视化作业”按钮(即,创建TensorBoard)。
TensorBoard可以直观地显示训练过程中loss、accuracy等评估指标的变化曲线,为开发者优化模型精度提供依据。
注意:TensorBoard使用完后需要及时关闭,否则会继续扣费。
---------------训练完成后,即可部署模型---------------
步骤1 . 需知---推理脚本customize_service.py 和模型配置文件config.json 导入模型文件model下。
customize_service.py 推理脚本中有两个方法。_preprocess
是预处理方法,在推理请求前调用,用于将API接口用户原始请求数据转换为模型期望输入数据。_postprocess
是后处理方法,在推理请求完成后调用,用于将模型输出转换为API接口输出。
config.json 是模型部署配置信息,定义了AI引擎的类别,推理脚本需要的Python依赖等。
点击“模型管理”界面,然后点击“导入”按钮。
命名模型,设置版本号,选择元数据来源:从训练中选择。
注意,其他参数会自动加载;推理代码:https://wt.wang-dogcat-recog.obs.myhwclouds.com/output/model/customize_service.py
模型管理页面, 找到之前导入的模型,点击“部署”下拉框中的“在线服务”。
同样,命名部署的在线服务的名称、模型来源等参数。
-模型部署成功如下。
注意:实验完成后,为了防止继续扣费,需要把在线服务停止掉,在线服务停止后可以重新启动。点击“停止”按钮即可:
Notebook使用:Yolo3物体检测
(查看我的CSDN资源页面,资源标题名称“Notebook:Yolo3物体检测.zip”)
具体操作步骤:
1. 登陆ModelArts控制台 --> 开发环境 --> Notebook --> 创建.
- 名称:notebook-obj-dect-yolo;参数:python3-公共资源池-GPU-云硬盘EVS
----------------------------------Notebook创建------------------------------------------
---------------------------------Notebook 开发环境下编写代码---------------------------------------------
点击‘new’, ’tensorflow-1.13.1’【和anaconda的jupyter notebook一样操作新建】
经过上面代码解压的数据文件,如下。
观察下载内容:coco是标注的训练数据文件和一些图片文件;model_data里面是模型参数文件和coco数据的类别文件;yolo3里面是模型源代码;train.py是训练代码,test.jpg用于最后的预测。Font里面不用在意。
-----------------------------代码部分运行结果-------------------------------------------
yolo3 相关:
- https://mp.weixin.qq.com/s?src=11×tamp=1587811364&ver=2300&signature=oqxbJ2QesbigUa47KfTIPiAGDvwhXjquIlY8qqP*jkjm9YNiqf9tvMTKfpgpN923utyKMPcxB6kFmCVBM0nkA8y-LcagvWxVqv22XwYKqP*Fn6CvNxXqyKi5mXxtTagf&new=1
- https://blog.csdn.net/qq_41375609/article/details/94737915
- https://blog.csdn.net/zziahgf/article/details/72819043
----------------------------------代码文件已经上传资源------------------------------------------
附注 : .ipynb内容
下面插入的代码在华为云 ModelArts平台的Notebook 下运行通过。
# 数据和代码下载,此处可不要,见CSDN资源文件。
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
# ------------------------------------------------------
# 准备数据
# ----------------------------------------------------------
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)
# ----------------------------------------------------------
# 模型训练:本案例使用Keras深度学习框架搭建YOLOv3神经网络。
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()
# ----------------------------------------------------------
# 构建神经网络,可以在./yolo3/model.py文件中查看细节
#
# 图像输入尺寸
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])
# ---------------------------------------------------------------
import os
os.makedirs(save_path)
# 保存模型
model.save_weights(os.path.join(save_path, 'trained_weights_final.h5'))
# ------------------------------------------------------------------
# 模型测试
# ------------------------------------------------------------------
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
# -图片预处理-
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
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)
# ----------------------------------------------------------
# 进行预测
# ----------------------------------------------------------
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)
# ----------------------------------------------------------
# 将预测结果绘制在图片上
# ----------------------------------------------------------
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
image
- 备注1:本文相关数据在CSDN资源,欢迎查看。
- 备注2:本次华为云AI项目赛事相关项目没有完全在本文写完,因为笔者认为,基本流程都是相似的,具体还是要用项目练手,练手资源华为云官方都准备好了,见:https://github.com/IamWWT/ModelArts-Lab