MXNet ndarray.random 随机数生成 API 完全指南:从均匀分布到多类别采样
2026/9/20 19:39:39 网站建设 项目流程

MXNet ndarray.random 随机数生成 API 完全指南:从均匀分布到多类别采样

【免费下载链接】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/mxnet1/mxnet

mxnet.ndarray.random是 MXNet 的命令式(Imperative)随机数生成接口,为权重初始化、数据增强、Dropout、强化学习策略采样等场景提供了一整套基于 NDArray 的分布采样能力。本文以官方 API 文档 index.rst 为核心骨架,逐一定义uniformnormalrandnpoissonexponentialgammamultinomialnegative_binomialgeneralized_negative_binomialshufflerandint等全部成员函数的参数语义与用法,并结合 Python 实现、C++ 采样算子 与 单元测试 深入其底层原理。读完本文,你将掌握 MXNet 随机 API 的完整调用方式、参数含义、设备与数据类型约束,以及随机种子控制与统计正确性验证方法。

一、模块概览:一句话看懂 mxnet.ndarray.random

在 MXNet 中,随机数生成分为两套体系:符号式(Symbolic,mx.sym.random.*)与命令式(Imperative,mx.nd.random.*)。本文聚焦后者——mxnet.ndarray.random是直接以 NDArray 为输入输出的随机分布生成器模块,其 Python 侧入口定义在 python/mxnet/ndarray/random.py:

__all__ = ['uniform', 'normal', 'randn', 'poisson', 'exponential', 'gamma', 'multinomial', 'negative_binomial', 'generalized_negative_binomial', 'shuffle', 'randint']

文档文件 docs/python_docs/python/api/ndarray/random/index.rst 使用 Sphinx 的automodule指令自动抽取上述模块的全部公开成员及其 docstring,也就是说,每个函数 docstring 中的参数说明、返回约定与交互式示例即为官方 API 文档的权威正文,本文逐条展开。

模块中的大多数采样函数(uniformnormalrandnpoissonexponentialgammanegative_binomialgeneralized_negative_binomialrandint)都经由一个统一的辅助函数_random_helper分发(见 random.py#L31-L51)。该辅助函数的核心逻辑是:

  • 若分布参数是NDArray,则所有参数必须同为 NDArray,走_sample_*系列的“多分布并行采样”路径(每个参数元素对应一条独立分布);
  • 若分布参数是Python 数值,则所有参数必须同为数值,走_random_*系列的“标量参数采样”路径,此时若未指定shape且未提供out,默认采样1个样本;
  • 若参数类型混用或非法,直接抛出ValueError

这一设计使得同一套函数既能做“从一条分布里抽 N 个样本”,也能做“从 N 组不同参数的分布里各抽若干个样本”,是理解后续 shape 规则的关键。

二、连续分布:uniform、normal、randn、exponential、gamma

2.1 uniform:均匀分布[low, high)

mx.nd.random.uniform(low=0, high=1, shape=_Null, dtype=_Null, ctx=None, out=None, **kwargs)在半开区间[low, high)(包含low,不包含high)上均匀采样。

核心参数

参数类型默认值说明
lowfloat 或 NDArray0输出区间下界,生成值均大于等于low
highfloat 或 NDArray1.0输出区间上界,生成值均小于high
shapeint 或 tuple_Null采样数量;low/high为标量时输出形状即shape
dtypestr'float32'支持'float16''float32''float64'
ctxContext当前上下文输出设备;当low为 NDArray 时被low.context覆盖
outNDArrayNone将结果写入既有 NDArray

shape 规则(本模块所有采样函数通用):若lowhigh为标量且shape=(m, n),输出形状为(m, n);若lowhigh为形状(x, y)的 NDArray,输出形状为(x, y, m, n),即对每个[low, high)参数对分别抽取m*n个样本。官方 docstring 示例:

>>> mx.nd.random.uniform(0, 1) [ 0.54881352] <NDArray 1 @cpu(0) >>> mx.nd.random.uniform(0, 1, ctx=mx.gpu(0)) [ 0.92514056] <NDArray 1 @gpu(0)> >>> mx.nd.random.uniform(-1, 1, shape=(2,)) [ 0.71589124 0.08976638] <NDArray 2 @cpu(0)> >>> low = mx.nd.array([1,2,3]) >>> high = mx.nd.array([2,3,4]) >>> mx.nd.random.uniform(low, high, shape=2) [[ 1.78653979 1.93707538] [ 2.01311183 2.37081361] [ 3.30491424 3.69977832]] <NDArray 3x2 @cpu(0)>

最后一个示例即“多分布并行采样”:low=[1,2,3]high=[2,3,4]定义了 3 条均匀分布,每条抽取 2 个样本,得到 3×2 的输出。

2.2 normal 与 randn:正态(高斯)分布

mx.nd.random.normal(loc=0, scale=1, ...)randn(*shape, **kwargs)均按loc(均值)与scale(标准差)参数化采样,二者的差异在于调用约定:

  • normaluniform同构,显式接收locscaleshape参数,也支持以 NDArray 形式传入loc/scale做多分布并行采样(见 random.py#L113-L167);
  • randn模仿 NumPy 的np.random.randn,把形状直接作为位置参数传入,如randn(2, 3),再通过关键字loc=scale=指定分布参数(见 random.py#L170-L226)。注意randn不接受shape关键字,因此无法像normal那样做多分布并行采样。
>>> mx.nd.random.randn(2, 3, loc=5, scale=1) [[4.19962 4.8311777 5.936328 ] [5.357444 5.7793283 3.9896927]] <NDArray 2x3 @cpu(0)>

randn的内部实现实际上是把locscalekwargs中弹出后转发给与normal相同的_random_normal/_sample_normal底层算子。

2.3 exponential:指数分布

mx.nd.random.exponential(scale=1, ...)的概率密度函数为

$$ f(x; \tfrac{1}{\beta}) = \frac{1}{\beta}\exp\left(-\frac{x}{\beta}\right), \quad x>0 $$

其中scale即尺度参数 $\beta = 1/\lambda$($\lambda$ 为速率参数)。一个值得注意的实现细节是:docstring 中的scale在 Python 层被换算为速率后传给底层算子(见 random.py#L328-L329):

return _random_helper(_internal._random_exponential, _internal._sample_exponential, [1.0/scale], shape, dtype, ctx, out, kwargs)

也就是说底层 C++ 算子ExponentialParam接收的是速率lam(见 sample_op.h#L63-L65),而对外暴露的 API 保持与 SciPy/NumPy 一致的scale语义,这体现了 API 层的参数语义转换设计。

2.4 gamma:Gamma 分布

mx.nd.random.gamma(alpha=1, beta=1, ...)alpha(形状参数)与beta(尺度参数)采样,二者均应大于零,默认均为 1。测试代码(test_random.py#L98-L110)验证了其统计性质:样本均值应接近alpha * beta,标准差应接近sqrt(alpha * beta**2)。示例:

>>> alpha = mx.nd.array([1,2,3]) >>> beta = mx.nd.array([2,3,4]) >>> mx.nd.random.gamma(alpha, beta, shape=2) [[ 3.24343276 0.94137681] [ 3.52734375 0.45568955] [ 14.26264095 14.0170126 ]] <NDArray 3x2 @cpu(0)>

三、离散分布:poisson、negative_binomial、generalized_negative_binomial

3.1 poisson:泊松分布

mx.nd.random.poisson(lam=1, ...)按速率参数lam(要求 ≥ 0)采样,用于建模单位时间内随机事件发生次数的计数场景。与连续分布不同,泊松采样结果始终以浮点类型返回。其均值与方差均为lam,测试在 test_random.py#L146-L158 中据此做了统计校验。

3.2 negative_binomial:负二项分布

mx.nd.random.negative_binomial(k=1, p=1, ...)k(失败实验次数上限,> 0)与p(每次实验的失败概率,∈ [0,1])为参数。测试(test_random.py#L170-L182)给出的统计关系为:均值k*(1-p)/p,标准差sqrt(k*(1-p))/p。示例:

>>> mx.nd.random.negative_binomial(10, 0.5, shape=(2,)) [ 3. 4.] <NDArray 2 @cpu(0)>

3.3 generalized_negative_binomial:广义负二项分布

mx.nd.random.generalized_negative_binomial(mu=1, alpha=1, ...)是负二项分布的“均值—离散度”参数化版本:mu为均值,alpha为离散度参数,且alpha = 1/kk为失败次数上限,此处推广到实数)。这种参数化在金融、保险等过离散(over-dispersion)计数数据建模中尤为常用。其统计性质(见 test_random.py#L194-L206)为:均值mu,标准差sqrt(mu + alpha * mu**2)

四、多类别采样与打乱:multinomial、shuffle

4.1 multinomial:多项式分布采样(强化学习的标配)

mx.nd.random.multinomial(data, shape=_Null, get_prob=False, out=None, dtype='int32', **kwargs)与前述函数差异很大:

  • 输入data必须是NDArray,其最后一维长度为k,表示每条多项式分布的k个可能结果;例如形状(m, n, k)的输入定义了m*n条各有k个结果的多项式分布。输入分布必须归一化,即data沿最后一维求和必须为 1;
  • 输出为0 起始的类别索引:对于n维输入(d1, ..., dn-1, k)与形状(s1, ..., sx)shape,返回形状为(d1, ..., dn-1, s1, ..., sx)的 NDArray;
  • get_prob=True时返回[ndarray_output, log_likelihood_output]二元组,其中对数似然数组与采样输出同形状、与data同数据类型。这一点通常用于强化学习:可将奖励作为该对数似然数组的头部梯度(head gradient)反向传播,从而估计策略梯度;
  • dtype控制采样输出类型,默认'int32';支持'uint8''int32''float16''float32''float64'(见 test_random.py#L564)。
>>> probs = mx.nd.array([0, 0.1, 0.2, 0.3, 0.4]) >>> mx.nd.random.multinomial(probs) [3] <NDArray 1 @cpu(0)> >>> probs = mx.nd.array([[0, 0.1, 0.2, 0.3, 0.4], [0.4, 0.3, 0.2, 0.1, 0]]) >>> mx.nd.random.multinomial(probs, shape=2) [[4 4] [1 2]] <NDArray 2x2 @cpu(0)> >>> mx.nd.random.multinomial(probs, get_prob=True) [3 2] <NDArray 2 @cpu(0)> [-1.20397282 -1.60943794] <NDArray 2 @cpu(0)>

实现层面,multinomial直接调用底层_sample_multinomial算子(random.py#L562),对应 C++ 实现位于 src/operator/random/sample_multinomial_op.cc。测试 test_sample_multinomial 同时验证了采样频率与输入概率一致、对数似然等于log(data[i, y[i]]/sum),以及通过prob.backward()得到的梯度与理论值一致。

4.2 shuffle:沿首轴随机打乱

mx.nd.random.shuffle(data, **kwargs)沿第一轴随机打乱数组,子数组内部元素顺序不变:对二维数组而言即打乱行序、保持行内元素顺序。它返回一个与输入同形状同类型的新 NDArray,不修改原输入

>>> data = mx.nd.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> mx.nd.random.shuffle(data) [[ 0. 1. 2.] [ 6. 7. 8.] [ 3. 4. 5.]] <NDArray 2x3 @cpu(0)>

底层算子见 src/operator/random/shuffle_op.cc 与 shuffle_op.cu。

五、整数采样:randint

mx.nd.random.randint(low, high, shape=_Null, dtype=_Null, ctx=None, out=None, **kwargs)从离散均匀分布[low, high)中采样整数

  • lowhigh均为必填 int,生成值大于等于low、小于high
  • dtype仅支持'int32'(默认)与'int64'
  • 与浮点采样函数不同,randintshape规则较简单:low/high为标量时输出形状即shape
>>> mx.nd.random.randint(5, 100) [ 90] <NDArray 1 @cpu(0) >>> mx.nd.random.randint(-10, 10, shape=(2,)) [ -5 4] <NDArray 2 @cpu(0)>

注意randint的实现只走_random_randint路径(_random_helpersampler参数传None,见 random.py#L648-L649),即不支持 NDArray 参数的多分布并行采样。

六、底层原理:C++ 采样算子与并行随机数生成

所有上述 Python 接口最终都落到 src/operator/random 目录下的 C++ 算子,其中包括:

  • sample_op.h / sample_op.cc / sample_op.cu:基础分布采样算子,参数结构体UniformParamNormalParamGammaParamExponentialParamPoissonParamNegBinomialParamGenNegBinomialParam定义于此(sample_op.h#L42-L79);
  • sampler.h:采样 functor 与并行 RNG 启动逻辑LaunchRNG
  • sample_multinomial_op.cc:多项式采样;
  • shuffle_op.cc:打乱算子;
  • pdf_op.cc:各类分布的概率密度/质量函数(random_pdf_*,支持is_log);
  • multisample_op.cc:与_like系列(如uniform_like)配合的多样本算子;
  • unique_sample_op.cc:无放回采样。

从 sampler.h#L43-L58 可以看到,LaunchRNG会将长度为N的采样任务切分为nthread个线程块(nthreadRandGenerator的状态数上限约束),每个线程独立持有自己的随机数状态,从而在 CPU/GPU 上实现高吞吐并行采样。均匀采样核函数的核心变换是:

out[i] = OType(lower[i / nBatch] + (upper[i / nBatch] - lower[i / nBatch]) * genImpl.uniform());

即对每个输出元素,先根据nBatch = 1 + (nSample - 1) / nParm定位其所属的参数对,再用[0,1)均匀随机数做线性变换——这也从源码层面印证了前文“参数为 NDArray 时输出形状(x, y, m, n)”的规则。

七、随机种子控制与可复现性

随机 API 的确定性由全局种子接口mx.random.seed(seed, ctx=None)控制。测试 test_random_seed_setting 与 test_parallel_random_seed_setting 专门验证了:在相同种子下,multinomial(使用非并行 RNG)与uniform(使用并行 RNG)无论此前是否设置过其他种子,都会生成完全一致的样本序列;而 test_random_seed_setting_for_context 进一步验证了对指定设备上下文设置种子后,不同 GPU 设备上的采样结果一致。这保证了分布式或多卡训练中随机采样的可复现性。

import mxnet as mx mx.random.seed(128) a = mx.nd.random.uniform(0, 1, shape=(100,)).asnumpy() mx.random.seed(128) b = mx.nd.random.uniform(0, 1, shape=(100,)).asnumpy() assert (a == b).all() # 相同种子下结果完全一致

八、NumPy 兼容层:mxnet.numpy.random

除命令式mxnet.ndarray.random外,MXNet 还提供了与 NumPy 风格对齐的兼容接口,定义于 python/mxnet/ndarray/numpy/random.py,其__all__['randint', 'uniform', 'normal', 'choice', 'rand', 'multinomial'],与本文接口的对应关系如下:

NumPy 兼容接口与 ndarray.random 的差异
np.random.randint(low, high=None, size=None, ...)支持high=None时等价于[0, low)size语义同 NumPy
np.random.uniform(low, high, size=None, ...)size=None时若low/high为标量则返回标量张量
np.random.normal(loc, scale, size=None, ...)同上,size替代shape
np.random.choice(a, size, replace, p, ...)支持从数组或arange(a)中按概率(加权/均匀)抽样,有放回或无放回
np.random.rand(*size)等价于uniform(0, 1, size=shape)
np.random.multinomial(n, pvals, size=None)参数化为实验次数n与各结果概率pvals,返回每类结果出现次数

这套接口让习惯 NumPy 风格的开发者可以无缝迁移,并同样支持ctxdtypeout等 MXNet 特性参数。

九、实践要点与统计正确性验证

综合源码与测试,使用本模块时有几个要点值得牢记:

  1. 参数类型必须统一:同一调用中分布参数要么全为数值、要么全为 NDArray,混用会抛出ValueError(random.py#L33-L51);
  2. 设备上下文:不显式传ctx时使用current_context();一旦分布参数中有 NDArray,输出设备自动跟随参数所在设备;
  3. dtype 约束:连续分布支持float16/float32/float64randint仅支持int32/int64multinomial的采样输出与对数似然数组类型不同(前者由dtype决定,后者与data一致);
  4. 统计性质可作为自检手段:测试文件 test_random.py 使用verify_generator配合 SciPy 的分布函数做卡方检验(如test_normal_generatortest_uniform_generator),验证生成器的分布正确性;用户也可以在训练代码中以大样本均值/方差与理论值比对来快速排查采样问题;
  5. 强化学习梯度路径multinomial(..., get_prob=True)返回的对数似然数组是可微的,配合mx.autograd.record()即可实现 REINFORCE 类策略梯度估计,参考 test_sample_multinomial 的用法。

至此,从[low, high)的均匀采样、正态/指数/Gamma 连续分布,到泊松/负二项离散计数,再到multinomial的多类别策略采样与shuffle数据打乱,mxnet.ndarray.random的 11 个成员函数已全部覆盖,且每个接口都有可对照的源码实现与统计测试作为依据,足以支撑你在初始化、数据增强与强化学习等场景中正确使用。

【免费下载链接】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/mxnet1/mxnet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询