激活函数之softmax介绍及C++实现
下溢(underflow):當接近零的數被四舍五入為零時發生下溢。許多函數在其參數為零而不是一個很小的正數時才會表現出質的不同。例如,我們通常要避免被零除或避免取零的對數。
上溢(overflow):當大量級的數被近似為∞或-∞時發生上溢。進一步的運算通常會導致這些無限值變為非數字。
必須對上溢和下溢進行數值穩定的一個例子是softmax函數(softmax function).softmax函數經常用于預測與Multinoulli分布相關聯的概率,定義為:
考慮一下當所有xi都等于某個常數c時會發生什么。從理論分析上說,我們可以發現所有的輸出都應該為1/n。從數值計算上說,當c量級很大時,這可能不會發生。如果c是很小的負數,exp(c)就會下溢。這意味著softmax函數的分母會變成0,所以最后的結果是未定義的。當c是非常大的正數時,exp(c)的上溢再次導致整個表達式未定義。這兩個困難能通過計算softmax(z)同時解決,其中z=x-maxixi.簡單的代數計算表明,softmax解析上的函數值不會因為從輸入向量減去或加上標量而改變。減去maxixi導致exp的最大參數為0,這排除了上溢的可能性。同樣地,分母中至少有一個值為1的項,這就排除了因分母下溢而導致被零除的可能性。
還有一個小問題。分子中的下溢仍可以導致整體表達式被計算為零。這意味著,如果我們在計算log(softmax(x))時,先計算softmax再把結果傳給log函數,會錯誤地得到-∞。相反,我們必須實現一個單獨的函數,并以數值穩定的方式計算log(softmax)。我們可以使用相同的技巧來穩定log(softmax)函數。
Softmax函數:在數學,尤其是概率論和相關領域中,Softmax函數,或稱歸一化指數函數,是邏輯函數的一種推廣。它能將一個含任意實數的K維的向量z的”壓縮”到另一個K維實向量σ(z)中,使得每一個元素的范圍都在(0,1)之間,并且所有元素的和為1。該函數的形式通常按下面的式子給出:其中,j=1,…,K.
Softmax函數實際上是有限項離散概率分布的梯度對數歸一化。因此,Softmax函數在包括多項邏輯回歸,多項線性判別分析,樸素貝葉斯分類器和人工神經網絡等的多種基于概率的多分類問題方法中都有著廣泛應用。
The softmax function is often used in the final layer of a neural network-based classifier. Such networks are commonly trained under a log loss (or cross-entropy) regime, giving a non-linear variant of multinomial logistic regression.
Softmax可作為神經網絡中的輸出層,用于多分類(sigmoid只能用于二分類,而softmax可用于多分類。使用Logistic函數來實現二分類問題,對于多分類問題,可以使用多項Logistic回歸,該方法也被稱之為softmax函數);Softmax還可以解決學習速度衰退的問題;softmax還可作為loss function。
softmax函數的導數如下:
以上內容主要摘自:《深度學習中文版》?和?維基百科
? 以下是C++實現的測試code:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"// ========================= Activation Function: softmax =====================
template<typename _Tp>
int activation_function_softmax(const _Tp* src, _Tp* dst, int length)
{const _Tp alpha = *std::max_element(src, src + length);_Tp denominator{ 0 };for (int i = 0; i < length; ++i) {dst[i] = std::exp(src[i] - alpha);denominator += dst[i];}for (int i = 0; i < length; ++i) {dst[i] /= denominator;}return 0;
}template<typename _Tp>
int activation_function_softmax_derivative(const _Tp* src, _Tp* dst, int length)
{std::vector<_Tp> y(length, (_Tp)0);activation_function_softmax(src, y.data(), length);fprintf(stderr, "Error: activation_function_softmax_derivative to do ...\n");return -1;
}int test_activation_function()
{std::vector<float> src{ 1.23f, 4.14f, -3.23f, -1.23f, 5.21f, 0.234f, -0.78f, 6.23f };int length = src.size();std::vector<float> dst(length);fprintf(stderr, "source vector: \n");fbc::print_matrix(src);fprintf(stderr, "calculate activation function:\n");fprintf(stderr, "type: sigmoid result: \n");fbc::activation_function_sigmoid(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: sigmoid derivative result: \n");fbc::activation_function_sigmoid_derivative(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: sigmoid fast result: \n");fbc::activation_function_sigmoid_fast(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: softplus result: \n");fbc::activation_function_softplus(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: softplus derivative result: \n");fbc::activation_function_softplus_derivative(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: ReLU result: \n");fbc::activation_function_ReLU(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: ReLU derivative result: \n");fbc::activation_function_ReLU_derivative(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: Leaky ReLUs result: \n");fbc::activation_function_Leaky_ReLUs(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: Leaky ReLUs derivative result: \n");fbc::activation_function_Leaky_ReLUs_derivative(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: Leaky ELUs result: \n");fbc::activation_function_ELUs(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: softmax result: \n");fbc::activation_function_softmax(src.data(), dst.data(), length);fbc::print_matrix(dst);fprintf(stderr, "type: softmax derivative result: \n");fbc::activation_function_softmax_derivative(src.data(), dst.data(), length);fbc::print_matrix(dst);return 0;
}
GitHub: https://github.com/fengbingchun/NN_Test
總結
以上是生活随笔為你收集整理的激活函数之softmax介绍及C++实现的全部內容,希望文章能夠幫你解決所遇到的問題。