MXNet symbol.random 随机采样 API 全解:在计算图中生成 12 种随机分布的完整指南
MXNet symbol.random 随机采样 API 全解在计算图中生成 12 种随机分布的完整指南【免费下载链接】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 符号图SymbolAPI 中的mxnet.symbol.random模块——该模块的官方文档入口位于 symbol.random 文档页它通过 Sphinx 的automodule指令自动生成 python/mxnet/symbol/random.py 中全部 12 个采样函数的 API 参考。读完本文你将掌握如何在构图阶段而非立即执行阶段把均匀、正态、Gamma、Poisson、二项、负二项、多项式等分布的随机数节点插入计算图参数为标量与参数为 Symbol 两种调用方式的区别及其底层算子分派机制以及每个 API 的完整参数、默认值、输出形状规则和 C 后端实现位置。模块定位文档页与实际模块的对应关系symbol.random 文档索引 的核心内容只有一组 Sphinx 指令.. automodule:: mxnet.symbol.random :members: :autosummary:它的作用是把 Python 模块mxnet.symbol.random的全部公开成员members连同自动生成的摘要表autosummary渲染为 API 参考页。因此理解这份文档就是理解 python/mxnet/symbol/random.py 这个模块本身。模块顶部的 docstring 明确其定位Random distribution generator Symbol API of MXNet——即面向符号图而非即时执行的随机分布生成器 API。模块通过__all__声明了 13 个公开函数见 python/mxnet/symbol/random.py__all__ [uniform, normal, randn, poisson, exponential, gamma, categorical, multinomial, binomial, negative_binomial, generalized_negative_binomial, shuffle, randint]按功能可以分为四类类别函数返回类型连续分布采样uniform、normal、randn、poisson文档按整值处理、exponential、gammaSymbol离散分布采样binomial、negative_binomial、generalized_negative_binomial、randintSymbol并行逐元素采样categorical、multinomialSymbol可返回多输出重排shuffleSymbol这些函数都位于 legacy 符号图 API 体系之下文档路径中的legacy即表明这一点调用后不会立即生成数据而是返回一个可嵌入mxnet.symbol计算图的随机算子节点在Executor前向执行时才真正采样。对应的即时执行版本位于 python/mxnet/ndarray/random.py两者函数名一一对应。核心机制_random_helper的双路分派所有参数化分布函数uniform、normal、poisson、exponential、gamma、binomial、negative_binomial、generalized_negative_binomial、randint都不直接调用算子而是统一走 python/mxnet/symbol/random.py 中的_random_helperdef _random_helper(random, sampler, params, shape, dtype, kwargs): Helper function for random generators. if isinstance(params[0], Symbol): for i in params[1:]: assert isinstance(i, Symbol), \ Distribution parameters must all have the same type, but got \ fboth {type(params[0])} and {type(i)}. return sampler(*params, shapeshape, dtypedtype, **kwargs) elif isinstance(params[0], numeric_types): for i in params[1:]: assert isinstance(i, numeric_types), \ Distribution parameters must all have the same type, but got \ fboth {type(params[0])} and {type(i)}. return random(*params, shapeshape, dtypedtype, **kwargs) raise ValueError(Distribution parameters must be either Symbol or numbers, fbut got {type(params[0])}.)从源码结构看它实现了两种调用模式的严格分派参数是数值numeric_types调用_internal._random_dist对应 C 端无输入、把参数作为算子属性传入的_random_*算子。随机节点在构图期就固化了分布参数。参数是 Symbol调用_internal._sample_dist对应 C 端_sample_*算子分布参数变成算子的输入张量采样时按元素位置并行采样concurrent sampling。混用两种类型、或传入其他类型如NDArray都会抛ValueError同一调用的多个参数类型必须一致。以uniform为例其实现只有对 helper 的一次委托python/mxnet/symbol/random.pyreturn _random_helper(_internal._random_uniform, _internal._sample_uniform, [low, high], shape, dtype, kwargs)这就是为什么文档中反复强调每个参数都是float or Symbol, optional——两种形态在 Python 层被统一签名在算子层分别落到_random_*与_sample_*两个不同的 NNVM 算子上。连续分布采样 APIuniform半开区间上的均匀分布uniform(low0, high1, shape_Null, dtype_Null, **kwargs)从半开区间[low, high)采样包含 low、不包含 high。low下界默认0可为float或Symbolhigh上界默认1.0可为float或Symbolshape采样个数如(m, n)。标量参数时输出形状即(m, n)若low/high本身是有形状的 Symbol如形状(x, y)输出形状为(x, y, m, n)——对每一对[low, high)各抽m*n个样本dtypefloat16/float32/float64默认float32_Null占位表示使用默认值。normal 与 randn高斯分布normal(loc0, scale1, shape_Null, dtype_Null, **kwargs)按均值loc与标准差scale采样形状规则与 uniform 完全一致标量参数输出(m, n)参数为形状(x, y)的 Symbol 时输出(x, y, m, n)对每对[loc, scale)各抽m*n个样本。randn(*shape, **kwargs)是 normal 的便捷变体形状通过位置参数给出*shapeloc默认 0、scale默认 1、dtype从kwargs中弹出并断言loc/scale是int、float或Symbolpython/mxnet/symbol/random.pyloc kwargs.pop(loc, 0) scale kwargs.pop(scale, 1) dtype kwargs.pop(dtype, _Null) assert isinstance(loc, (int, float, Symbol)) assert isinstance(scale, (int, float, Symbol)) return _random_helper(_internal._random_normal, _internal._sample_normal, [loc, scale], shape, dtype, kwargs)poisson、exponential、gammapoisson(lam1, shape_Null, dtype_Null, **kwargs)按速率lam期望间隔须 0采样 Poisson 分布文档注明采样结果始终以浮点类型返回Samples will always be returned as a floating point data type。lam为形状(x, y)的 Symbol 时对lam的每个条目各抽m*n个样本。exponential(scale1, shape_Null, dtype_Null, **kwargs)指数分布概率密度函数为 $f(x; \frac{1}{\beta}) \frac{1}{\beta}\exp(-\frac{x}{\beta})$$x 0$其余为 0。注意 API 暴露的是尺度参数 $\beta$而 C 算子接收的是速率参数 $\lambda 1/\beta$——Python 层在委托时做了换算python/mxnet/symbol/random.pyreturn _random_helper(_internal._random_exponential, _internal._sample_exponential, [1.0/scale], shape, dtype, kwargs)也就是说exponential(scale2)实际以lambda0.5传给_random_exponential算子。gamma(alpha1, beta1, shape_Null, dtype_Null, **kwargs)Gamma 分布alpha形状参数须 0与beta尺度参数须 0默认 1。参数为形状(x, y)的 Symbol 时对每对[alpha, beta)各抽m*n个样本。离散分布采样 APIbinomial二项分布binomial(n1, p0.5, shape_Null, dtype_Null, **kwargs)n为试验次数 0p为每次试验的成功概率0 p 1两者均可标量或 Symbol。n、p为形状(x, y)的 Symbol 时对每对[n, p)各抽m*n个样本。negative_binomial负二项分布negative_binomial(k1, p1, shape_Null, dtype_Null, **kwargs)k为失败试验的上限 0p为每次试验的失败概率0 p 1结果同样以浮点类型返回。形状广播规则与 binomial 相同参数形状(x, y)时输出(x, y, m, n)。generalized_negative_binomial广义负二项分布generalized_negative_binomial(mu1, alpha1, shape_Null, dtype_Null, **kwargs)以mu均值与alpha离散度参数化其中alpha 1/kk是负二项分布中失败次数上限的实数化推广generalized to real numbers。这使得该分布可用于计数回归如 overdispersion 建模采样结果以浮点类型返回。randint离散均匀分布randint(low, high, shape_Null, dtype_Null, **kwargs)从半开区间[low, high)的整数中均匀采样low/high均为必填整数。与浮点函数不同其dtype只接受int32或int64默认int32。从源码看randint 的 sampler 位置传的是Nonepython/mxnet/symbol/random.pyreturn _random_helper(_internal._random_randint, None, [low, high], shape, dtype, kwargs)即 randint 只有_random_randint一条路径不支持把 low/high 作为 Symbol 输入——整数边界必须在构图期确定。并行采样 APIcategorical 与 multinomialcategorical对批量类别分布并发采样categorical(data, shape_Null, get_probTrue, dtypeint32, **kwargs)直接委托给_internal._sample_categoricalpython/mxnet/symbol/random.py不走_random_helper因为它的输入是概率分布本身而非分布参数dataSymboln 维数组最后一维长度为k每个类别分布的取值数。例如形状(m, n, k)表示m*n个各有k种取值的类别分布。data必须在最后一维上归一化即沿最后一维求和为 1文档中的 note 明确要求shape每个分布抽取的样本数若为空则每个分布抽 1 个get_prob默认True。若为真除采样结果外还返回一个对数似然log likelihood数组形状与采样输出相同。文档说明其典型用途是强化学习可以把 reward 作为该数组的梯度回传从而估计策略梯度dtype采样输出的数据类型默认int32对数似然数组的 dtype 与data一致。输出形状规则输入data形状(d1, ..., dn-1, k)、shape为(s1, ..., sx)时返回符号解析后形状为(d1, ..., dn-1, s1, ..., sx)新增维度上填充从各分布中采样的0 起始索引值特例n1, x1时解析为(s1,)。get_probTrue时返回多输出符号解析为[ndarray_output, log_likelihood_output]列表。multinomial对批量多项式分布并发采样multinomial(n[1], p[[1.0]], shape_Null, dtypefloat32, **kwargs)委托给_internal._sample_multinomialpython/mxnet/symbol/random.pyn每个多项式分布的试验次数n 维数组可为标量pn1 维概率数组最后一维长度k为取值数。例如形状(m, n, k)表示m*n个各有k种取值的分布。p必须在最后一维上归一化输出形状n、p分别为标量与长度 k 的向量时输出(m, n, k)n、p形状分别为(x, y)、(x, y, k)时输出(x, y, m, n, k)即对每对[n, p)各抽m*n组样本。shuffle沿第一轴随机重排shuffle(data, **kwargs)委托给_internal._shufflepython/mxnet/symbol/random.py沿第一轴随机打乱数组每个子数组内部的元素顺序保持不变只有行的顺序随机变化。文档给出了可直接复现的示例 data mx.nd.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) a mx.sym.Variable(a) b mx.sym.random.shuffle(a) b.eval(adata) [[ 0. 1. 2.] [ 6. 7. 8.] [ 3. 4. 5.]] NDArray 3x3 cpu(0) b.eval(adata) [[ 3. 4. 5.] [ 0. 1. 2.] [ 6. 7. 8.]] NDArray 3x3 cpu(0)同一个Symbol两次eval得到不同的排列说明 shuffle 节点每次执行都会重新采样置换——这正是图内随机语义的直观体现常用于训练时的样本顺序打乱。C 后端随机算子如何注册Python 层的_random_*/_sample_*内建符号最终对应src/operator/random/下的 C 算子。_random_*算子参数即属性src/operator/random/sample_op.cc 中的注册宏揭示了结构零输入、单输出参数通过ParamParser解析并注册形状/类型/存储推断与 CPU 计算函数#define MXNET_OPERATOR_REGISTER_SAMPLE(name, ParamType) \ NNVM_REGISTER_OP(name) \ .set_num_inputs(0) \ .set_num_outputs(1) \ .set_attr_parser(ParamParserParamType) \ .set_attrmxnet::FInferShape(FInferShape, InitShapeParamType) \ .set_attrnnvm::FInferType(FInferType, SampleOpTypeParamType) \ .set_attrFResourceRequest(FResourceRequest, SampleResource) \ ... .set_attrFCompute(FComputecpu, Sample_cpu, ParamType)[src/operator/random/sample_op.cc](https://link.gitcode.com/i/f418325c986ba45c4c7f3264a69394bb)依次注册了_random_uniform、_random_normal、_random_gamma、_random_exponential、_random_poisson、_random_binomial、_random_negative_binomial、_random_generalized_negative_binomial、_random_randint并用MXNET_OPERATOR_REGISTER_SAMPLE_LIKE注册了各自的_random_*_like变体以输入张量形状决定输出形状。值得注意的是_random_uniform还保留了向后兼容别名src/operator/random/sample_op.ccMXNET_OPERATOR_REGISTER_SAMPLE(_random_uniform, SampleUniformParam) .add_alias(uniform) .add_alias(random_uniform)两个值得注意的实现细节所有随机算子都声明了FResourceRequest - SampleResource即执行时向资源管理器申请随机数生成器资源这是同一符号多次执行产生不同结果的基础_like变体设置了FIgnoreInputs并只使用输入的 shape/typeElemwiseShape1,1/ElemwiseType1,1输入数据本身被忽略——它只用于推断输出形状。_sample_*算子参数即输入src/operator/random/multisample_op.cc 通过MXNET_OPERATOR_REGISTER_SAMPLING宏注册参数张量化的采样算子MXNET_OPERATOR_REGISTER_SAMPLING2(uniform, uniform_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING2(normal, normal_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING2(gamma, gamma_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING1(exponential, exponential_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING1(poisson, poisson_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING2(binomial, binomial_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING2(negative_binomial, negative_binomial_s, ...) MXNET_OPERATOR_REGISTER_SAMPLING2(generalized_negative_binomial, ...)SAMPLING1/SAMPLING2的差别在于分布参数的个数1 个或 2 个与 Python 层_random_helper中标量走_random_*、Symbol 走_sample_*的分派严格对应。[src/operator/random/multisample_op.cu](https://link.gitcode.com/i/f5b11d21d59cb68fe30b6e24525fb9ef)提供对应的 GPU 实现因此这些算子可以落在mx.gpu()上执行。categorical、multinomial分别由src/operator/random/multisample_op.cc与 src/operator/random/sample_multinomial_op.cc 实现shuffle由 src/operator/random/shuffle_op.cc含 GPU 实现shuffle_op.cu实现。实践要点与使用边界Symbol 参数与 NDArray 参数不可混用_random_helper只接受全 Symbol或全数值两种模式categorical/multinomial的data/n/p则是纯粹的 Symbol分布本身不存在标量路径。符号解析形状所有标量参数 shape调用在参数为标量时解析形状即shape本身参数为带形状 Symbol 时解析形状为参数形状 shape的拼接这是构建逐位置分布如每个样本独立的(mu, scale)的关键约定。随机节点可重复执行shuffle 的示例已经证明同一Symbol多次eval产生不同结果所有随机算子同理每次前向都会重新采样。别名与历史遗留C 层uniform、random_uniform是_random_uniform的弃用别名本文介绍的是 legacy 符号图 API文档位于legacy/symbol/random/目录下新代码若使用 Gluon/即时执行风格对应入口是 python/mxnet/ndarray/random.py 中的mx.random模块函数签名与行为同构。导出与精度_random_uniform等算子有 ONNX 转换路径见 python/mxnet/onnx/mx2onnx/_op_translations/_op_translations_opset12.py且_random_uniform、_sample_uniform等被列入 AMP 白名单见 python/mxnet/amp/lists/symbol_fp16.py说明随机算子在混合精度与模型导出场景下是一等公民。速查表函数分布关键参数默认值dtype默认备注uniform均匀 [low, high)low0, high1float32半开区间normal高斯loc0, scale1float32randn高斯*shape, loc0, scale1float32shape 为位置参数poissonPoissonlam1float32结果按浮点返回exponential指数scale1float32内部换算为 lambda1/scalegammaGammaalpha1, beta1float32alpha、beta 须 0binomial二项n1, p0.5float32negative_binomial负二项k1, p1float32p 为失败概率generalized_negative_binomial广义负二项mu1, alpha1float32alpha1/k 实数化randint离散均匀 [low, high)low/high 必填int32仅 int32/int64无 Symbol 参数路径categorical类别批量data 必填, get_probTrueint32data 末维须归一化可回传对数似然multinomial多项式批量n[1], p[[1.0]]float32p 末维须归一化shuffle重排data 必填与输入一致沿第一轴打乱以上每个 API 的完整参数语义、形状规则与默认值均以 python/mxnet/symbol/random.py 的 docstring即 symbol.random 文档页 的渲染来源为准C 算子行为可进一步在src/operator/random/目录中查证。【免费下载链接】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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考