PhiloxRandom

产品支持情况

产品

是否支持

Ascend 950PR/Ascend 950DT

Atlas A3 训练系列产品/Atlas A3 推理系列产品

x

Atlas A2 训练系列产品/Atlas A2 推理系列产品

x

功能说明

基于Philox随机数生成算法,给定随机数种子,生成若干的随机数。

Philox随机数生成的核心算法是一个基于记数的伪随机数生成算法,输入为一个128bit的记数器C,两个32bit的key(k0和k1),输出为4个32bit的整数。

函数原型

  • 连续模式

    template <uint16_t Rounds = 7, typename T>
    __aicore__ inline void PhiloxRandom(const LocalTensor<T>& dstLocal, const PhiloxKey& philoxKey, const PhiloxCounter& philoxCounter, uint16_t count)
    
  • stride模式

    template <uint16_t Rounds = 7, typename T>
    __aicore__ inline void PhiloxRandom(const LocalTensor<T>& dstLocal, const PhiloxKey& philoxKey, const PhiloxCounter& philoxCounter, const PhiloxRandomParams& params)
    

参数说明

表 1 模板参数说明

参数名

描述

Rounds

Philox算法内部实现迭代次数,支持取值7或10。

T

目的操作数数据类型,支持的数据类型为:uint32_t、int32_t、float。

其中uint32_t/int32_t为数据类型范围内的均匀分布,float为0-1范围内的均匀分布。

表 2 参数说明

参数名

输入/输出

描述

dstLocal

输出

目的操作数。

类型为LocalTensor,支持的TPosition为VECIN/VECCALC/VECOUT。

LocalTensor的起始地址需要32字节对齐。

philoxKey

输入

随机数种子。两个32bit的key,定义如下:

using PhiloxKey = uint32_t[2];

philoxCounter

输入

随机数种子。一个128bit的记数器C(由4个32bit组成),定义如下:

using PhiloxCounter = uint32_t[4];

count

输入

生成目的操作数的元素个数。

params

输入

stride模式计算所需的参数信息。PhiloxRandomParams类型,定义如下:

struct PhiloxRandomParams {
   uint32_t stride;  // 两行元素之间的间隔
   uint32_t row;     // 表示生成的行数
   uint32_t column;  // 表示生成的每一行的元素个数
}
  • row * column大于0,不大于LocalTensor的大小。
  • column % 4 == 0,stride % 4 == 0,stride >= column。

图 1 PhiloxRandom示意图

上图是一个生成随机数的示意图。

  • 连续模式下使用philoxCounter={0, 0, 0, 0},count=32来生成32个随机数。
  • stride模式下可按列分两次生成,调用两次接口。第一次调用参数为philoxCounter={0, 0, 0, 0},stride=8,row=4,column=4;第二次调用参数为philoxCounter={1, 0, 0, 0}(每次记数器C自增会生成128bit的随机数),stride=8,row=4,column=4。

返回值说明

约束说明

调用示例

  • 接口使用样例

    // philoxKey={0,0}, philoxCounter={0,0,0,0}, params={1024, 8, 1024}
    LocalTensor<uint32_t> dstLocal = outQueue.AllocTensor<uint32_t>();  
    PhiloxRandom<7>(dstLocal, {0, 0}, {0, 0, 0, 0},{1024, 8, 1024});
    
  • 完整样例

    #include "kernel_operator.h"
    
    template <uint16_t Rounds, typename srcType>
    class KernelPhiloxStride {
    public:
        __aicore__ inline KernelPhiloxStride() {}
        __aicore__ inline void Init(GM_ADDR dstGm, uint32_t paramStride, uint32_t paramRow, uint32_t paramColumn)
        {
            stride = paramStride;
            row = paramRow;
            column = paramColumn;
            count = row * column;
            const int alginSize = AscendC::GetDataBlockSizeInBytes() / sizeof(srcType);
            dstSize = (count + alginSize - 1) / alginSize * alginSize;
            dstGlobal.SetGlobalBuffer(reinterpret_cast<__gm__ srcType *>(dstGm), dstSize);
            pipe.InitBuffer(outQueue, 1, dstSize * sizeof(srcType));
        }
        __aicore__ inline void Process(uint32_t seed0, uint32_t seed1, uint32_t seed2, uint32_t seed3, uint32_t seed4,
            uint32_t seed5)
        {
            Compute(seed0, seed1, seed2, seed3, seed4, seed5);
            CopyOut();
        }
    private:
        __aicore__ inline void Compute(uint32_t seed0, uint32_t seed1, uint32_t seed2, uint32_t seed3, uint32_t seed4,
            uint32_t seed5)
        {
            AscendC::LocalTensor<srcType> dstLocal = outQueue.AllocTensor<srcType>();
            AscendC::PhiloxRandom<Rounds>(dstLocal, { seed0, seed1 }, { seed2, seed3, seed4, seed5 },
                { stride, row, column });
            outQueue.EnQue<srcType>(dstLocal);
        }
        __aicore__ inline void CopyOut()
        {
            AscendC::LocalTensor<srcType> dstLocal = outQueue.DeQue<srcType>();
            AscendC::DataCopy(dstGlobal, dstLocal, dstSize);
            outQueue.FreeTensor(dstLocal);
        }
    private:
        AscendC::GlobalTensor<srcType> dstGlobal;
        AscendC::TPipe pipe;
        AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueue;
        uint32_t count;
        uint32_t stride;
        uint32_t row;
        uint32_t column;
        uint32_t dstSize;
    };
    
    extern "C" __global__ __aicore__ void philox_kernel_stride(GM_ADDR dstGm)
    {
        KernelPhiloxStride<7, uint32_t> op;
        op.Init(dstGm, 1024, 8, 1024);
        op.Process(0, 0, 0, 0, 0, 0);
    }