Adam
=================

    使用 Adam 算法更新参数权重。支持 Nesterov 动量。

    算法逻辑如下：

    .. math::

        m_t = m_{t-1} + (g_t - m_{t-1}) \cdot (1 - \beta_1) \\
        v_t = v_{t-1} + (g_t^2 - v_{t-1}) \cdot (1 - \beta_2) \\
        \hat{lr} = lr \cdot \frac{\sqrt{1 - \beta_2^t}}{1 - \beta_1^t}

    如果不启用 Nesterov：

    .. math::

        w_t = w_{t-1} - \hat{lr} \cdot \frac{m_t}{\sqrt{v_t} + \epsilon}

    如果启用 Nesterov：

    .. math::

        w_t = w_{t-1} - \hat{lr} \cdot \frac{m_t \cdot \beta_1 + (1 - \beta_1) \cdot g_t}{\sqrt{v_t} + \epsilon}

    输入：
        - **m** - 一阶矩向量地址（输入/输出）。
        - **v** - 二阶矩向量地址（输入/输出）。
        - **gradient** - 梯度向量地址。
        - **weight** - 权重向量地址（输入/输出）。
        - **params** - 一其他参数打包。

**AdamParam定义如下**

.. code-block:: c
    :linenos:

     typedef struct {
        float beta1; //阶矩估计的指数衰减率。
        float beta2; //二阶矩估计的指数衰减率
        float beta1_power; //:math:`\beta_1^t` 的值（指针形式传入）
        float beta2_power; //:math:`\beta_2^t` 的值（指针形式传入）
        float eps; // 数值稳定性项 epsilon  
        float learning_rate; // 学习率
        int nesterov; // 是否启用 Nesterov 动量（0: 不启用, 1: 启用）
        int start; // 计算的起始索引（包含）
        int end; // 计算的结束索引（不包含）
    } AdamParam;


输出：
    - **m** - 更新后的一阶矩。
    - **v** - 更新后的二阶矩。
    - **weight** - 更新后的权重。

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

.. note::
    - 支持fp32,fp16类型。

**共享存储版本:**

.. c:function:: void fp_adam_s(float* m, float* v, const float* gradient, float* weight, AdamParam *params, int core_mask)

    **C调用示例：**

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

        #include <stdio.h>

        int main(int argc, char* argv[]) {
            // 假设所有数据均位于DDR空间
            float* m = (float*)0xC0000000;
            float* v = (float*)0xC1000000;
            float* gradient = (float*)0xC2000000;
            float* weight = (float*)0xC3000000;
            
            // 标量参数
            float beta1 = 0.9f;
            float beta2 = 0.999f;
            float beta1_power_val = 0.9f;   // beta1^1
            float beta2_power_val = 0.999f; // beta2^1
            float* beta1_power = &beta1_power_val;
            float* beta2_power = &beta2_power_val;
            float eps = 1e-8f;
            float learning_rate = 0.001f;
            int nesterov = 1;

            int start = 0;
            int end = 800000; // 元素总数
            int core_mask = 0xff; // 使用所有核心

            AdamParam params = {
                .beta1 = beta1,
                .beta2 = beta2,
                .beta1_power = beta1_power_val,
                .beta2_power = beta2_power_val,
                .eps = eps,
                .learning_rate = learning_rate,
                .nesterov = nesterov,
                .start = 0,
                .end = 800000
            };

            fp_adam_s(m, v, gradient, weight, &params, core_mask);
            
            return 0;
        }


**私有存储版本:**

.. c:function:: void fp_adam_p(float* m, float* v, const float* gradient, float* weight, AdamParam *params)

    **C调用示例：**

    .. code-block:: c
        :linenos:
        :emphasize-lines: 20-21

        #include <stdio.h>

        int main(int argc, char* argv[]) {
            // 假设所有数据均位于L2/AM空间
            float* m = (float*)0x10820000;
            float* v = (float*)0x10830000;
            float* gradient = (float*)0x10840000;
            float* weight = (float*)0x10850000;

            float beta1 = 0.9f;
            float beta2 = 0.999f;
            float beta1_power_val = 0.9f;
            float beta2_power_val = 0.999f;
            float eps = 1e-8f;
            float learning_rate = 0.001f;
            int nesterov = 0;
            int start = 0;
            int end = 2000;

            AdamParam params = {
                .beta1 = beta1,
                .beta2 = beta2,
                .beta1_power = beta1_power_val,
                .beta2_power = beta2_power_val,
                .eps = eps,
                .learning_rate = learning_rate,
                .nesterov = nesterov,
                .start = start,
                .end = end
            };

            fp_adam_p(m, v, gradient, weight, &params);
            
            return 0;
        }