L2norm
=================



对输入向量进行 L2 归一化，并可选择性地应用 ReLU 或 ReLU6 激活函数。该算子首先用输入向量的 L2 范数（即欧几里得长度）去除向量中的每个元素，然后应用激活函数。

.. math::

    S = \sqrt{\sum_{i=0}^{N-1} Input_i^2}

    \text{temp}_i = \frac{Input_i}{S}

    output_i = \begin{cases}
        \min(6, \max(0, \text{temp}_i)), & \text{if } \text{is\_relu6} = 1 \\
        \max(0, \text{temp}_i), & \text{if } \text{is\_relu} = 1 \\
        \text{temp}_i, & \text{otherwise}
    \end{cases}

输入：
    - **Input** - 输入数据地址。
    - **params** - 参数打包成数组。
        - **input_shape** - 输入向量的shape。
        - **temp_sum** - 多核时每个核心计算的部分累加和。
        - **shape_num** - 输入维度数量。
        - **element_num** - 输入元素数量。
        - **norm_flag** - 0 表示全局归一化，1 表示按最后一个维度归一化, mindspore源码里面没有norm_flag，需要在接口部分自己计算
        - **is_relu** - 是否进行 ReLU 操作的标志（0或1）。
        - **is_relu6** - 是否进行 ReLU6 操作的标志（0或1）。
        - **&epsilon** - 归一化因子，防止除0，这里传指针
    - **core_mask** - 核掩码（仅共享存储版本需要）。

输出：
    - **Output** - 计算结果地址。

支持平台：
    ``FT78NE``
    ``MT7004``

.. note::
    - FT78NE 支持fp32
    - MT7004 支持fp16, fp32

**共享存储版本:**

.. c:function:: void hp_l2norm_s(half* Input, half* output, long long *params, int core_mask)
.. c:function:: void fp_l2norm_s(float* Input, float* output, long long *params, int core_mask)

**C调用示例：**

.. code-block:: c
    :linenos:
    :emphasize-lines: 16

    //FT78NE示例
    #include <stdio.h>
    #include <math.h>
    #include <l2norm.h> // 假设头文件名为 l2norm.h

    int main(int argc, char* argv[]) {
        float* input = (float*)0x81000000;
        float* output = (float*)0x82000000;

        int input_shape[4] = {16, 8, 16, 8};
        int is_relu = 1;
        int is_relu6 = 1;
        int norm_flag = 1; //0：全部norm，1：按最后一个维度norm
        int shape_num = 4;
        int element_num = input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3];
        float* temp_sum = (float*)0x10040000;
        float epsilon = 1e-6;

        srand(seed++);

        int i;
        for (i = 0; i < element_num; i++) { 
            input[i] = (float)(rand() % 20 + 1);
        }

        long long params[10];

        params[0] = (long long)input_shape;
        params[1] = (long long)temp_sum;
        params[2] = (long long)shape_num;
        params[3] = (long long)element_num;
        params[4] = (long long)norm_flag;
        params[5] = (long long)is_relu;
        params[6] = (long long)is_relu6;
        params[7] = (long long)&epsilon; //这里传指针
       
        int core_mask = 0b1111;
        fp_l2norm_s(input, output, (long long *)params, core_mask);
        return 0;
    }


**私有存储版本:**

.. c:function:: void hp_l2norm_p(half* Input, half* output, long long *params, int is_relu6)
.. c:function:: void fp_l2norm_p(float* Input, float* output, long long *params)
    
**C调用示例：**

.. code-block:: c
    :linenos:
    :emphasize-lines: 15

    //FT78NE示例
    #include <stdio.h>
    #include <math.h>
    #include <l2norm.h> // 假设头文件名为 l2norm.h

    int main(int argc, char* argv[]) {
        float* input = (float*)0x10010000;
        float* output = (float*)0x10020000;

        int input_shape[4] = {16, 8, 16, 8};
        int is_relu = 1;
        int is_relu6 = 1;
        int norm_flag = 1; //0：全部norm，1：按最后一个维度norm
        int shape_num = 4;
        int element_num = input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3];
        float* temp_sum = (float*)0x10040000;
        float epsilon = 1e-6;

        srand(seed++);

        int i;
        for (i = 0; i < element_num; i++) { 
            input[i] = (float)(rand() % 20 + 1);
        }

        long long params[10];

        params[0] = (long long)input_shape;
        params[1] = (long long)temp_sum;
        params[2] = (long long)shape_num;
        params[3] = (long long)element_num;
        params[4] = (long long)norm_flag;
        params[5] = (long long)is_relu;
        params[6] = (long long)is_relu6;
        params[7] = (long long)&epsilon; //这里传指针
       
        fp_l2norm_p(input, output, (long long *)params);
        return 0;
    }