【华为云-上云之路】【2020华为云AI实战营】【每天进步一点点】基于ModelArts 实现人脸识别(MXNET)

网友投稿 588 2022-05-29

什么是ModelArts? 来看看介绍

这里我们用到的就是ModelArts中的NoteBook,也用到了OBS桶。正好在ModelArts上做了一个人脸识别的云端实验,在这里分享一下执行过程,下面开始吧。

1. 创建NoteBook

选择左侧栏,点击“开发环境”-> “Notebook”->“创建”,如下图所示:

进入Notebook创建页面。参数:

① 计费方式:按需计费

② 名称:任意,如face_recognition

③ 自动停止:关闭

④ 工作环境:Python3

⑤ 资源池:公共资源池

⑥ 类型:GPU

⑦ 规格:GPU: 1*v100NV32 CPU: 8 核 64GiB

⑧ 存储配置:云硬盘⑧ 磁盘规格:默认

参数填写完毕后,点击“下一步”,查看Notebook实例预览信息,确认无误后点击“提交”。创建任务提交成功,点击页面的“返回Notebook列表”,返回Notebook列表页,等待Notebook创建成功,创建成功后状态会变成“运行中”,如下图所示:

2. 创建Notebook Python开发环境

点击“打开”按钮进入Notebook。点击“New” ->”MXNet 1.2.1”创建 Notebook Python开发环境。如下图所示:

重命名刚刚创建的Notebook Python开发环境。点击“Untitled”,我们可以填写一个跟本实验相关的名称,然后点击“Rename”按钮,如下图所示:

我们打印一行字符串,按Shift+Enter(该组合键是Notebook中执行代码的快捷键)或者点击下图“Run”。

print("hello notebook!")

查看代码执行结果。如下图所示:

3. 准备源代码和数据

相关资源已经保存在OBS中,通过ModelArts SDK将资源下载,并解压到当前目录下。解压后,当前目录包含src和data两个目录,分别存有源代码和数据集(可进入Notebook查看)。代码如下:

from modelarts.session import Session session = Session() if session.region_name=='cn-north-4':     session.download_data(bucket_path='ai-course-common-20-bj4/face_recognition/face_recognition.tar',     path='./face_recognition.tar') else:     session.download_data(bucket_path='ai-course-common-20/face_recognition/face_recognition.tar',     path='./face_recognition.tar') # 使用tar命令解压资源包 !tar xf ./face_recognition.tar

日志如下:

Successfully download file ai-course-common-20-bj4/face_recognition/face_recognition.tar from OBS to local ./face_recognition.tar

如下图所示:

执行成功,回到ModelArts“Notebook”列表即可看到资源,后面步骤生成的文件及文件夹同样可以这样查看,如下图所示:

4. 创建OBS桶

鼠标移动到云桌面浏览器页面中左侧菜单栏,点击“服务列表”-> 选择“存储”的“对象存储服务”,进入后右上角点击“创建桶”。

参数:

① 区域:华北-北京四

② 桶名称:自定义即可(需要记住此名称以备后续步骤使用)

③ 存储类别:标准存储

④ 桶策略:私有

⑤ 归档数据直读:关闭

⑥ 多AZ:关闭

点击右下角“立即创建”,如下图所示:

5. 配置信息

将运行结果上传至OBS中,设置相关的参数(使用自己真实的桶名替换掉*号):

• BUCKET_NAME:自己的OBS桶名。

切换至前面创建的Notebook Python开发环境界面,将下方代码拷贝粘贴并替换桶名称后,执行“run”,此段代码无输出。

BUCKET_NAME = '*' UNIQUE_ID = 'face-data' OBS_BASE_PATH = BUCKET_NAME + '/' + UNIQUE_ID

6. 导入基本信息

执行以下代码,导入使用的Python开发基本工具库,代码无输出。

MXNet框架是我们使用的AI编程框架;

argparse库用于解析外部输入参数;

src.face_resnet包含了人脸识别的卷积模型骨干。

import os import mxnet as mx import argparse from src.face_resnet import get_symbol import warnings warnings.filterwarnings('ignore') import logginglogger = logging.getLogger() logger.setLevel(logging.INFO)

训练数据量和训练的关系说明:

per_batch_size:指在每个GPU上一次训练一批数据的大小,调整这个值越大,表示一次训练的数据量也就越大,这个公式代表了梯度更新的方法大小,

m为batch_size大小,

【华为云-上云之路】【2020华为云AI实战营】【每天进步一点点】基于ModelArts 实现人脸识别(MXNET)

Var是指方差,显然当batch_size越大,方差也就越大,而方差越大,也就表示数据越稳定,在深度学习中也就表示训练得越稳定。

结合上面讲的学习率大小的调整,在显存可承受范围内,越大的batch_size使得学习更稳定情况下,学习率也可以随着调整得更大。

def parse_args():     parser = argparse.ArgumentParser(description='Train face network')     parser.add_argument('--data_dir', default='data',                         help='training set directory')# 训练数据路径     parser.add_argument('--train_url', type=str, default='ckpt',                         help='train path')# 训练模型输出路径     parser.add_argument('--num_epoch', type=int, default=20,                         help='training epoch size.')# 训练epoch数量     parser.add_argument('--num_layers', type=int, default=18,                         help='specify network layer, 18 50 100')# 使用的ResNet卷积层层数     parser.add_argument('--image_size', default='112,112',                         help='specify input image height and width')# 输入图像的大小,高、宽     parser.add_argument('--lr', type=float, default=0.005,                         help='start learning rate')# 训练开始的学习率大小     parser.add_argument('--wd', type=float, default=0.0005,                         help='weight decay')# 权值衰减系数     parser.add_argument('--mom', type=float, default=0.9,                         help='momentum')# 动量     parser.add_argument('--per_batch_size', type=int, default=8,                         help='batch size in each context')# 每一个GPU的batch size大小     parser.add_argument('--epoch_image_num', type=int, default=200,                         help='image size in one epoch')# 训练样本大小     parser.add_argument('--train_file', type=str, default='celeb_train.rec',                         help='train')# 训练数据文件     parser.add_argument('--val_file', type=str, default='celeb_val.rec',                         help='val')# 验证集文件     parser.add_argument('--num_classes', type=int, default=5,                         help='classes number')# 分类数     parser.add_argument('--num_embed', type=int, default=8,                         help='embedding number')# 嵌入层神经元数量     parser.add_argument('--num_gpus', type=int, default=1,                         help='GPUs number')# GPU数量     parser.add_argument('--save_frequency', type=int, default=1,                         help='save frequency')# 保存模型的频率     parser.add_argument('--export_model', type=bool, default=False,                         help='change train url to model,metric.json')#是否改变train url结构          args, _ = parser.parse_known_args()     return args args = parse_args()

# 模型所在的环境,指cpu或者哪块gpu ctx = [mx.gpu(x) for x in range(args.num_gpus)] if args.num_gpus>0 else [mx.cpu()] print(ctx)

设置超参,就是在训练前需要人工指定的参数。设置训练需要的超参:

设置模型训练的设备环境;

设置训练时的batch size,固定图像大小的信息,和梯度归一化等参数;

设置优化器参数;

设置训练时的回调函数;

设置模型参数初始化方法

# 一次训练输入的batch size大小的数据 batch_size = int(args.per_batch_size * (args.num_gpus if args.num_gpus>0 else 1)) print('batch size: ', batch_size) # 输入图像的高和宽 image_h, image_w = [int(x) for x in args.image_size.split(',')] print('image height: ', image_h, ', image width: ', image_w) # 梯度归一化参数,大小为1.0 / batch_size _rescale = 1.0 / batch_size print('rescale grad: ', _rescale)

# 优化器参数,包含学习率调度器、权值衰减系数等 optimizer_params = {'learning_rate': args.lr,                     'wd' : args.wd,                     'lr_scheduler': None,                     'clip_gradient': 5,                     'momentum' : args.mom,                     'multi_precision' : True,                     'rescale_grad': _rescale,                     } print(optimizer_params)

# 每一个step训练完后的操作 batch_end_callbacks = [mx.callback.Speedometer(batch_size, 10, auto_reset=True)] # 每一个epoch训练完后的操作 # 这里的模型保存路径为模型输出文件目录下的model目录,模型文件以face开头 epoch_end_callbacks = mx.callback.do_checkpoint(     os.path.join(args.train_url,'model/face'), args.save_frequency) # 模型评估方法,准确度和交叉熵 eval_metrics = [mx.metric.Accuracy(), mx.metric.CrossEntropy()]

# 模型参数的初始化方法 initializer = mx.init.Xavier(rnd_type='gaussian', factor_type="out", magnitude=2)

7. 读取数据集,准备训练

人脸识别数据集使用的是明星人脸图像集CelebFace,经过人脸3D对齐等操作制作成了适合分类模型训练的数据,每张图像的大小为112*112,样本图像如下:

数据集格式为MXNet专用的rec格式,rec格式的数据集相比原图读取速度更快。使用MXNet自带的mx.io.ImageRecordIter方法读取rec格式数据集,mx.io.ImageRecordIter可以在读取数据时就实现数据增强的方法,这里做了随机翻转、数据集重新洗牌等增强。拷贝执行如下代码,这里定义数据加载器的对象,加载成功会打印输出 “data loaded!”。

# 训练集和验证集的rec文件路径 path_imgrec = os.path.join(args.data_dir, args.train_file) path_val_imgrec = os.path.join(args.data_dir, args.val_file) # 使用mxnet自带的mx.io.ImageRecordIter加载数据 val_dataiter = mx.io.ImageRecordIter(         path_imgrec=path_val_imgrec,         data_shape=(3, image_h, image_w),         batch_size=batch_size,         resize=image_w,                 # 图像按照其最短边resize到定义好的宽长         shuffle=False,         preprocess_threads=2) train_dataiter = mx.io.ImageRecordIter(         path_imgrec=path_imgrec,         data_shape=(3, image_h, image_w),         num_parts=1,                    # 训练的节点数         part_index=0,                   # 本机所在的节点id         batch_size=batch_size,         resize=image_w,         rand_crop=False,         rand_mirror=True,              # 图像随机翻转         shuffle=True,                  # 数据集随机洗牌         preprocess_threads=2) print('data loaded!')

import matplotlib.pyplot as plt next_data_batch = next(iter(train_dataiter)) img = next_data_batch.data[0][0].transpose(axes=(2,1,0)) img = img.asnumpy().astype('uint8') # 画图,数据增强后的图片 %matplotlib inline fig = plt.figure() plt.imshow(img) plt.show()

搭建网络,人脸识别算法使用的模型骨干(backbone)为ResNet-50,基于ResNet-50模型构建人脸识别神经网络。src目录(打开的Notebook下可以查看)下的face_resnet.py源代码文件加载模型骨干,并将其分类层作为嵌入层,分类数设置为嵌入层神经元数。在嵌入层后面接一个分类数为num_classes的分类层,就可以得到本实验的人脸识别神经网络了。拷贝执行如下代码,这里会输出一个 mx.mod.Module 对象。

# 初始化模型参数为None,这里可以加载预训练的模型参数 arg_params = None aux_params = None # 得到嵌入层模型的Symbol embedding = get_symbol(num_classes=args.num_embed, num_layers=args.num_layers) # 设置分类层的权值 _weight = mx.symbol.Variable("fc7_weight",                              shape=(args.num_classes, args.num_embed),                              lr_mult=1.0, wd_mult=1.0) _bias = mx.symbol.Variable('fc7_bias', lr_mult=2.0, wd_mult=0.0) # 全连接层 fc7 = mx.sym.FullyConnected(data=embedding, weight = _weight,                             bias = _bias, num_hidden=args.num_classes, name='fc7') all_label = mx.symbol.Variable('softmax_label') softmax = mx.symbol.SoftmaxOutput(data=fc7, label = all_label, name='softmax') # 输入模型环境和Symbol model = mx.mod.Module(context=ctx, symbol=softmax) print(model)

开始训练

model_output_dir = args.train_url + '/model/' if os.path.exists(model_output_dir) == False:     os.makedirs(model_output_dir) model.fit(train_dataiter,           begin_epoch        = 0,           num_epoch          = args.num_epoch,           eval_data          = val_dataiter,           eval_metric        = eval_metrics,           kvstore            = 'local',           optimizer          = 'nag',           optimizer_params   = optimizer_params,           initializer        = initializer,           arg_params         = arg_params,           aux_params         = aux_params,           allow_missing      = True,           batch_end_callback = batch_end_callbacks,           epoch_end_callback = epoch_end_callbacks )

部分日志如下:

8. 执行推理

模型推理共分为以下几个步骤:

导入读取图片所需的库;

输出测试的原图;

测试原图转换成模型需要的数据;

加载推理使用的模型结构;

推理计算并输出结果。

代码如下:

import moxing as mox # The obs_dst_path pattern: {BUCKET_NAME}/{UNIQUE_ID}/face_recognition/results/{TRAIN_URL} obs_dst_path = "s3://" + OBS_BASE_PATH + "/face_recognition/results/" + args.train_url + '/' mox.file.copy_parallel(args.train_url+'/model',                       obs_dst_path)

import mxnet.image as image import moxing as mox import mxnet as mx import matplotlib.pyplot as plt import os

# 设置类别名,由于不能知道每张人脸的真实名字,用数字来替代 class_names = range(5) # 人脸图像路径,这里可以任意选择一张人脸图像,并上传到自己的OBS路径 # 如s3://ai-course-001/face_recognition/data/下的test.png file_name = args.data_dir + '/test.png' # 以二进制形式,将图片读入内存 img = mox.file.read(file_name, binary=True) # 查看图片 orig_img = mx.img.imdecode(img, to_rgb=1).asnumpy().astype('uint8') plt.imshow(orig_img) plt.show()

# 图像处理 # 将图像处理成(3,112,112)大小 [h, w] = [112, 112] img_arr = mx.img.imdecode(img, to_rgb=1) # 首先转换成NDArray形式 img_arr = mx.img.resize_short(img_arr, w, 0) # 翻转,经过翻转的图像不能通过plt显示 img_arr = mx.nd.transpose(img_arr, (2, 0, 1)) img_arr = mx.nd.expand_dims(img_arr, axis=0) # 将图像绑定到cpu上 d = [img_arr.as_in_context(mx.cpu())] print(d)

# 模型文件位置,比如由上面训练得到的位置train_url+'model', # 这个路径位置下面必须有.json和.params的模型文件 ckpt = os.path.join(args.train_url, 'model/face') # 加载第几个epoch load_epoch = 1 # 加载模型文件,sym为推理模型结构,arg_params, aux_params为模型参数 sym, arg_params, aux_params = mx.model.load_checkpoint(ckpt, load_epoch) # 选择使用cpu进行推理,数据名默认为data,推理无需输入label mx_model = mx.mod.Module(symbol=sym, context=mx.cpu(),                                       data_names=['data'], label_names=None) # 绑定模型计算模块到底层计算引擎,绑定的数据大小默认为(1,3,112,112) mx_model.bind(for_training=False, data_shapes=[('data',(1,3,112,112))]) # 设置模型的参数 mx_model.set_params(arg_params, aux_params, allow_missing=True)

# 模型结果后处理方法 def _postprocess(data):     dim = len(data[0].shape)     if dim > 2:         data = mx.nd.array(np.squeeze(data.asnumpy(), axis=tuple(range(dim)[2:])))     # 将得到的结果排序,选择可能性最大的类别     sorted_prob = mx.nd.argsort(data[0], is_ascend=False)     top_prob = list(map(lambda x: int(x.asscalar()), sorted_prob[0:2]))     # 输出推理得到的类别和对应可能性     return {"predicted_label": class_names[top_prob[0]],             "scores": [[class_names[i], float(data[0, i].asscalar())] for i in top_prob]} # 进行前向推理 mx_model.forward(mx.io.DataBatch(d)) # 输出 print(_postprocess(mx_model.get_outputs()[0]))

最后得到输出

至此,基于ModelArts的MXNET框架的人脸识别完成了,包括训练和推理,快来试试吧。最后附上完成代码,在附件,下载解压缩后,上传face_recognition.ipynb到NoteBook中,逐步运行即可。

附件: face_recognition.zip 71.65KB 下载次数:3次

EI 人工智能 ModelArts 华为云ModelArts

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java nio 基础用法
下一篇:【2021最新版】Java基础面试题总结(70道题含答案解析)
相关文章