Softmax算子的“前世”与“今生”

88 阅读1分钟


  1. Naive Softmax

在实际的计算中,指数计算exp存在不稳定性,数值容易溢出,超过一定范围计算精度会下降等问题

1.1 算法伪代码

1.2 算法的实现

std::vector<float> navieSoftmax(std::vector<float> &src) {
    std::vector<float> dst(src.size());
    float sum = 0.0f;
    for (int i = 0; i < src.size(); i++) {
        sum += std::expf(src[i]);
    }

    for (int i = 0; i < src.size(); i++) {
        dst[i] = std::expf(src[i])/sum;
    }
    return dst;
}

2. # Safe Softmax

Naive版本相比,不会出现数值溢出,但是计算复杂度高了一些。

2.1 算法伪代码

2.2 算法的实现

std::vector<float> safeSoftmax(std::vector<float> &src) {
    std::vector<float> dst(src.size());
    float max_value = -99999999.f;
    for (int i = 0; i < src.size(); i++) {
        max_value = std::max(max_value, src[i]);
    }
    float sum = 0.0f;
    for (int i = 0; i < src.size(); i++) {
        sum += std::expf(src[i]-max_value);
    }
    for (int i = 0; i < src.size(); i++) {
        dst[i] = std::expf(src[i] - max_value) / sum;
    }
    return dst;
}

3. # Online Softmax

3.1 算法伪代码

3.2 算法的实现


std::vector<float> onlineSoftmax(std::vector<float> &src) {
    std::vector<float> dst(src.size());
    float max_value = -99999999.f;
    float sum = 0.0f;
    float prev_value = 0.0f;
    for (int i = 0; i < src.size(); i++) {
        max_value = std::max(max_value, src[i]);
        sum = sum * std::expf(prev_value - max_value) + std::expf(src[i] - max_value);
        prev_value = max_value;
    }
    for (int i = 0; i < src.size(); i++) {
        dst[i] = std::expf(src[i] - max_value) / sum;
    }

    return dst;
}