并通过解析Python中的参数,将它们转换成C++中的对应类型,然后调用imperative::apply,进入dispatch(https://github.com/MegEngine/MegEngine/blob/master/imperative/python/megengine/functional/tensor.py#L995)层。 部分functional的op不直接调用py
apply 是在Python 层调用底层 op 的接口,apply 的第一个参数是 op(通过 builtin 获得),后面的参数是执行这个 op 需要的参数,都为 Tensor。在 imperative 中op 计算通过 apply(op, inputs) 的方式向下传递并最终调用到 MegDNN 中的kernel。 Functional 中的许多 op 都需要通过 builtin 和apply 调用底层 MegD...
x = mge.tensor(np.random.randn(2, 3, 32, 32).astype(np.float32)) two_layer_conv_module = TwoLayerConv() out = two_layer_conv_module(x) print(out.shape) 输出: (2, 16, 28, 28) 使用Module定义的网络比使用functional进一步封装了内部实现,更易复用,统一的接口使得代码更易维护。推荐使用M...
算子的输入和输出数据都是 Tensor 类型。算子的参数通常由 Parameter 类表示。 Parameter 是Tensor 的子类,其对象(即网络参数)可以被优化器更新。更多内容参见 网络的训练和测试。 下面的例子实现了一个两层卷积网络(使用 ReLU 作为激活函数): import megengine as mge import megengine.functional as F import numpy...
算子的输入和输出数据都是Tensor类型。算子的参数通常由Parameter类表示。Parameter是Tensor的子类,其对象(即网络参数)可以被优化器更新。更多内容参见网络的训练和测试。 下面的例子实现了一个两层卷积网络(使用ReLU作为激活函数): importmegengineasmge importmegengine.functionalasF ...
前面我们提到在functional模块中封装了很多算子,并以python接口的形式提供。实际上这些算子需要向下发射指令对tensor进行操作并返回操作完成后的tensor,这些发射的op指令就会到dispatch层,在进行实际计算之前,dispatcher会对tensor做一些处理,我们把这些处理叫作Transformation。
实际上,在MegBrain的Computing Graph中已经有了非常多的算子实现,因此MegEngine的Imperative借助张量解释器Tensor Interpreter较多地复用了MegBrain中的op。这样做的原因是: 重写算子代价高,且容易写错。 若Imperative的实现和MegBrain的实现不一致的话,容易导致训练推理不一致。
在python 中,Op 会被封装成 functional 和 module,这才是符合一般算法同学认知的 Op。 而从python 中执行一个操作时,这些 Op 会逐层向下调用,分别在每一层完成一部分工作,直到最后才调用了 MegDNN 算子库中具体的 kernel。这个过程中,任何一个层次的 Op 概念都是缺一不可的。其实不只是 Op,包括 Tensor 在...
假设我们要将 PyTorch 中的数据转换为 MegEngine Tensor,可以使用如下代码: importmegengine.tensorasmge_tensor# 从 PyTorch Tensor 转换到 MegEngine Tensorforimages,labelsintrain_loader:images_mge=mge_tensor.tensor(images.numpy())# 将PyTorch的Tensor转为numpy,再转为MegEngine Tensorlabels_mge=mge_tensor.tenso...
MegEngine 现在是动态执行的,即 python 中每一个 mge.functional 的调用都对应着底层 gpu 上的一次 kernel 执行。这种模式的好处在于实际的执行方式与代码逻辑一致,所见即所得,非常的灵活;不过其问题是难以优化,性能可能不是最优。 而XLA 采取静态执行的方式,会将模型计算过程表达成一张静态计算图,称为 “HLO” ...