Avgpooling
=================


对NHWC格式的输入张量执行2D平均池化，并随后进行范围裁剪（Clip）激活。

该算子融合了两个步骤：

1. **平均池化 (Average Pooling)**:

.. math::

    \text{Pool}_{i,j} = \frac{1}{k_h \times k_w} \sum_{m=0}^{k_h-1} \sum_{n=0}^{k_w-1} \text{Input}_{i \cdot s_h + m, j \cdot s_w + n}

2. **裁剪激活 (Clipping Activation)**:

.. math::

    \text{Output} = \max(\min\_val, \min(\text{Pool}, \max\_val))

输入：
    - **input** - 输入张量的数据地址。格式: NHWC。
    - **params** - 其他参数打包成数组。
    - **core_mask** - 核掩码。

输出：
    - **output** - 输出张量的数据地址。

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

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

**参数数组结构：**

.. code-block:: c
    :linenos:

    long long params[16];
    params[0] = (long long)in_w;  输入特征图的宽度。
    params[1] = (long long)in_h;  输入特征图的高度。
    params[2] = (long long)win_w;  池化核的宽度。
    params[3] = (long long)win_h;  池化核的高度。
    params[4] = (long long)output_w;  输出特征图的宽度。
    params[5] = (long long)output_h;  输出特征图的高度。
    params[6] = (long long)output_batch;  输出特征图的批大小。
    params[7] = (long long)channel;  输出特征图的通道数。
    params[8] = (long long)stride_w;  水平方向的步长。
    params[9] = (long long)stride_h;  垂直方向的步长。
    params[10] = (long long)pad_l;  左边距填充。
    params[11] = (long long)pad_u;  上边距填充。
    params[12] = (long long)&minf;  裁剪范围的最小值地址。
    params[13] = (long long)&maxf;  裁剪范围的最大值地址。


**共享存储版本:**

.. c:function:: void i8_avgpool_fusion_s(int8_t* input, int8_t* output, long long* params, int core_mask)
.. c:function:: void fp_avgpool_fusion_s(float* input, float* output, long long* params, int core_mask)
.. c:function:: void hp_avgpool_fusion_s(half* input, half* output, long long* params, int core_mask)

**C调用示例：**

.. code-block:: c
   :linenos:
   :emphasize-lines: 25-28

   //FT78NE示例
   #include <stdio.h>
   #include <avgpooling.h>
   int main(int argc, char* argv[]) {
        float *input_ptr = (float *)0x81000000;
        float *output_ptr = (float *)0x82000000;

        int output_batch = 16; //batch数
        int channel = 4;
        int in_w = 16;
        int in_h = 16;

        int win_w = 2;
        int win_h = 2;
        int stride_w = 2;
        int stride_h = 2;
        int pad_l = 0;
        int pad_u = 0;
        float minf = 0;
        float maxf = 50;

        //计算output_w和output_h
        int dividor = in_w + pad_l + 0 - win_w;
        int output_w = (dividor + stride_w - 1) / stride_w  + 1;
        int dividor2 = in_h + pad_u + 0 - win_h;
        int output_h = (dividor2 + stride_h - 1) / stride_h  + 1;

        long long params[16];
        params[0] = (long long)in_w;
        params[1] = (long long)in_h;
        params[2] = (long long)win_w;
        params[3] = (long long)win_h;
        params[4] = (long long)output_w;
        params[5] = (long long)output_h;
        params[6] = (long long)output_batch;
        params[7] = (long long)channel;
        params[8] = (long long)stride_w;
        params[9] = (long long)stride_h;
        params[10] = (long long)pad_l;
        params[11] = (long long)pad_u;
        params[12] = (long long)&minf; //注意这里传指针，不能直接强制转换成long long
        params[13] = (long long)&maxf;

        srand(time(NULL));

        //初始化output_ptr
        int input_size = output_batch * channel * in_w * in_h;
        int i;
        for (i = 0; i < input_size; i++) {
            input_ptr[i] = (float)(rand() % 100);
        }
        int core_mask = 0b1111;
        fp_avg_pooling_s(input_ptr, output_ptr, params, core_mask);
        return 0;
   }



**私有存储版本:**

.. c:function:: void i8_avgpool_fusion_p(int8_t* input, int8_t* output, long long* params)
.. c:function:: void fp_avgpool_fusion_p(float* input, float* output, long long* params)
.. c:function:: void hp_avgpool_fusion_p(half* input, half* output, long long* params)
    

**C调用示例：**

.. code-block:: c
   :linenos:
   :emphasize-lines: 23-26

   //FT78NE示例
   #include <stdio.h>
   #include <avgpooling.h>
   int main(int argc, char* argv[]) {
        float *input_ptr = (float *)0x10010000;
        float *output_ptr = (float *)0x10020000;

        int output_batch = 16; //batch数
        int channel = 4;
        int in_w = 16;
        int in_h = 16;

        int win_w = 2;
        int win_h = 2;
        int stride_w = 2;
        int stride_h = 2;
        int pad_l = 0;
        int pad_u = 0;
        float minf = 0;
        float maxf = 50;

        //计算output_w和output_h
        int dividor = in_w + pad_l + 0 - win_w;
        int output_w = (dividor + stride_w - 1) / stride_w  + 1;
        int dividor2 = in_h + pad_u + 0 - win_h;
        int output_h = (dividor2 + stride_h - 1) / stride_h  + 1;

        long long params[16];
        params[0] = (long long)in_w;
        params[1] = (long long)in_h;
        params[2] = (long long)win_w;
        params[3] = (long long)win_h;
        params[4] = (long long)output_w;
        params[5] = (long long)output_h;
        params[6] = (long long)output_batch;
        params[7] = (long long)channel;
        params[8] = (long long)stride_w;
        params[9] = (long long)stride_h;
        params[10] = (long long)pad_l;
        params[11] = (long long)pad_u;
        params[12] = (long long)&minf; //注意这里传指针，不能直接强制转换成long long
        params[13] = (long long)&maxf;

        srand(time(NULL));

        //初始化output_ptr
        int input_size = output_batch * channel * in_w * in_h;
        int i;
        for (i = 0; i < input_size; i++) {
            input_ptr[i] = (float)(rand() % 100);
        }
        int core_mask = 0b1111;
        fp_avg_pooling_p(input_ptr, output_ptr, params);
        return 0;
   }
