NLLLoss
=================



对输入的对数概率（log-probabilities）和目标标签计算负对数似然损失（Negative Log Likelihood Loss）。

该算子通常用于分类任务中，输入为已经取对数的概率值（例如 LogSoftmax 的输出）。

.. math::

    \text{loss}_i = - \log p_{i, y_i} \cdot w_{y_i}

其中：

- :math:`p_{i, y_i}` 表示第 :math:`i` 个样本在真实类别 :math:`y_i` 上的预测概率
- :math:`w_{y_i}` 表示对应类别的权重

根据 ``reduction_type`` 的不同，对 batch 维度的损失进行不同方式的归约。

输入：
    - **log_probs** - 输入的对数概率数据地址，形状为 ``[batch_size, class_num]``。
    - **labels** - 真实标签索引地址，形状为 ``[batch_size]``。
    - **weight** - 类别权重数组地址，形状为 ``[class_num]``。
    - **batch_size** - batch 大小。
    - **class_num** - 类别数量。
    - **reduction_type** - 损失归约方式：
        - ``0``：None，不做归约，逐样本输出
        - ``1``：Sum，对 batch 内损失求和
        - ``2``：Mean，对 batch 内损失按权重和求平均
    - **core_mask** - 核掩码（仅适用于共享存储版本）。

输出：
    - **loss** - 损失输出地址：
        - 当 ``reduction_type = 0`` 时，输出长度为 ``batch_size``
        - 当 ``reduction_type = 1`` 或 ``2`` 时，仅使用 ``loss[0]``
    - **total_weight** - 所有样本权重之和地址。

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

.. note::
    - FT78NE 支持 fp, int8
    - MT7004 支持 hp, fp
    - 输入 ``log_probs`` 应已是对数概率值
    - ``labels`` 中的索引需满足 ``0 <= label < class_num``

**共享存储版本:**

.. c:function:: void i8_nllloss_s(const int8_t* log_probs, const int* labels, const int8_t* weight, int32_t* loss, int32_t* total_weight, int batch_size, int class_num, int reduction_type, int core_mask)
.. c:function:: void hp_nllloss_s(const half* log_probs, const int* labels, const half* weight, half* loss, half* total_weight, int batch_size, int class_num, int reduction_type, int core_mask)
.. c:function:: void fp_nllloss_s(const float* log_probs, const int* labels, const float* weight, float* loss, float* total_weight, int batch_size, int class_num, int reduction_type, int core_mask)

**C调用示例：**

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

    //FT78NE示例
    #include <stdio.h>
    #include <nllloss.h>

    int main(int argc, char* argv[]) {
        float *log_probs = (float *)0xA0000000;   // [batch_size, class_num]
        int   *labels    = (int *)0xA0001000;     // [batch_size]
        float *weight    = (float *)0xA0002000;   // [class_num]
        float *loss      = (float *)0xC0000000;
        float *total_w   = (float *)0xC0001000;
        int batch_size = 32;
        int class_num  = 1000;
        int reduction_type = 2;   // Mean
        int core_mask = 0xff;

        fp_nllloss_s(log_probs, labels, weight, loss, total_w,
                     batch_size, class_num, reduction_type, core_mask);
        return 0;
    }


**私有存储版本:**

.. c:function:: void i8_nllloss_p(const int8_t* log_probs, const int* labels, const int8_t* weight, int32_t* loss, int32_t* total_weight, int batch_size, int class_num, int reduction_type)
.. c:function:: void hp_nllloss_p(const half* log_probs, const int* labels, const half* weight, half* loss, half* total_weight, int batch_size, int class_num, int reduction_type)
.. c:function:: void fp_nllloss_p(const float* log_probs, const int* labels, const float* weight, float* loss, float* total_weight, int batch_size, int class_num, int reduction_type)

**C调用示例：**

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

    //FT78NE示例
    #include <stdio.h>
    #include <nllloss.h>

    int main(int argc, char* argv[]) {
        float *log_probs = (float *)0x10810000;   // L2空间
        int   *labels    = (int *)0x10820000;
        float *weight    = (float *)0x10830000;
        float *loss      = (float *)0x10840000;
        float *total_w   = (float *)0x10850000;
        int batch_size = 32;
        int class_num  = 1000;
        int reduction_type = 1;   // Sum

        fp_nllloss_p(log_probs, labels, weight, loss, total_w,
                     batch_size, class_num, reduction_type);
        return 0;
    }
