LayerNormOperation(部分代码开放)
产品支持情况
| 
          硬件型号  | 
        
          是否支持  | 
       
|---|---|
| 
          | 
        
          √  | 
       
| 
          | 
        
          √  | 
       
| 
          | 
        
          x  | 
       
| 
          | 
        
          x  | 
       
| 
          | 
        
          x  | 
       
功能
LayerNorm是一种归一化方法,可以将网络层输入数据归一化到[0, 1]之间。当前支持NORM、PRENORM、POSTNORM三种归一化。
计算公式
- Norm
      
标准的LayerNorm操作,公式为:
图1 LayerNorm计算公式图
       - PostNorm
      
add和layernorm融合算子,先将x和residual相加再做layernorm归一化,公式为:
图2 Add+LayerNorm计算公式图
       - PreNorm
      
add和layernorm融合算子,先将x和residual相加再做layernorm归一化。公式与PostNorm相同。和postNorm区别在于会输出x和residual相加的结果。
 
定义
          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 27 28 29 30 31 32 33 34 35 36  | 
         
          struct LayerNormParam { enum LayerNormType : int { LAYER_NORM_UNDEFINED = 0, LAYER_NORM_NORM, LAYER_NORM_PRENORM, LAYER_NORM_POSTNORM, LAYER_NORM_MAX, }; struct NormParam { QuantType quantType = QUANT_UNQUANT; float epsilon = 1e-5; int32_t beginNormAxis = 0; int32_t beginParamsAxis = 0; DynamicQuantType dynamicQuantType = DYNAMIC_QUANT_UNDEFINED; uint8_t rsv[20] = {0}; }; struct PreNormParam { QuantType quantType = QUANT_UNQUANT; float epsilon = 1e-5; uint64_t opMode = 0; float zoomScaleValue = 1.0f; uint8_t rsv[20] = {0}; }; struct PostNormParam { QuantType quantType = QUANT_UNQUANT; float epsilon = 1e-5; uint64_t opMode = 0; float zoomScaleValue = 1.0f; uint8_t rsv[20] = {0}; }; LayerNormType layerType = LAYER_NORM_UNDEFINED; NormParam normParam; PreNormParam preNormParam; PostNormParam postNormParam; uint8_t rsv[8] = {0}; };  | 
        
参数列表
| 
          成员名称  | 
        
          描述  | 
       
|---|---|
| 
          layerType  | 
        
          归一化类型。 
  | 
       
| 
          normParam  | 
        
          NORM参数,具体请参见表1。  | 
       
| 
          preNormParam  | 
        
          PRENORM参数,具体请参见表2。  | 
       
| 
          postNormParam  | 
        
          POSTNORM参数,具体请参见表3。  | 
       
| 
          rsv[8]  | 
        
          预留参数。  | 
       
| 
          参数  | 
        
          类型  | 
        
          默认值  | 
        
          描述  | 
       
|---|---|---|---|
| 
          quantType  | 
        
          QuantType  | 
        
          QUANT_UNQUANT  | 
        
          量化类型。 当前支持以下类型。 
  | 
       
| 
          epsilon  | 
        
          float  | 
        
          1e-5  | 
        
          Epsilon,归一化时加在分母上防止除0。  | 
       
| 
          beginNormAxis  | 
        
          int32_t  | 
        
          0  | 
        
          归一化的维度,默认值为0,从第几维开始norm,同时决定输入gamma和beta维度。  | 
       
| 
          beginParamsAxis  | 
        
          int32_t  | 
        
          0  | 
        
          归一化的维度,默认值为0,决定从第几维开始把后面的维度按轴合并。  | 
       
| 
          dynamicQuantType  | 
        
          DynamicQuantType  | 
        
          DYNAMIC_QUANT_UNDEFINED  | 
        
          动态量化类型。默认为DYNAMIC_QUANT_UNDEFINED非动态量化。当前版本暂不支持非对称动态量化。  | 
       
| 
          rsv[20]  | 
        
          uint8_t  | 
        
          {0}  | 
        
          预留参数。  | 
       
 
     8.0.RC2及后续版本normParam不再支持quantInputScale、quantInputOffset、quantInputAlpha量化参数。
| 
          参数  | 
        
          类型  | 
        
          默认值  | 
        
          描述  | 
       
|---|---|---|---|
| 
          quantType  | 
        
          QuantType  | 
        
          QUANT_UNQUANT  | 
        
          量化类型。当前仅支持QUANT_UNQUANT。  | 
       
| 
          epsilon  | 
        
          float  | 
        
          1e-5  | 
        
          Epsilon,归一化时加在分母上防止除0。  | 
       
| 
          opMode  | 
        
          uint64_t  | 
        
          0  | 
        
         
  | 
       
| 
          zoomScaleValue  | 
        
          float  | 
        
          1.0f  | 
        
          缩放因子。  | 
       
| 
          rsv[20]  | 
        
          uint8_t  | 
        
          {0}  | 
        
          预留参数。  | 
       
| 
          参数  | 
        
          类型  | 
        
          默认值  | 
        
          描述  | 
       
|---|---|---|---|
| 
          quantType  | 
        
          QuantType  | 
        
          QUANT_UNQUANT  | 
        
          量化类型。当前支持以下类型。 
  | 
       
| 
          epsilon  | 
        
          float  | 
        
          1e-5  | 
        
          Epsilon,归一化时加在分母上防止除0。  | 
       
| 
          opMode  | 
        
          uint64_t  | 
        
          0  | 
        
         
  | 
       
| 
          zoomScaleValue  | 
        
          float  | 
        
          1.0f  | 
        
          缩放因子。  | 
       
| 
          rsv[20]  | 
        
          uint8_t  | 
        
          {0}  | 
        
          预留参数。  | 
       
 
     8.0.RC2及后续版本postNormParam不再支持quantInputScale、quantInputOffset、quantInputAlpha量化参数。
规格约束
- beginNormAxis 需要小于 tensor x的维度大小。为负数时,与tensor x维度大小之和需要大于0。
 - Norm的动态量化只支持DYNAMIC_QUANT_SYMMETRIC对称动态量化。最后一维需要小于等于12288。
 - 除量化场景下的scale和offset tensor,其余tensor的最后一维大小相等。
 
功能列表
- 非量化
      
- 基础layernorm
 - add+layernorm融合(prenorm,postnorm)
 
 - 量化
      
- layernorm量化
 - layernorm对称动态量化
 - add+layernorm量化(postnorm)
 
 
算子调用示例(C++)
前置条件和编译命令请参见算子调用示例。
场景:基础场景
          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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98  | 
         
          #include <iostream> #include <vector> #include <numeric> #include "acl/acl.h" #include "atb/operation.h" #include "atb/types.h" #include "atb/atb_infer.h" #include "demo_util.h" const int32_t DEVICE_ID = 0; const uint32_t DIM_0 = 128; const uint32_t DIM_1 = 256; const int32_t BEGIN_NORM_AXIS = 1; /** * @brief 准备atb::VariantPack中的所有输入tensor * @param contextPtr context指针 * @param stream stream * @return atb::SVector<atb::Tensor> atb::VariantPack中的输入tensor * @note 需要传入所有host侧tensor */ atb::SVector<atb::Tensor> PrepareInTensor(atb::Context *contextPtr, aclrtStream stream) { atb::Tensor x = CreateTensorFromVector(contextPtr, stream, std::vector<float>(DIM_0 * DIM_1, 2.0), ACL_FLOAT16, aclFormat::ACL_FORMAT_ND, {DIM_0, DIM_1}); atb::Tensor gamma = CreateTensorFromVector( contextPtr, stream, std::vector<float>(DIM_1, 2.0), ACL_FLOAT16, aclFormat::ACL_FORMAT_ND, {DIM_1}); atb::Tensor beta = CreateTensorFromVector( contextPtr, stream, std::vector<float>(DIM_1, 1.0), ACL_FLOAT16, aclFormat::ACL_FORMAT_ND, {DIM_1}); atb::SVector<atb::Tensor> inTensors = {x, gamma, beta}; return inTensors; } /** * @brief 创建一个beginNormAxis为1的layernorm operation * @return atb::Operation * 返回一个Operation指针 */ atb::Operation *CreateLayerNormOperation() { atb::infer::LayerNormParam param; param.layerType = atb::infer::LayerNormParam::LayerNormType::LAYER_NORM_NORM; param.normParam.beginNormAxis = BEGIN_NORM_AXIS; atb::Operation *layerNormOp = nullptr; CHECK_STATUS(atb::CreateOperation(param, &layerNormOp)); return layerNormOp; } int main(int argc, char **argv) { // 设置卡号、创建context、设置stream atb::Context *context = nullptr; void *stream = nullptr; CHECK_STATUS(aclInit(nullptr)); CHECK_STATUS(aclrtSetDevice(DEVICE_ID)); CHECK_STATUS(atb::CreateContext(&context)); CHECK_STATUS(aclrtCreateStream(&stream)); context->SetExecuteStream(stream); // 创建op atb::Operation *layerNormOp = CreateLayerNormOperation(); // 准备输入tensor atb::VariantPack variantPack; variantPack.inTensors = PrepareInTensor(context, stream); // 放入输入tensor atb::Tensor tensorOut = CreateTensor(ACL_FLOAT16, aclFormat::ACL_FORMAT_ND, {DIM_0, DIM_1}); variantPack.outTensors = {tensorOut}; // 放入输出tensor uint64_t workspaceSize = 0; // 计算workspace大小 CHECK_STATUS(layerNormOp->Setup(variantPack, workspaceSize, context)); uint8_t *workspacePtr = nullptr; if (workspaceSize > 0) { CHECK_STATUS(aclrtMalloc((void **)(&workspacePtr), workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST)); } // layernorm执行 layerNormOp->Execute(variantPack, workspacePtr, workspaceSize, context); CHECK_STATUS(aclrtSynchronizeStream(stream)); // 流同步,等待device侧任务计算完成 // 释放资源 for (atb::Tensor &inTensor : variantPack.inTensors) { CHECK_STATUS(aclrtFree(inTensor.deviceData)); } CHECK_STATUS(aclrtFree(tensorOut.deviceData)); if (workspaceSize > 0) { CHECK_STATUS(aclrtFree(workspacePtr)); } CHECK_STATUS(atb::DestroyOperation(layerNormOp)); // operation,对象概念,先释放 CHECK_STATUS(aclrtDestroyStream(stream)); CHECK_STATUS(DestroyContext(context)); // context,全局资源,后释放 CHECK_STATUS(aclFinalize()); std::cout << "Layernorm demo success!" << std::endl; return 0; }  |