ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

MXNet Gluon 实战:从实验到部署的迁移学习全流程(ResNet50 V2 花卉识别)

MXNet Gluon 实战:从实验到部署的迁移学习全流程(ResNet50 V2 花卉识别) 深度学习人工智能机器学习分布式训练【免费下载链接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more项目地址https://gitcode.com/gh_mirrors/mx/mxnet点击查看免费下载导读本文基于 MXNet Gluon API 的完整能力带领你走通一条从**实验Experiment到部署Deployment**的典型链路数据准备 → 迁移学习微调 → 模型导出 → 推理部署。以「花卉物种识别」服务为例使用 ImageNet 预训练的 ResNet50 V2 模型在 Oxford 102 花卉数据集上做微调Fine-tuning最终通过 Gluon 的export导出为符号图与参数文件供 Python 与 C 等多语言推理场景复用。读完本文你将掌握 Gluon 的数据增强流水线、混合式编程Hybridization、学习率调度、多设备训练以及模型序列化的完整实战方案。背景数据不足时的迁移学习构建一个花卉识别服务时最典型的问题是自有标注数据不足以从头训练一个足够鲁棒的模型。此时迁移学习Transfer Learning是行业标准解法——利用一个在超大规模标准数据集如 ImageNet约 130 万张图片上预训练、且与目标任务高度相关的模型把其中学到的通用视觉特征迁移到当前的小数据集任务上。Gluon 的模型动物园Model Zoo为分类、目标检测、分割等标准任务提供了多种 State of the Art 预训练模型。本教程选用在 ImageNet 上预训练的 ResNet50 V2该模型在 ImageNet 上达到 77.11% 的 Top-1 准确率通过迁移其卷积特征提取能力让模型在仅 102 类的花卉数据集上也能快速收敛并取得高精度。注原文档中出现的模型 Zoo 源码可在 python/mxnet/gluon/model_zoo/vision/resnet.py 中查看resnet50_v2由get_resnet(2, 50, **kwargs)构建支持pretrained、device、root等参数root默认指向$MXNET_HOME/models。前置条件从源码构建 MXNet需同时包含 Python(Gluon) 与 C 包构建说明可参考项目根目录的 README.md 与 docs/README.md。掌握 Gluon 基础可参考 Gluon 60 分钟快速入门 与 hybridize 教程。数据准备Oxford 102 花卉数据集本教程以 Oxford 102 Category Flower Dataset 为例。仓库已提供数据工具脚本 docs/tutorial_utils/data/oxford_102_flower_dataset.py它会下载原始数据图片包102flowers.tgz、标签文件imagelabels.mat、划分文件setid.mat解析.mat中的 train/test/valid 索引并把同一类别的图片归入同一文件夹最终形成 GluonImageFolderDataset可直接消费的目录结构。import mxnet as mx # 下载数据工具脚本tutorial_utils 目录下已内置也可从仓库直接获取 data_util_file oxford_102_flower_dataset.py base_url https://raw.githubusercontent.com/apache/mxnet/master/docs/tutorial_utils/data/{}?rawtrue mx.test_utils.download(base_url.format(data_util_file), fnamedata_util_file) import oxford_102_flower_dataset # download and move data to train, test, valid folders path ./data oxford_102_flower_dataset.get_data(path)执行后数据被组织为./data/train、./data/test、./data/valid三个子集每个子集内按类别名如pink primrose、sunflower、rose等 102 个花名建子目录。从源码看get_data依次调用download_data()下载并解压、prepare_data()按setid.mat划分并复制文件和generate_synset()生成按字母序排列的synset.txt供数据集 API 使用其中move_files使用了测试集与训练集索引互换的处理idx_test归入 trainidx_train归入 test并统一将标签从 1-based 转为 0-based便于与 Gluon 损失函数对齐。训练Gluon 微调流水线超参数定义先导入所需包并定义微调超参数。原文档强调使用 MXNet 学习率调度器在训练过程中调整学习率可参考 learning_rate_schedules 教程为快速演示将epochs设为 1实际训练请改为 40。import math import os import time from mxnet import autograd from mxnet import gluon, init from mxnet.gluon import nn from mxnet.gluon.data.vision import transforms from mxnet.gluon.model_zoo.vision import resnet50_v2 classes 102 epochs 1 # 演示用实际训练建议 40 lr 0.001 per_device_batch_size 32 momentum 0.9 wd 0.0001 # 权重衰减 lr_factor 0.75 lr_epochs [10, 20, 30] # 在这些 epoch 处调整学习率 num_gpus mx.device.num_gpus() num_workers 8 # 可替换为你的 CPU 核心数 device [mx.gpu(i) for i in range(num_gpus)] if num_gpus 0 else [mx.cpu()] batch_size per_device_batch_size * max(num_gpus, 1)要点说明device是一个设备列表有 GPU 时按num_gpus展开为多卡列表否则回退到[mx.cpu()]后续gluon.utils.split_and_load会把 batch 平均分到每个设备上。batch_size per_device_batch_size * max(num_gpus, 1)保证多卡时总 batch 随设备数线性扩展。num_workers控制数据加载进程数可按本机 CPU 核数调整是影响数据吞吐的关键参数。数据增强与 Transform 流水线在训练图像上施加数据增强通过对训练样本做轻微改动让模型把它们视为不同样本从而缓解小数据集过拟合、提升泛化能力。这里使用 Gluon 的 DataSet API、DataLoader API 与 Transform API 完成加载与预处理共 5 步随机裁剪并缩放到 224×224随机水平翻转随机颜色抖动并加噪声RandomLighting即 PCA 光照抖动将数据从[height, width, num_channels]转置为[num_channels, height, width]并把像素值从 [0, 255] 映射到 [0, 1]ToTensor用 ImageNet 的均值/标准差归一化。验证与推理阶段只需步骤 1、4、5不引入随机性保证结果可复现同时把均值/标准差保存下来供其他语言绑定做推理时复用。jitter_param 0.4 lighting_param 0.1 # mean and std for normalizing image value in range (0,1) mean [0.485, 0.456, 0.406] std [0.229, 0.224, 0.225] training_transformer transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomFlipLeftRight(), transforms.RandomColorJitter(brightnessjitter_param, contrastjitter_param, saturationjitter_param), transforms.RandomLighting(lighting_param), transforms.ToTensor(), transforms.Normalize(mean, std) ]) validation_transformer transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean, std) ]) # save mean and std NDArray values for inference mean_img mx.np.stack([mx.np.full((224, 224), m) for m in mean]) std_img mx.np.stack([mx.np.full((224, 224), s) for s in std]) mx.npx.savez(mean_std_224.np, **{mean_img: mean_img, std_img: std_img}) train_path os.path.join(path, train) val_path os.path.join(path, valid) test_path os.path.join(path, test) # loading the data and apply pre-processing(transforms) on images train_data gluon.data.DataLoader( gluon.data.vision.ImageFolderDataset(train_path).transform_first(training_transformer), batch_sizebatch_size, shuffleTrue, num_workersnum_workers) val_data gluon.data.DataLoader( gluon.data.vision.ImageFolderDataset(val_path).transform_first(validation_transformer), batch_sizebatch_size, shuffleFalse, num_workersnum_workers) test_data gluon.data.DataLoader( gluon.data.vision.ImageFolderDataset(test_path).transform_first(validation_transformer), batch_sizebatch_size, shuffleFalse, num_workersnum_workers)实现细节ImageFolderDataset的实现位于 python/mxnet/gluon/data/vision/datasets.pyclass ImageFolderDataset它按子目录名解析类别标签transform_first只对数据不含标签做变换比transform更高效DataLoader负责多进程异步加载与 batch 组装。加载预训练模型并重定义输出层使用 ImageNet1000 类预训练的resnet50_v2。由于花卉数据集只有 102 类必须重定义最后的 softmax 输出层为 102 维并初始化新层参数。这里引入 Gluon 的标志性特性——混合式编程Hybridization调用net.hybridize()即可把命令式imperative代码编译成静态符号图带来两大收益执行效率更高、部署序列化更容易。其底层原理是HybridBlock第一次前向时缓存计算图_cached_graph后续前向直接执行编译后的符号图。# load pre-trained resnet50_v2 from model zoo finetune_net resnet50_v2(pretrainedTrue, devicedevice) # change last softmax layer since number of classes are different finetune_net.output nn.Dense(classes) finetune_net.output.initialize(init.Xavier(), devicedevice) # hybridize for better performance finetune_net.hybridize() num_batch len(train_data) # setup learning rate scheduler iterations_per_epoch math.ceil(num_batch) # learning rate change at following steps lr_steps [epoch * iterations_per_epoch for epoch in lr_epochs] schedule mx.lr_scheduler.MultiFactorScheduler(steplr_steps, factorlr_factor, base_lrlr) # setup optimizer with learning rate scheduler, metric, and loss function sgd_optimizer mx.optimizer.SGD(learning_ratelr, lr_schedulerschedule, momentummomentum, wdwd) metric mx.gluon.metric.Accuracy() softmax_cross_entropy gluon.loss.SoftmaxCrossEntropyLoss()关键点resnet50_v2(pretrainedTrue, devicedevice)将预训练权重加载到目标设备device为列表时权重会在每个设备上复制一份。注意hybridize()必须在重定义输出层之后调用且导出前必须先完成一次前向让_cached_graph生成。init.Xavier()只初始化新加的 Dense 层预训练层权重保持不变这正是迁移学习的核心。学习率调度MultiFactorScheduler实现在 python/mxnet/lr_scheduler.py把 epoch 级调度点换算成 step 级lr_steps每到达一个调度点将学习率乘以factor0.75。损失与优化器SoftmaxCrossEntropyLosspython/mxnet/gluon/loss.py配合带 momentum 的 SGDgluon.Trainerpython/mxnet/gluon/trainer.py负责参数更新与多设备同步。微调训练循环定义验证函数并执行训练循环def test(net, val_data, device): metric mx.gluon.metric.Accuracy() for i, (data, label) in enumerate(val_data): data gluon.utils.split_and_load(data, device, even_splitFalse) label gluon.utils.split_and_load(label, device, even_splitFalse) outputs [net(x) for x in data] metric.update(label, outputs) return metric.get() trainer gluon.Trainer(finetune_net.collect_params(), optimizersgd_optimizer) # start with epoch 1 for easier learning rate calculation for epoch in range(1, epochs 1): tic time.time() train_loss 0 metric.reset() for i, (data, label) in enumerate(train_data): # get the images and labels data gluon.utils.split_and_load(data, device, even_splitFalse) label gluon.utils.split_and_load(label, device, even_splitFalse) with autograd.record(): outputs [finetune_net(x) for x in data] loss [softmax_cross_entropy(yhat, y) for yhat, y in zip(outputs, label)] for l in loss: l.backward() trainer.step(batch_size) train_loss sum([l.mean().item() for l in loss]) / len(loss) metric.update(label, outputs) _, train_acc metric.get() train_loss / num_batch _, val_acc test(finetune_net, val_data, device) print([Epoch %d] Train-acc: %.3f, loss: %.3f | Val-acc: %.3f | learning-rate: %.3E | time: %.1f % (epoch, train_acc, train_loss, val_acc, trainer.learning_rate, time.time() - tic)) _, test_acc test(finetune_net, test_data, device) print([Finished] Test-acc: %.3f % (test_acc))训练循环结构拆解autograd.record()记录前向计算图loss.backward()反向传播split_and_load(data, device, even_splitFalse)python/mxnet/gluon/utils.py把 batch 按设备数切分返回每个设备上的数据切片列表随后逐设备前向trainer.step(batch_size)以全局 batch_size为分母做梯度归一化多卡时自动聚合各卡梯度metric.update(label, outputs)累积准确率metric.get()返回(名称, 值)元组学习率从trainer.learning_rate实时读取验证调度是否生效。原文档给出的 40 epoch 训练结果如下硬件为 4×Tesla V100 的 AWS p3.8xlarge 实例耗时约 12 分钟[Epoch 40] Train-acc: 0.945, loss: 0.354 | Val-acc: 0.955 | learning-rate: 4.219E-04 | time: 17.8 [Finished] Test-acc: 0.952最终测试准确率达 95.2%验证集 95.5%。如此之快且准正是因为模型已在 130 万张 ImageNet 图像上习得了很强的特征提取能力小数据集上只需微调即可。导出微调后的模型训练完成即可用export序列化模型。export会把模型架构导出为.json文件、模型参数导出为.params文件finetune_net.export(flower-recognition, epochepochs)执行后在当前目录生成flower-recognition-symbol.json与flower-recognition-0040.params0040对应 40 个 epoch。这两个文件可直接用于部署通过HybridBlock.importPython 侧为gluon.SymbolBlock.imports或 C 接口加载。从源码看export实现于 python/mxnet/gluon/block.pyHybridBlock.export若未先hybridize()并完成至少一次前向会抛出RuntimeErrorPlease first call block.hybridize() and then run forward with this block at least once before calling export——这是导出前最常见的报错导出时会把符号输入重命名为可读的参数名{path}-symbol.json参数文件命名为{path}-{epoch:04d}.params单输入时输入名固定为data多输入时依次命名为data0、data1……推理端需按此约定构造输入参数以arg:/aux:前缀区分参数与辅助状态当前 numpy 数组模式下使用mx.npx.savez保存旧模式下用ndarray.saveremove_amp_cast参数可控制在导出时是否移除 AMP自动混合精度插入的amp_cast/amp_multicast算子。部署与推理export产出的-symbol.json-params是 Gluon 的标准部署产物支持多种消费方式Python 推理用gluon.SymbolBlock.imports(flower-recognition-symbol.json, [data], flower-recognition-0040.params)重新加载符号图与参数传入与训练一致的预处理Resize→CenterCrop→ToTensor→Normalize均值/标准差可用此前保存的mean_std_224.np即可推理。C 推理-symbol.json与.params正是 cpp-package/example/inference 等 C 示例所加载的文件格式实现了 Python 训练、C 部署的跨语言链路这也是教程中单独保存mean_std_224.np的原因——C 端需要同一套归一化参数。模型服务器可将导出文件用于 MXNet Model Server 等推理服务编排把模型封装为在线服务。后续学习路径想深入推理与部署的更多玩法可继续探索Gluon 混合式编程 hybridize 详解理解hybridize()如何把命令式代码编译为静态图以及export/imports的配套用法。Gluon 块的保存与加载对比save_parameters/load_parameters仅参数与export架构参数的适用场景。学习率调度掌握MultiFactorScheduler之外的余弦退火、自定义调度等策略。Gluon 数据 API了解Dataset、DataLoader、transform的完整接口与自定义数据集写法。想从零训练或微调其他骨干网络可阅读 python/mxnet/gluon/model_zoo/vision/resnet.py 中resnet34_v2、resnet101_v2等变体它们共享同一套get_resnet构建逻辑。参考ResNet V2 论文Identity Mappings in Deep Residual NetworksOxford 102 Category Flower Dataset 官方页面Gluon 微调书籍章节d2l 的 fine-tuning 章节Gluon CV 迁移学习教程Gluon 快速入门课程仓库内 C 推理示例cpp-package/example/inference赞分享深度学习人工智能机器学习分布式训练【免费下载链接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more项目地址https://gitcode.com/gh_mirrors/mx/mxnet点击查看免费下载相关推荐MXNet Gluon 迁移学习实战从花卉识别实验到模型部署的完整流程MXNet Gluon 迁移学习实战从花卉识别实验到模型部署的完整流程 导读 本文以构建一个花卉种类识别服务为实战场景完整演示 MXNet Gluon人工智能深度学习机器学习企业微信客户联系集成bot-on-anything客户管理方案企业微信客户联系集成bot on anything客户管理方案 在当今数字化办公环境中企业微信已成为团队协作和客户沟通的重要平台。bot on anythiAI 应用后端交互助手从MXNet Gluon到ivyimperative深度学习接口的迁移从MXNet Gluon到ivyimperative深度学习接口的迁移 1. 迁移背景与价值 在深度学习框架碎片化的当下MXNet Gluon作为早期imp人工智能机器学习开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表