LayerNorm是一种归一化方法,可以将网络层输入数据归一化到[0, 1]之间。当前支持三种:NORM、PRENORM、POSTNORM三种归一化。
标准的LayerNorm操作,公式为:
add和layernorm融合算子,先将x和residual相加再做layernorm归一化,公式为:
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 |
PRETNORM参数,具体请参见表2。 |
postNormParam |
POSTNORM参数,具体请参见表3。 |
rsv[8] |
预留参数。 |
参数 |
类型 |
默认值 |
描述 |
---|---|---|---|
quantType |
QuantType |
QUANT_UNQUANT |
量化类型。 当前支持以下类型。
|
epsilon |
float |
1e-5 |
Epsilon,归一化时加在分母上防止除零。 |
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,归一化时加在分母上防止除零。 |
opMode |
uint64_t |
0 |
|
zoomScaleValue |
float |
1.0f |
缩放因子。 |
rsv[20] |
uint8_t |
{0} |
预留参数。 |
参数 |
类型 |
默认值 |
描述 |
---|---|---|---|
quantType |
QuantType |
QUANT_UNQUANT |
量化类型。当前支持以下类型。
|
epsilon |
float |
1e-5 |
Epsilon,归一化时加在分母上防止除零。 |
opMode |
uint64_t |
0 |
|
zoomScaleValue |
float |
1.0f |
缩放因子。 |
rsv[20] |
uint8_t |
{0} |
预留参数。 |
8.0.RC2及后续版本postNormParam不再支持quantInputScale、quantInputOffset、quantInputAlpha量化参数。
前置条件和编译命令请参见算子调用示例。
场景:基础场景
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; } |