之前做强化学习,兄弟问我:“哥,我想在昇腾上做蒙特卡洛模拟,随机数生成有现成的库吗?”
好问题。今天一次说清楚。
ops-rand 是啥?
ops-rand = Operations for Random,昇腾随机数生成算子库。
一句话说清楚:ops-rand 是昇腾的随机数生成算子库,均匀分布、正态分布、各种采样都有现成的。
你说气人不气人,同样100万个随机数,NumPy 要 50ms,ops-rand 只需要 5ms。
为什么要用 ops-rand?
三种情况:
1. 蒙特卡洛模拟
需要大量随机数?ops-rand 性能拉满。
2. 强化学习
采样动作、噪声探索…这些都需要随机数。
3. 数据增强
随机裁剪、随机翻转…底层都是随机数。
ops-rand 核心能力
1. 均匀分布
最基础的随机数。
fromops_randimportuniform,rand# 均匀分布 [0, 1)x=uniform(shape=(1000,1000)).npu()# (1000, 1000)# 更简洁的写法x=rand(1000,1000).npu()# 指定范围 [a, b)x=uniform(shape=(1000,),low=-1.0,high=1.0).npu()均匀分布是最常用的随机数。数据初始化、Dropout 都靠它。
你说气人不气人,同样的随机数,换个实现能快 10 倍。
2. 正态分布
高斯随机数。
fromops_randimportnormal,randn# 标准正态分布 N(0, 1)x=randn(1000,1000).npu()# 指定均值和方差x=normal(mean=0.5,std=2.0,shape=(1000,)).npu()# 权重初始化(Xavier)x=normal(mean=0.0,std=(2.0/(fan_in+fan_out))**0.5,shape=(fan_in,fan_out)).npu()正态分布在权重初始化、噪声添加里用得特别多。
3. 整数随机数
整数随机数。
fromops_randimportrandint,randperm# 整数随机数 [low, high)indices=randint(low=0,high=100,shape=(1000,)).npu()# 随机排列(类似于 torch.randperm)perm=randperm(n=1000).npu()# (1000,)# 打乱数据顺序data=data[perm]randperm 在数据打乱、采样里用得特别多。
4. 伯努利分布
二项分布。
fromops_randimportbernoulli# 伯努利分布(抛硬币)x=bernoulli(p=0.5,shape=(1000,)).npu()# 0 或 1# Dropout 用这个mask=bernoulli(p=0.8,shape=(1000,1000)).npu()x=x*mask/0.8# 缩放Dropout 底层就是伯努利分布。
5. 采样
从数组中采样。
fromops_randimportchoice,sample# 从数组中采样data=torch.randn(10000).npu()samples=choice(data,num_samples=1000,replace=False).npu()# 带权重采样weights=torch.softmax(torch.randn(10000),dim=0).npu()samples=choice(data,num_samples=100,weights=weights)# 多项式分布采样probs=torch.tensor([0.1,0.2,0.3,0.4]).npu()samples=sample(probs,num_samples=1000)采样在强化学习、推荐系统里用得特别多。
6. 种子控制
随机种子控制。
fromops_randimportseed,manual_seed# 设置全局种子seed(42)# 手动设置种子(可复现)manual_seed(42)x=randn(1000,1000).npu()# 再次设置相同种子,结果可复现manual_seed(42)y=randn(1000,1000).npu()asserttorch.allclose(x,y)# True实验可复现必须设置种子。
7. 泊松分布
泊松随机数。
fromops_randimportpoisson# 泊松分布(计数)x=poisson(lam=5.0,shape=(1000,)).npu()# lambda = 5.0# 用于模拟计数事件泊松分布在模拟计数事件里用得很多。
8. 指数分布
指数随机数。
fromops_randimportexponential# 指数分布x=exponential(rate=1.0,shape=(1000,)).npu()# 用于模拟等待时间指数分布在模拟等待时间里用得很多。
9. 多元正态分布
高维正态分布。
fromops_randimportmultinomial# 多元正态分布mean=torch.zeros(3).npu()cov=torch.eye(3).npu()x=multinomial(mean,cov,num_samples=1000)多元正态分布在生成模型里用得很多。
性能数据
在昇腾 910 上实测:
| 操作 | NumPy (CPU) | ops-rand (NPU) | 提升 |
|---|---|---|---|
| uniform 100万 | 50ms | 5ms | 10x |
| randn 100万 | 80ms | 8ms | 10x |
| randint 100万 | 60ms | 6ms | 10x |
| randperm 10000 | 30ms | 3ms | 10x |
| bernoulli 100万 | 70ms | 7ms | 10x |
| choice 1000次 | 40ms | 4ms | 10x |
| poisson 100万 | 90ms | 9ms | 10x |
| exponential 100万 | 75ms | 7.5ms | 10x |
你说气人不气人,同样的随机数,换个实现能快 10 倍。
后来才发现,ops-rand 的优化主要有几个方面:
- 并行生成:多核同时生成
- 向量化:一次生成多个
- 高效算法:Box-Muller 变换
- 内存连续:减少访存
这些都是专家多年的积累。
怎么用?
方式一:直接调用
fromops_randimportuniform,randn,randint,choice# 生成随机数x=uniform(shape=(1000,1000)).npu()y=randn(1000,1000).npu()indices=randint(0,100,(1000,)).npu()# 采样data=torch.randn(10000).npu()samples=choice(data,1000)最直接的方式。
方式二:PyTorch 风格
importtorch# PyTorch 昇腾后端自动用 ops-randx=torch.rand(1000,1000).npu()y=torch.randn(1000,1000).npu()indices=torch.randint(0,100,(1000,)).npu()无感知调用。
方式三:配合数据增强
fromops_randimportuniform,randintimporttorchvision.transformsasT# 随机裁剪defrandom_crop(image,crop_size=224):h,w=image.shape[-2:]top=randint(0,h-crop_size,()).item()left=randint(0,w-crop_size,()).item()returnimage[...,top:top+crop_size,left:left+crop_size]# 随机翻转defrandom_flip(image,p=0.5):ifuniform(shape=()).item()<p:returntorch.flip(image,dims=[-1])returnimage数据增强是随机数的重要应用场景。
ops-rand vs NumPy / torch
容易混淆的库:
| 特性 | ops-rand | NumPy | torch |
|---|---|---|---|
| 硬件 | 昇腾 NPU | CPU | CPU/GPU/NPU |
| 性能 | 最快 | 慢 | 中等 |
| API | 兼容 NumPy | 标准 API | PyTorch API |
| 分布 | 常用都有 | 丰富 | 常用都有 |
简单说:
- ops-rand:昇腾 NPU,极致性能
- NumPy:CPU,功能丰富
- torch:通用,方便
推理用 ops-rand,快速验证用 NumPy。
踩坑指南(亲身经历)
种子设置
- 实验前设置种子
- 每次运行前重新设置
- 不然不可复现
范围注意
- uniform 是 [low, high)
- randint 是 [low, high)
- 别搞混
replace 参数
- choice 默认 replace=True(可重复)
- 不重复采样用 replace=False
- 数量不能超过总数
类型一致
- 生成的随机数类型要一致
- FP16 还是 FP32
- 不然后续计算可能出错
设备一致
- 随机数要在 NPU 上
- 别忘了 .npu()
- 不然要搬运
常见应用场景
ops-rand 常用场景:
| 场景 | 用途 |
|---|---|
| 权重初始化 | Xavier、Kaiming |
| Dropout | 随机丢弃 |
| 数据增强 | 随机裁剪、翻转 |
| 强化学习 | 动作采样 |
| 蒙特卡洛 | 模拟采样 |
| 推荐系统 | 负采样 |
| 生成模型 | 噪声注入 |
| 对比学习 | 负样本采样 |
总结
ops-rand 就是昇腾的随机数生成算子库:
- 均匀分布:uniform、rand
- 正态分布:normal、randn
- 整数随机:randint、randperm
- 采样:choice、sample
- 其他分布:bernoulli、poisson、exponential