ARTICLE DETAIL

资讯详情

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

MXNet numpy.ndarray 完全指南:N 维数组的构造、索引、内存布局与操作算子

MXNet numpy.ndarray 完全指南:N 维数组的构造、索引、内存布局与操作算子 人工智能深度学习机器学习【免费下载链接】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点击查看免费下载mxnet.np.ndarray是 MXNet 提供的与 NumPy 风格一致的 N 维数组核心类型它将深度学习框架的算子加速能力CPU/GPU、自动微分、混合精度与 NumPy 的编程习惯统一起来。本文以官方 API 文档 arrays.ndarray.rst 为主线结合 multiarray.py 的源码实现系统讲解 ndarray 的构造方式、三种索引语义、内部内存布局、属性与方法体系以及算术/比较/矩阵乘法等运算符行为帮助你在 MXNet 中写出既符合 NumPy 习惯又能充分利用框架性能的数组代码。什么是 mxnet.np.ndarray一个ndarray是一个通常大小固定的多维容器其中的元素具有相同的类型与大小。数组的维度数与元素个数由其shape属性定义——shape是一个由 N 个非负整数组成的tuple分别指定每个维度的大小元素的类型则由与每个 ndarray 关联的独立数据类型对象dtype指定。与 Python 中其他容器对象一样ndarray 的内容可以通过索引或切片例如使用 N 个整数来访问和修改也可以通过 ndarray 的方法和属性来操作。基本示例官方文档给出一个 2×3、由 4 字节整数元素组成的二维数组示例 x np.array([[1, 2, 3], [4, 5, 6]], np.int32) type(x) class mxnet.numpy.ndarray x.shape (2, 3) x.dtype dtype(int32)数组可以用 Python 容器式语法进行索引 # 第 *二* 行、第 *三* 列的元素即 6 x[1, 2] array(6, dtypeint32) # 这与官方 NumPy 不同官方返回 np.int32 对象视图view与基数组base不同的 ndarray 可以共享同一份数据因此对一个 ndarray 的修改可能在另一个 ndarray 中可见。也就是说一个 ndarray 可以成为另一个 ndarray 的“视图”view它所引用的数据由“基数组”base负责管理。当切片取到的元素在内存中是连续contiguous的时切片会产生原数组的视图 y x[1,:] y array([9, 5, 6], dtypeint32) # 同时修改了 x 中对应的元素 x array([[1, 2, 3], [9, 5, 6]], dtypeint32)从源码看这一行为由 multiarray.py 中的_get_np_basic_indexing实现当_basic_indexing_slice_is_contiguous判定切片连续时会先reshape_view(-1)展平再通过MXNDArraySlice/MXNDArraySlice64底层接口创建共享内存的低层切片最后用reshape_view恢复形状——全程零拷贝。构造数组新数组可以通过数组创建例程如array、zeros、empty、ones、full、eye、identity、arange、linspace等构造也可以使用低层ndarray构造函数。在 multiarray.py 中ndarray类的文档明确说明“数组应使用array、zeros或empty构造。目前仅支持 C-contiguous 数组。”其构造参数为参数说明handle: int后端C中的 ndarray 句柄writable: bool是否允许对该数组进行原地inplace赋值默认 dtype 策略与官方 NumPy 的差异MXNet 的array在默认 dtype 上与官方 NumPy 不同官方 NumPy 默认float64而 MXNet 作为深度学习框架默认float32。源码 multiarray.py 中当npx.is_np_default_dtype()返回False时默认 dtype 为float32当返回True时默认 dtype 为float64。可通过npx.set_np(dtypeTrue)将默认 dtype 切换为与官方 NumPy 一致。empty的实现multiarray.py同样遵循此策略且只接受orderC其余 order 会抛出NotImplementedError。 np.array([1, 2, 3]).dtype dtype(float32) npx.set_np(dtypeTrue) np.array([1, 2, 3]).dtype dtype(float64)索引数组数组可以使用扩展的 Python 切片语法array[selection]进行索引。完整语义见索引专题文档共有三种索引类型基本切片basic slicing、高级索引advanced indexing和布尔掩码索引boolean mask indexing具体触发哪种取决于选择对象obj。在 Python 中x[(exp1, exp2, ..., expN)]等价于x[exp1, exp2, ..., expN]后者只是前者的语法糖。基本切片与索引当obj是slice对象由方括号内的start:stop:step表示法构造、整数或由切片对象与整数组成的元组时触发基本切片。Ellipsis...和newaxis即None对象也可以穿插其中。需要记住的几条要点基本切片语法为i:j:k其中i是起始索引、j是终止索引、k是步长k≠0。它选出索引值为i, ik, ..., i(m-1)k的m个元素负的i和j被解释为ni和njn为该维度的元素个数负的k使步进朝索引减小的方向进行若i未给出k0时默认为 0k0时默认为n-1若j未给出k0时默认为nk0时默认为-n-1若k未给出则默认为 1。::与:相同表示沿该轴选择所有索引若选择元组中对象的个数少于N则后续维度默认按:处理Ellipsis展开为补齐选择元组到所有维度所需的:个数且整条索引中只能出现一个省略号每个newaxis对象会使结果增加一个单位长度的维度位置即newaxis在元组中的位置整数i与i:i1返回相同元素区别在于返回对象的维度会减少 1基本切片产生的结果总是原数组的视图前提是取到的元素在内存中连续可以用切片给数组赋值但与 list 不同永远无法让数组增长x[obj] value中 value 的大小必须可广播到x[obj]的形状。官方文档示例 x np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) x[1:7:2] array([1, 3, 5]) x[-2:10] array([8, 9]) x[-3:3:-1] array([7, 6, 5, 4]) x[5:] array([5, 6, 7, 8, 9])切片元组始终可以构造为obj对象并使用x[obj]记号例如x[1:10:5,::-1]可写成obj (slice(1,10,5), slice(None,None,-1)); x[obj]这对编写面向任意维数组的通用代码很有用。高级索引整数数组索引当选择对象obj是非元组的序列对象、整数或布尔类型的 ndarray或至少含一个序列对象/ndarray 的元组时触发高级索引。高级索引总是返回数据的副本与基本切片部分情况返回视图形成对比。纯整数数组索引当索引中的整数数组个数与数组维度数相同且可广播时result[i_1, ..., i_M] x[ind_1[i_1, ..., i_M], ..., ind_N[i_1, ..., i_M]]结果形状与广播后的索引数组形状相同 x np.array([[1, 2], [3, 4], [5, 6]]) x[[0, 1, 2], [0, 1, 0]] array([1, 4, 5])高级与基本索引混合当高级索引之间被切片、Ellipsis或newaxis隔开时如x[arr1, :, arr2]高级索引产生的维度位于结果数组最前面当高级索引紧挨在一起时如x[..., arr1, arr2, :]高级索引产生的维度插入到与原数组相同的位置。示例若x.shape为 (10,20,30) 且ind是形状 (2,3,4) 的索引数组则x[...,ind,:]的形状为 (10,2,3,4,30)。⚠️x[(1,2,3),]与x[(1,2,3)]有本质区别后者等价于x[1,2,3]基本选择前者触发高级索引。另外x[[1,2,slice(None)]]在官方 NumPy 中会触发基本切片但 MXNet 的numpy模块当前不支持该写法。布尔数组索引当obj是布尔类型的数组例如比较运算符的返回值时发生。若obj.ndim x.ndimx[obj]返回一个一维数组按行主序C 风格填充obj中为True的位置对应的x元素若obj比x小则等价于用False填充补齐。 x np.array([[0, 1], [1, 1], [2, 2]], dtypenp.int32) rowsum x.sum(-1) x[rowsum 2] array([[0, 1], [1, 1]], dtypeint32)⚠️ MXNet 当前仅支持单个布尔 ndarray 作为索引含布尔数组的复合索引暂不支持见 arrays.indexing.rst。当布尔索引形状与x不一致时会抛出IndexError。从源码看索引分派逻辑在 multiarray.py 中定义了_NDARRAY_BASIC_INDEXING、_NDARRAY_ADVANCED_INDEXING、_NDARRAY_EMPTY_TUPLE_INDEXING等返回码__getitem__multiarray.py根据键类型分别路由到_get_np_basic_indexing、_get_np_advanced_indexing底层调用gather_nd与_get_np_boolean_indexing底层调用boolean_mask__setitem__multiarray.py则对应使用scatter_set_nd、boolean_mask_assign_scalar/tensor等算子完成就地写入。ndarray 的内部内存布局一个ndarray实例由一段连续的一维计算机内存由数组本身或某个其他对象持有与一个索引方案组成该索引方案将 N 个整数映射到块中某个元素的位置。索引可变化的范围由数组的shape指定每个元素占多少字节、字节如何解释由与数组关联的数据类型对象定义。跨步strides与偏移公式内存段本质上是一维的将 N 维数组的元素排列进一维块有无数种方案。在跨步strided方案中N 维索引(n_0, n_1, ..., n_{N-1})对应从内存块起始处的字节偏移n_offset Σ_{k0}^{N-1} s_k · n_k其中s_k是整数即数组的strides跨步。列主序Fortran、Matlab 使用与行主序C 使用只是跨步方案的两种特例分别对应可由跨步寻址的内存s_k^column itemsize · Π_{j0}^{k-1} d_js_k^row itemsize · Π_{jk1}^{N-1} d_j其中d_j self.shape[j]。C 序与 Fortran 序都是连续single-segment的内存布局块的每个部分都能被某种索引组合访问到。连续性与对齐的边界情况虽然 C 风格与 Fortran 风格连续的数组可以按上述跨步寻址但实际跨步可能不同这发生在两种情况下若self.shape[k] 1则对任意合法索引index[k] 0此时s_k · n_k 0s_k self.strides[k]的取值是任意的若数组没有元素self.size 0则不存在合法索引跨步永远不会被使用。任何无元素数组都可以认为既是 C 风格连续又是 Fortran 风格连续。要点 1 意味着self与self.squeeze()始终具有相同的连续性与aligned标志这也意味着即使高维数组也可能同时是 C 风格与 Fortran 风格连续的。一个数组被认为是**对齐aligned**的当所有元素的内存偏移以及基偏移本身都是self.itemsize的倍数。理解内存对齐可以在大多数硬件上获得更好的性能。⚠️ 上述要点 (1)(2) 在官方 NumPy 中默认并不生效从 NumPy 1.8.0 起只有在构建时定义了环境变量NPY_RELAXED_STRIDES_CHECKING1才一致生效。可以用np.ones((10,1), orderC).flags.f_contiguous是否为True来检查你的 NumPy 是否启用了 relaxed strides checking。⚠️ 一般情况下不能假定 C 风格连续数组满足self.strides[-1] self.itemsize或 Fortran 风格连续数组满足self.strides[0] self.itemsize。MXNet 的实现限制与自动拷贝官方文档特别注明mxnet.numpy.ndarray目前仅支持以 C 序行主序连续内存存储元素上述关于多种内存布局的解释是从官方 NumPy 文档摘录的综合性参考。新 ndarray 中的数据默认按行主序C排列但基本数组切片经常产生不同方案的视图。NumPy 中若干算法可作用于任意跨步数组但有些算法要求单段single-segment数组——当把不规则跨步的数组传给这类算法时会自动制作一份拷贝。MXNet 的实现同样遵循这一原则例如reshape仅接受orderC见 multiarray.py其余 order 抛出NotImplementedError。数组属性数组属性反映数组本身固有intrinsic的信息。通常通过属性访问数组可以获取、有时也能设置数组的内在属性而无需创建新数组。暴露的属性是数组的核心组成部分其中只有一部分可以在不创建新数组的情况下被有意义地重置。内存布局相关属性属性含义ndarray.shape数组维度的元组。实现见 multiarray.py通过MXNDArrayGetShape/MXNDArrayGetShape64底层接口获取ndarray.ndim数组的维度数即len(self.shape)multiarray.pyndarray.size数组中的元素总数multiarray.py数据类型属性与数组关联的数据类型对象可以通过dtype属性获取。MXNet 的dtype返回的是一个官方numpy.dtype对象_np.dtype(...)便于与 NumPy 生态互操作 x np.zeros((2,3)) x.dtype dtype(float32) y np.zeros((2,3), dtypeint32) y.dtype dtype(int32)数组方法ndarray对象拥有许多对数组进行某种运算、通常返回数组结果的方法。下述方法在mxnet.numpy中也有对应的自由函数all、any、argmax、argmin、argpartition、argsort、choose、clip、compress、copy、cumprod、cumsum、diagonal、imag、max即amax、mean、min即amin、nonzero、partition、prod、ptp、put、ravel、real、repeat、reshape、round即around、searchsorted、sort、squeeze、std、sum、swapaxes、take、trace、transpose、var。数组转换方法说明ndarray.item将数组元素复制为标准 Python 标量multiarray.pyndarray.copy返回数组的拷贝order参数仅支持Cmultiarray.pyndarray.tolist将数组转换为 Python listmultiarray.pyndarray.astype转换数组的 dtype支持order、casting、subok、copy参数multiarray.py形状操作对于reshape、resize和transpose单个元组参数可以用n个整数替换这n个整数会被解释为 n 元组。例如a.reshape(10, 11)等价于a.reshape((10, 11))multiarray.py。方法说明ndarray.reshape返回具有新形状的数组拷贝语义仅 C 序ndarray.transpose反转或按给定轴排列数组的维度ndarray.swapaxes交换两个轴返回拷贝multiarray.pyndarray.flatten返回展平为一维的拷贝order仅支持Cmultiarray.pyndarray.squeeze移除形状中长度为 1 的维度multiarray.py元素选择与操作对于接受axis关键字的数组方法axis默认为None。若axis为None数组被当作 1-D 数组处理axis的任何其他值表示操作应沿该维度进行。方法说明ndarray.nonzero返回非零元素的下标元组multiarray.pyndarray.take沿给定轴按索引取元素mode参数控制越界行为multiarray.pyndarray.repeat沿指定轴重复元素multiarray.pyndarray.argsort返回排序后索引MXNet 扩展支持descending与stable参数multiarray.pyndarray.sort原地排序同样支持descending与stable参数multiarray.py计算归约方法许多方法接受名为axis的参数若axis为None默认数组被当作 1-D 数组对整个数组执行操作。当self是 0 维数组或数组标量时这也是默认行为数组标量是 float32、float64 等类型/类的实例而 0 维数组是恰好包含一个数组标量的 ndarray 实例若axis是整数则沿给定轴执行操作对该轴可创建的每个 1-D 子数组。官方文档给出 3×3×3 数组沿三个轴分别求和的完整示例 x array([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8]], [[ 9, 10, 11], [12, 13, 14], [15, 16, 17]], [[18, 19, 20], [21, 22, 23], [24, 25, 26]]]) x.sum(axis0) array([[27, 30, 33], [36, 39, 42], [45, 48, 51]]) # 对于 sumaxis 是第一个关键字参数所以可以省略名字直接传值 x.sum(0), x.sum(1), x.sum(2) (array([[27, 30, 33], [36, 39, 42], [45, 48, 51]]), array([[ 9, 12, 15], [36, 39, 42], [63, 66, 69]]), array([[ 3, 12, 21], [30, 39, 48], [57, 66, 75]]))参数dtype指定归约操作如求和应在哪种数据类型上进行。默认归约数据类型与self相同为避免溢出使用更大的数据类型进行归约会很有用。多个方法还接受可选的out参数结果将放入给定的输出数组中。out参数必须是ndarray且元素个数相同它可以是不同的数据类型此时会执行类型转换casting。归约方法清单max、argmax、min、argmin、clip、sum、mean、prod、cumsum、var、std、round、all、any。其中sum、prod、mean、std、var的实现见 multiarray.pymax/min/round等见 multiarray.py。算术、矩阵乘法与比较运算ndarray 上的算术与比较运算定义为逐元素element-wise操作一般产生ndarray对象作为结果。每个算术运算、-、*、/、//、%、divmod()、**/pow()、、、、^、|、~和比较运算、、、、、!都等价于 NumPy 中对应的通用函数universal function简称 ufunc。比较运算符与真值测试比较运算符通过特殊方法实现__lt__、__le__、__gt__、__ge__、__eq__、__ne__。数组的真值测试bool()调用__bool__multiarray.py⚠️ 若数组中元素个数大于 1__bool__会抛出错误因为此类数组的真值具有歧义。一元运算与算术一元运算__neg__取负、__abs__绝对值、__invert__按位取反。算术运算__add__、__sub__、__mul__、__truediv__、__mod__、__pow__、__and__、__or__、__xor__。需要注意的细节调用pow()时传入的任何第三个参数会被静默忽略因为底层powerufunc 只接受两个参数三种除法运算符均已定义默认激活div当__future__除法生效时激活truediv由于 ndarray 是用 C 编写的内置类型__r{op}__特殊方法并未直接定义实现许多算术特殊方法所调用的函数可以通过__array_ufunc__修改。原地in-place算术原地算术__iadd__、__isub__、__imul__、__itruediv__、__imod__、__iand__、__ior__、__ixor__。⚠️ 原地运算将使用两个操作数数据类型决定的精度进行计算但会静默降位downcast结果如有必要以便放回数组。因此对混合精度计算A {op} B可能与A A {op} B不同。例如设a ones((3,3))则a 3j与a a 3j不同两者执行相同的计算但a 3j将结果降位以放回a而a a 3j将名字a重新绑定到结果。矩阵乘法ndarray.__matmul__multiarray.py实现运算符对应matmul算子在 MXNet 中会路由到后端优化过的矩阵乘实现。与官方 NumPy 的互操作mxnet.numpy.ndarray通过__array_ufunc__multiarray.py与__array_function__multiarray.py协议与官方 NumPy 互操作当 mxnet ndarray 与官方 numpy 数组混合运算时结果类型遵循既定规则如c a b中只要有一个操作数是 mx_np结果就是 mx_np对于未在 MXNet 中实现的 ufunc/函数会回退到官方 NumPy 的实现并打印一次 fallback 警告若在 autograd 记录作用域内回退则会抛出ValueError提示因为回退到 NumPy 的算子无法参与 MXNet 的自动微分此外还实现了__array_namespace__Array API 协议与__dlpack__/__dlpack_device__DLPack 零拷贝互操作使得该数组可以被标准数组 API 生态与 DLPack 消费者直接消费。特殊方法标准库函数ndarray.__reduce__与ndarray.__setstate__支持pickle序列化multiarray.py。基础定制ndarray.__new__支持子类化与底层句柄构造。容器定制ndarray.__len__返回第一个轴的长度multiarray.py、__getitem__multiarray.py、__setitem__multiarray.py索引语义详见索引专题。转换与字符串表示__index__、__int__、__float__multiarray.py仅对只有一个元素的数组生效返回相应的标量。__str__multiarray.py与__repr__multiarray.py负责数组的字符串表示。验证与测试仓库中针对mxnet.np.ndarray的测试覆盖了上述全部语义可作为深入研读的参考test_numpy_op.py 中的test_np_reshape验证 reshape 的多种调用形式元组参数与分离参数test_numpy_op.py 中的test_np_transpose及其错误用例test_np_transpose_error验证轴置换语义test_numpy_op.py 中的test_np_broadcast_to验证广播到新形状的行为test_numpy_default_dtype.py 验证默认 dtype 在float32/float64之间的切换策略test_numpy_interoperability.py 验证与官方 NumPy 的混合运算与回退行为。小结mxnet.np.ndarray在 MXNet 中承担着“NumPy 兼容接口 框架级算子加速”的双重角色构造上array/zeros/empty等例程按深度学习习惯默认使用float32并可通过npx.set_np(dtypeTrue)切换为float64索引上完整支持基本切片返回视图、整数数组高级索引返回拷贝与布尔掩码索引底层由slice/gather_nd/boolean_mask等算子实现内存布局上目前仅支持 C 序行主序连续存储视图与基数组共享数据运算上逐元素算术、比较、矩阵乘法与归约方法一应俱全并通过__array_ufunc__/__array_function__协议与官方 NumPy 无缝互操作。掌握这些语义后你既可以用熟悉的 NumPy 心智模型编写 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点击查看免费下载相关推荐MXNet mxnet.np 数组对象指南ndarray 的构建、索引、内存布局与源码实现MXNet mxnet.np 数组对象指南ndarray 的构建、索引、内存布局与源码实现 本文基于 MXNet 官方 API 参考文档 arrays.rst深度学习人工智能机器学习分布式训练NumPy ndarray 权威指南N 维数组的内存布局、属性、方法与运算全解析NumPy ndarray 权威指南N 维数组的内存布局、属性、方法与运算全解析 导读 numpy.ndarray 是 NumPy 的核心数据结构也是整个科科学计算数据分析MXNet.numpy ndarray 详解多维数组的数据模型、内存布局与操作方法MXNet.numpy ndarray 详解多维数组的数据模型、内存布局与操作方法 本篇以 MXNet 官方 Python API 文档 arrays.nda深度学习人工智能机器学习分布式训练创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表