
人工智能深度学习机器学习【免费下载链接】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/mxne/mxnet点击查看免费下载Apache MXNet 的 Gluon 接口提供与 PyTorch 几乎一致的命令式imperative编程体验同时支持通过hybridize()将网络转换为符号图以获得额外性能收益。本文以官方教程 PyTorch vs Apache MXNet 为主体完整对比两个框架在安装、数据操作、模型训练全流程中的差异结合仓库源码剖析autograd、Trainer、HybridBlock等核心机制的底层实现并附上全面的 API 对照速查表帮助 PyTorch 开发者快速完成迁移。为什么关注 PyTorch 与 MXNet 的迁移PyTorch 因其直观的 API 与彻底的命令式imperative编程风格广受欢迎。Apache MXNet 的 Gluon API 同样提供命令式的简洁与灵活在此之上还能将网络混合hybridize为符号图以利用符号计算图的性能优化能力。原教程引用了 2019 年 4 月 NVIDIA 的性能基准在训练 ResNet-50 时 Apache MXNet 达到 10,925 images/sPyTorch 为 6,175 images/s即 MXNet 领先约 77%数据来自原文档引用的 NVIDIA 官方基准请注意该数据反映的是彼时版本与硬件的对比实际表现应以当前版本实测为准。对 PyTorch 用户而言两框架的学习曲线非常平缓——核心差异集中在术语Tensor vs NDArray与梯度累积行为PyTorch 累积、MXNet 覆盖两点上其余代码几乎可以一一对应搬移。安装方式对比PyTorch 默认使用 conda 安装MXNet 则推荐 pip# PyTorchconda 安装 CPU 版本 # !conda install pytorch-cpu -c pytorch, torchvision # MXNetpip 安装 CPU 版本 # !pip install mxnetMXNet 安装 GPU 版本时需要显式指定 CUDA 版本例如安装 CUDA 10.2 支持# !pip install mxnet-cu102仓库中对应不同 CUDA 版本的构建配置位于 config/distribution如linux_cu101.cmake、linux_cu102.cmake读者可根据自身 CUDA 环境选择匹配的 pip 包。数据操作Tensor 与 NDArray两个框架都以多维矩阵作为数据载体。PyTorch 沿用 Torch 的命名习惯称为 tensorMXNet 遵循 NumPy 惯例称为 NDArray。下面的例子创建一个每个元素均为 1 的二维矩阵对每个元素加 1 后打印结果# PyTorch import torch x torch.ones(5, 3) y x 1 y# MXNet from mxnet import np x np.ones((5, 3)) y x 1 y两者唯一的明显差异是包名以及 MXNet 的形状shape参数需要像 NumPy 一样以括号包裹的元组传入np.ones((5, 3))而 PyTorch 直接传多个整数torch.ones(5, 3)。两个框架都提供了丰富的张量/NDArray 创建与操作函数。从源码结构看MXNet 的 NumPy 兼容接口由python/mxnet/numpy与 src/operator/numpy 提供mxnet.np模块目标是让 NumPy 代码几乎零成本迁移到 GPU 上运行。MNIST 实战MLP 训练的四个步骤下面以 MNIST 手写数字识别、多层感知机MLP为例将训练流程拆分为四个步骤进行逐段对比。第 1 步读取数据# PyTorch from torchvision import datasets, transforms trans transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.13,), (0.31,))]) pt_train_data torch.utils.data.DataLoader(datasets.MNIST( root., trainTrue, downloadTrue, transformtrans), batch_size128, shuffleTrue, num_workers4)# MXNet from mxnet import gluon from mxnet.gluon.data.vision import datasets, transforms trans transforms.Compose([transforms.ToTensor(), transforms.Normalize(0.13, 0.31)]) mx_train_data gluon.data.DataLoader( datasets.MNIST(trainTrue).transform_first(trans), batch_size128, shuffleTrue, num_workers4)两个框架都能自动下载 MNIST 数据集并指定仅取训练集。核心差异在于 MXNet 使用 transform_first 方法表示变换只作用于数据批的第一个元素MNIST 图片而不作用于第二个元素标签。从源码看transform_first定义于 python/mxnet/gluon/data/dataset.py其实现为self.transform(_TransformFirstClosure(fn), lazy)即内部复用了transform机制并包装一个只作用于首个元素的闭包lazyTrue默认表示按需逐个变换样本如果变换函数是随机的如数据增强必须保持 lazy 为 True否则所有 epoch 会得到相同结果。这正是 MNIST 这类图片在第一个元素、标签在第二个元素的数据集的标准用法。第 2 步创建模型下面定义一个单隐藏层 MLP输出层 10 个单元# PyTorch import torch.nn as pt_nn pt_net pt_nn.Sequential( pt_nn.Linear(28 * 28, 256), pt_nn.ReLU(), pt_nn.Linear(256, 10))# MXNet import mxnet.gluon.nn as mx_nn mx_net mx_nn.Sequential() mx_net.add(mx_nn.Dense(256, activationrelu), mx_nn.Dense(10)) mx_net.initialize()两个框架都用Sequential容器逐层堆叠网络但 MXNet 与 PyTorch 有三点差异输入尺寸可自动推断PyTorch 的Linear必须显式给出输入大小如Linear(28*28, 256)MXNet 允许省略输入维度在第一次前向传播后自动推断为网络结构设计提供了额外灵活性。激活函数直接内嵌MXNet 可以在全连接层、卷积层内直接通过activationrelu指定激活函数无需单独添加 ReLU 层。显式初始化模型结构定义完成后MXNet 需要显式调用initialize()。Sequential让层按顺序依次执行若要自定义执行流程PyTorch 可继承nn.Module并重写.forward()MXNet 则对应继承 gluon.Block。两者对应的类定义分别位于 python/mxnet/gluon/nn/basic_layers.pySequential与 python/mxnet/gluon/block.pyBlock。第 3 步损失函数与优化算法本例采用交叉熵损失cross-entropy loss与随机梯度下降SGD# PyTorch pt_loss_fn pt_nn.CrossEntropyLoss() pt_trainer torch.optim.SGD(pt_net.parameters(), lr0.1)# MXNet mx_loss_fn gluon.loss.SoftmaxCrossEntropyLoss() mx_trainer gluon.Trainer(mx_net.collect_params(), sgd, {learning_rate: 0.1})代码差异很小。主要区别是 MXNet 使用 Trainer 类将优化算法作为构造参数传入如sgd并通过 .collect_params() 获取网络全部参数。从源码看Trainer.__init__python/mxnet/gluon/trainer.py接收paramscollect_params()返回的参数字典或列表、optimizer名称与optimizer_params参数字典并支持kvstore、compression_params等分布式与梯度压缩选项collect_params()定义于 python/mxnet/gluon/block.py用于递归收集块内所有Parameter。第 4 步训练循环# PyTorch import time for epoch in range(5): total_loss .0 tic time.time() for X, y in pt_train_data: pt_trainer.zero_grad() loss pt_loss_fn(pt_net(X.view(-1, 28 * 28)), y) loss.backward() pt_trainer.step() total_loss loss.mean() print(epoch %d, avg loss %.4f, time %.2f % ( epoch, total_loss / len(pt_train_data), time.time() - tic))# MXNet from mxnet import autograd for epoch in range(5): total_loss .0 tic time.time() for X, y in mx_train_data: with autograd.record(): loss mx_loss_fn(mx_net(X), y) loss.backward() mx_trainer.step(batch_size128) total_loss loss.mean().item() print(epoch %d, avg loss %.4f, time %.2f % ( epoch, total_loss / len(mx_train_data), time.time() - tic))注意每次运行结果可能有差异因为权重初始化值不同且数据因 shuffle 读取顺序不同。MXNet 侧与 PyTorch 的差异点无需手动展平输入MXNet 前向传入数据时无需像 PyTorch 那样调用X.view(-1, 28*28)将 4-D 输入展平为 2-D。必须在autograd.record()作用域内计算只有记录作用域内的计算才会在反向传播时被自动微分。无需每步清空梯度MXNet 默认grad_reqwrite新梯度直接写入覆盖不会像 PyTorch 那样累积因此不需要trainer.zero_grad()。step()需传批大小MXNet 调用 Trainer.step 时必须指定更新步长通常为 batch size。.item()转标量MXNet 需要调用 .item() 将多维数组转为标量对应 PyTorch 的loss.mean()可直接参与标量运算。原教程提到在此示例中 MXNet 约为 PyTorch 的两倍速度同时强调这类玩具级对比需要谨慎看待不应作为框架性能的定论。深入理解 MXNet 的底层机制autograd作用域式自动微分PyTorch 通过Variable(tensor, requires_gradTrue)包装张量来记录计算图MXNet 则是作用域式记录调用attach_grad()为 NDArray 申请梯度然后在autograd.record()作用域内完成前向计算再调用backward()。# PyTorch x Variable(torch.FloatTensor(1), requires_gradTrue) y x * 2 y.backward() # MXNet x mx.nd.ones((1,)) x.attach_grad() with mx.autograd.record(): y x * 2 y.backward()源码层面record()返回一个_RecordingStateScopepython/mxnet/autograd.py进入with块时通过set_recording(True)开启记录状态、set_training(True)置为训练模式退出时自动恢复先前状态。record(train_modeTrue)的train_mode参数控制 Dropout、BatchNorm 等层在训练/预测模式下的不同行为。作用域覆盖pause、train_mode、predict_mode某些算子Dropout、BatchNorm 等在训练与预测时行为不同MXNet 通过作用域控制x mx.nd.ones((1,)) with autograd.train_mode(): y mx.nd.Dropout(x) with autograd.predict_mode(): z mx.nd.Dropout(y) w mx.nd.ones((1,)) w.attach_grad() with autograd.record(): y x * w y.backward() with autograd.pause(): w w.gradtrain_mode()/predict_mode()仅切换训练/预测行为不改变记录状态python/mxnet/autograd.py 起。pause()用于不需要计算梯度的代码段如测试、I/O、梯度更新其实现为_RecordingStateScope(False, train_mode)python/mxnet/autograd.py。惰性求值与批末同步MXNet 采用惰性求值lazy evaluation以获得更优性能Python 线程只是把操作推入底层引擎engine队列便立即返回算子实际在后台异步执行。因此训练中需要在批末做显式同步例如asnumpy()、wait_to_read()、metric.update(...)等for (data, label) in train_data: with autograd.record(): output net(data) L loss(output, label) L.backward() trainer.step(data.shape[0]) metric.update([label], [output])对应的引擎实现可参见 src/engine如threaded_engine.cc、threaded_engine_pooled.cc其中threaded_engine_pooled.cc使用线程池调度算子、实现依赖感知的异步执行。这也是MXNet 前向/反向会自动排布并行、批末同步后取结果这一编程模型的来源。HybridBlock命令式到符号式的混合HybridBlock同时支持以 Symbol 与 NDArray 前向。hybridize()之后HybridBlock 会把前向计算构建成符号图并缓存。大多数内置块Dense、Conv2D、MaxPool2D、BatchNorm 等都是 HybridBlock类定义位于 python/mxnet/gluon/block.py。net mx.gluon.nn.HybridSequential() net.add(mx.gluon.nn.Dense(10)) net.hybridize()HybridSequential定义于 python/mxnet/gluon/nn/basic_layers.py。混合化后无需显式声明输入数量只需给出输出数量输入形状会在网络首次接收输入时自动推断——这就是partial-shape部分形状信息能力。SymbolBlock从符号图构建块SymbolBlock可从 Symbol 构造块适合把预训练模型用作特征提取器alexnet mx.gluon.model_zoo.vision.alexnet(pretrainedTrue) out alexnet(inputs) internals out.get_internals() outputs [internals[model_dense0_relu_fwd_output]] feat_model gluon.SymbolBlock(outputs, inputs, paramsalexnet.collect_params())API 对照速查附录Tensor 操作对照PyTorch Tensor 与 MXNet NDArray 中函数名不同的对应关系功能PyTorchMXNet Gluon逐元素反余弦x.acos()或torch.acos(x)nd.arccos(x)批量矩阵乘并累加torch.addbmm(M, batch1, batch2)nd.linalg_gemm(M, batch1, batch2)前 n-2 维被归约逐元素除法加缩放再加张量torch.addcdiv(t, v, t1, t2)t v*(t1/t2)矩阵乘并累加torch.addmm(M, mat1, mat2)nd.linalg_gemm(M, mat1, mat2)两向量外积加矩阵m.addr(vec1, vec2)不可用逐元素应用函数x.apply_(callable)不可用但有nd.custom(x, op)逐元素反正弦x.asin()或torch.asin(x)nd.arcsin(x)逐元素反正切x.atan()或torch.atan(x)nd.arctan(x)两张量的反正切x.atan2(y)或torch.atan2(x, y)不可用批量矩阵乘x.bmm(y)或torch.bmm(x, x)nd.linalg_gemm2(x, y)从伯努利分布采样x.bernoulli()不可用用柯西分布填充x.cauchy_()不可用按维度切分张量x.chunk(num_of_chunk)nd.split(x, num_outputsnum_of_chunk)裁剪数值范围x.clamp(min, max)nd.clip(x, min, max)返回副本x.clone()x.copy()叉积x.cross(y)不可用沿轴的累积乘积x.cumprod(1)不可用沿轴的累积和x.cumsum(1)不可用首元素地址x.data_ptr()不可用生成对角张量x.diag()不可用计算张量范数x.dist()nd.norm(x)仅 L2 范数高斯误差函数x.erf()不可用广播到新形状x.expand(3, 4)x.broadcast_to([3, 4])指数分布填充x.exponential_()nd.random_exponential()逐元素取模x.fmod(3)nd.module(x, 3)小数部分x.frac()x - nd.trunc(x)按指定维度 gathertorch.gather(x, 1, torch.LongTensor([[0,0],[1,0]]))nd.gather_nd(x, nd.array([[[0,0],[1,1]],[[0,0],[1,0]]]))最小二乘/最小范数求解B.gels(A)不可用几何分布采样x.geometric_(p)不可用张量所在设备print(x)打印所在设备x.context重复张量x.repeat(4, 2)x.tile(4, 2)张量数据类型x.type()x.dtype散射torch.zeros(2, 4).scatter_(1, torch.LongTensor([[2],[3]]), 1.23)nd.scatter_nd(nd.array([1.23,1.23]), nd.array([[0,1],[2,3]]), (2,4))返回形状x.size()x.shape元素个数x.numel()x.size转为 NumPy ndarrayx.numpy()x.asnumpy()对称矩阵特征分解e, v a.symeig()v, e nd.linalg.syevd(a)转置x.t()x.T均匀分布采样torch.uniform_()nd.sample_uniform()插入新维度x.unsqueeze()nd.expand_dims(x)重塑x.view(16)x.reshape((16,))按指定张量形状查看x.view_as(y)x.reshape_like(y)类型转换副本x.type(type)x.astype(dtype)拷贝值到另一张量dst.copy_(src)src.copyto(dst)指定形状全零张量x torch.zeros(2, 3)x nd.zeros((2, 3))指定形状全一张量x torch.ones(2, 3)x nd.ones((2, 3))同尺寸全一张量y torch.ones_like(x)y nd.ones_like(x)GPU 与跨设备操作与 Tensor 类似MXNet NDArray 可通过指定 context上下文拷贝到 GPU 并在其上运算功能PyTorchMXNet Gluon拷贝到 GPUy torch.FloatTensor(1).cuda()y mx.nd.ones((1,), ctxmx.gpu(0))转成 numpy 数组x y.cpu().numpy()x y.asnumpy()上下文作用域with torch.cuda.device(1):y torch.cuda.FloatTensor(1)with mx.gpu(1):y mx.nd.ones((3, 5))跨多 GPU 拷贝功能PyTorchMXNet Gluon从 GPU 0 拷贝到 GPU 1x torch.cuda.FloatTensor(1)y x.cuda(1)x mx.nd.ones((1,), ctxmx.gpu(0))y x.as_in_context(mx.gpu(1))不同 GPU 间拷贝 Tensor/NDArrayy.copy_(x)x.copyto(y)Autograd 对照功能PyTorchMXNet Gluon记录计算过程x Variable(torch.FloatTensor(1), requires_gradTrue)y x * 2y.backward()x mx.nd.ones((1,))x.attach_grad()with mx.autograd.record():y x * 2y.backward()作用域覆盖不可用x mx.nd.ones((1,))with autograd.train_mode():y mx.nd.Dropout(x)with autograd.predict_mode():z mx.nd.Dropout(y)w mx.nd.ones((1,))w.attach_grad()with autograd.record():y x * wy.backward()with autograd.pause():w w.grad批末同步不可用for (data, label) in train_data:with autograd.record():output net(data)L loss(output, label)L.backward()trainer.step(data.shape[0])metric.update([label], [output])批末同步如asnumpy()、wait_to_read()、metric.update(...)是 MXNet 惰性求值模型下训练循环的必备操作。Module 与 Gluon Block新块定义Gluon 与 PyTorch 高度相似功能PyTorchMXNet Gluon新块定义class Net(torch.nn.Module):def __init__(self, D_in, D_out):super(Net, self).__init__()self.linear torch.nn.Linear(D_in, D_out)def forward(self, x):return self.linear(x)class Net(mx.gluon.Block):def __init__(self, D_in, D_out):super(Net, self).__init__()self.dense mx.gluon.nn.Dense(D_out, in_unitsD_in)def forward(self, x):return self.dense(x)参数与初始化PyTorch 创建层时无需指定参数初始化器各层有默认值Gluon 创建层时可以指定初始化器或留空参数在调用net.initialize(init method)后完成初始化未显式指定初始化器的层会使用传入的init方法。功能PyTorchMXNet Gluon获取全部参数net.parameters()net.collect_params()初始化网络不可用net.initialize(mx.init.Xavier())指定层初始化器layer torch.nn.Linear(20, 10)torch.nn.init.normal(layer.weight, 0, 0.01)layer mx.gluon.nn.Dense(10, weight_initializermx.init.Normal(0.01))已有块的使用几乎一致y net(x)。HybridBlock混合化后允许 partial-shape只给输出数量、输入形状自动推断功能PyTorchMXNet Gluonpartial-shape 混合化不可用net mx.gluon.nn.HybridSequential()net.add(mx.gluon.nn.Dense(10))net.hybridize()Optimizer 与 Gluon Trainer大多数情况下 Gluon API 无需调用zero_grad。zero_grad用于清空所有参数的梯度Gluon 中若grad_req write默认每个 batch 的梯度直接覆盖写入无需手动清空功能PyTorchMXNet Gluon清空梯度optm torch.optim.SGD(model.parameters(), lr0.1)optm.zero_grad()loss_fn(model(input), target).backward()optm.step()trainer gluon.Trainer(net.collect_params(), sgd, {learning_rate: 0.1})with autograd.record():loss loss_fn(net(data), label)loss.backward()trainer.step(batch_size)多 GPU 数据并行功能PyTorchMXNet Gluon数据并行net torch.nn.DataParallel(model, device_ids[0, 1, 2])output net(data)ctx [mx.gpu(i) for i in range(3)]data gluon.utils.split_and_load(data, ctx)label gluon.utils.split_and_load(label, ctx)with autograd.record():losses [loss(net(X), Y) for X, Y in zip(data, label)]for l in losses:l.backward()分布式数据并行功能PyTorchMXNet Gluon分布式数据并行torch.distributed.init_process_group(...)model torch.nn.parallel.distributedDataParallel(model, ...)store kv.create(dist)trainer gluon.Trainer(net.collect_params(), ..., kvstorestore)注意MXNet 的kvstore参数不仅支持dist分布式还支持device、local等模式其实现位于 src/kvstorekvstore_local.h、kvstore_dist.h、kvstore_nccl.h等。训练监控Gluon 提供若干预定义指标metric可在线评估模型性能功能PyTorchMXNet Gluon指标不可用metric mx.metric.Accuracy()with autograd.record():output net(data)L loss(output, label)loss(output, label).backward()trainer.step(batch_size)metric.update(label, output)数据可视化方面PyTorch 常用 TensorboardXMXNet 可用 MXBoard两者 API 风格对应PyTorchMXNetsw tensorboardX.SummaryWriter()sw mxboard.SummaryWriter()......for name, param in model.named_parameters():for name, param in net.collect_params():grad param.clone().cpu().data.numpy()grad param.grad.asnumpy().flatten()sw.add_histogram(name, grad, n_iter)sw.add_histogram(tagstr(param),...valuesgrad,sw.close()bins200,global_stepi)...sw.close()数据加载与序列化Dataset与DataLoader是加载数据的基础组件类PyTorchMXNet Gluon数组数据集torch.utils.data.TensorDataset(data_tensor, label_tensor)gluon.data.ArrayDataset(data_array, label_array)数据加载器torch.utils.data.DataLoader(dataset, batch_size1, shuffleFalse, samplerNone, batch_samplerNone, num_workers0, collate_fnfunction default_collate, drop_lastFalse)gluon.data.DataLoader(dataset, batch_sizeNone, shuffleFalse, samplerNone, last_batchkeep, batch_samplerNone, batchify_fnNone, num_workers0)顺序采样器torch.utils.data.sampler.SequentialSampler(data_source)gluon.data.SequentialSampler(length)随机采样器torch.utils.data.sampler.RandomSampler(data_source)gluon.data.RandomSampler(length)计算机视觉常用数据集由mx.gluon.data.vision包提供源码见 python/mxnet/gluon/data/vision类PyTorchMXNet GluonMNISTtorchvision.datasets.MNISTmx.gluon.data.vision.MNISTCIFAR10torchvision.datasets.CIFAR10mx.gluon.data.vision.CIFAR10CIFAR100torchvision.datasets.CIFAR100mx.gluon.data.vision.CIFAR100文件夹图像加载器torchvision.datasets.ImageFolder(root, transformNone, target_transformNone, loaderfunction default_loader)mx.gluon.data.vision.ImageFolderDataset(root, flag, transformNone)序列化与反序列化通过save_parameters与load_parameters完成类PyTorchMXNet Gluon保存模型参数torch.save(the_model.state_dict(), filename)model.save_parameters(filename)加载参数the_model.load_state_dict(torch.load(PATH))model.load_parameters(filename, ctx, allow_missingFalse, ignore_extraFalse)结论如上所见Apache MXNet 的 Gluon API 与 PyTorch 存在大量相似之处。核心差异集中在两点术语Tensor vs NDArray与梯度累积行为PyTorch 中梯度累积、MXNet 中梯度覆盖写入。其余代码结构高度对应将代码从一个框架迁移到另一个框架非常直接。推荐下一步Gluon API 与 PyTorch 相似之外还提供了一些让代码更快的能力阅读 Hybridize 教程学习如何编写可转换为符号式的命令式代码。阅读 自定义层教程了解如何用自定义层扩展 MXNet。赞分享人工智能深度学习机器学习【免费下载链接】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/mxne/mxnet点击查看免费下载相关推荐从原生 Selenium 迁移到 SeleniumBase五阶段演进实战与底层原理对照从原生 Selenium 迁移到 SeleniumBase五阶段演进实战与底层原理对照 本文以 SeleniumBase 仓库中的 examples/migr测试网页爬虫RPA如何在15分钟内完成黑苹果配置OpCore-Simplify智能EFI构建指南如何在15分钟内完成黑苹果配置OpCore Simplify智能EFI构建指南 还在为复杂的黑苹果配置而头疼吗OpCore Simplify是你的终极解决方深度学习人工智能机器学习分布式训练PyTorch与MXNet/Gluon深度学习框架全方位对比从入门到迁移实战指南PyTorch与MXNet/Gluon深度学习框架全方位对比从入门到迁移实战指南 引言框架选型的终极难题 你是否在PyTorch与MXNet/Gluon之间创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考