softmax

Softmax函数

概念

在数学,尤其是概率论和相关领域中,Softmax函数,或称归一化指数函数是[逻辑斯谛函数]的一种推广。它能将一个含任意实数的K维向量 之间,并且所有元素的和为1(也可视为一个 (k-1)维的hyperplane或subspace)。该函数的形式通常按下面的式子给出
f(x_i) = \frac{e^{x_i}}{\sum{e^{x_k}}} ( 0 =< k < n, 0 =< i < n)

实际实现的时候,为了防止溢出,会先把每个元素减去原先的最大值
f(x_i) = \frac{e^{x_i}}{\sum{e^{x_k}}} = \frac{e^{-m}}{e^{-m}} \frac{e^{x_i}}{\sum{e^{x_k}}} = \frac{e^{x_i - m}}{\sum{e^{x_k - m}}} ( 0 =< k < n, 0 =< i < n)

实现

python实现

import numpy as np

def softmax(x):
   e_x = np.exp(x - np.max(x)) # 避免指数溢出
   return e_x / np.sum(e_x, axis=0)

cuda实现

__global__ void softmax(float *predict, int length, int *max_index) 
{
    extern __shared__ float shared_data[];
    float *shared_max_vals = shared_data;
    int *shared_max_indices = (int*)&shared_max_vals[blockDim.x];
    
    int tid = threadIdx.x;

    // 1. 找到最大值和最大值的下标,存储在共享内存中
    float max_val = -FLT_MAX;
    int max_idx = -1;
    for (int i = tid; i < length; i += blockDim.x) {
        if (predict[i] > max_val) {
            max_val = predict[i];
            max_idx = i;
        }
    }
    shared_max_vals[tid] = max_val;
    shared_max_indices[tid] = max_idx;
    __syncthreads();

    // 在所有线程间找到全局最大值和对应的下标
    if (tid == 0) {
        for (int i = 1; i < blockDim.x; i++) {
            if (shared_max_vals[i] > shared_max_vals[0]) {
                shared_max_vals[0] = shared_max_vals[i];
                shared_max_indices[0] = shared_max_indices[i];
            }
        }
        *max_index = shared_max_indices[0];
    }
    __syncthreads();

    max_val = shared_max_vals[0];

    // 2. 计算指数并求和
    float sum_exp = 0.0f;
    for (int i = tid; i < length; i += blockDim.x) {
        predict[i] = expf(predict[i] - max_val);
        sum_exp += predict[i];
    }
    shared_max_vals[tid] = sum_exp;
    __syncthreads();

    // 汇总所有线程的指数和
    if (tid == 0) {
        for (int i = 1; i < blockDim.x; i++) {
            shared_max_vals[0] += shared_max_vals[i];
        }
    }
    __syncthreads();
    float total_sum = shared_max_vals[0];

    // 3. 每个元素除以总和,得到 softmax 值
    for (int i = tid; i < length; i += blockDim.x) {
        predict[i] /= total_sum;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容