数学中的导数
導數(Derivative)是微積分學(微積分學是研究極限、微分學、積分學和無窮級數等的一個數學分支)中重要的基礎概念。一個函數在某一點的導數描述了這個函數在這一點附件的變化率。導數的本質是通過極限的概念對函數進行局部的線性逼近。當函數f的自變量在一點x0上產生一個增量h時,函數輸出值的增量與自變量增量h的比值在h趨于0時的極限如果存在,即為f在x0處的導數,記作
導數是函數的局部性質。不是所有的函數都有導數,一個函數也不一定在所有點上都有導數。若某函數在某一點導數存在,則稱其在這一點可導,否則稱為不可導。如果函數的自變量和取值都是實數的話,那么函數在某一點的導數就是該函數所代表的曲線在這一點上的切線斜率(斜率用來量度斜坡的斜度,數學上,直線的斜率在任一處皆相等,是直線傾斜程度的量度。透過代數和幾何能計算出直線的斜率;曲線上某點的切線斜率反映此曲線的變數在此點的變化快慢程度,用微積分可計算出曲線中任一點的切線斜率)。
對于可導的函數f,x→f’(x)也是一個函數,稱作f的導函數。尋找已知的函數在某點的導數或其導函數的過程稱為求導。反之,已知導函數也可以倒過來求原來的函數,即不定積分(在微積分中,一個函數f的不定積分,也稱為原函數或反導數,是一個導數等于f的函數F,即F’=f。不定積分和定積分間的關系由微積分基本定理確定)。微積分基本定理說明了求原函數與積分是等價的。求導和積分是一對互逆的操作,它們都是微積分學中最為基礎的概念。
一般定義:設有定義域和取值都在實數域中的函數y=f(x)。若f(x)在點x0的某個領域內有定義,則當自變量x在x0處取得增量Δx(點x0+Δx仍在該鄰域內)時,相應地y取得增量Δy=f(x0+Δx)-f(x0);如果Δy與Δx之比當Δx→0時的極限存在,則稱函數y=f(x)在點x0處可導,并稱這個極限為函數y=f(x)在點x0處的導數,記為f’(x0),即:
對于一般的函數,如果不使用增量的概念,函數f(x)在點x0處的導數也可以定義為:當定義域內的變量x趨近于x0時,f(x)-f(x0)/(x-x0)的極限,也就是說:
幾何意義:當函數定義域和取值都在實數域中的時候,導數可以表示函數的曲線上的切線斜率。
??????? 導函數:若函數f(x)在其定義域包含的某區間I內每一個點都可導,那么也可以說函數f(x)在區間I內可導,這時對于I內每一個確定的x值,都對應著f的一個確定的導數值,如此一來就構成了一個新的函數x→f’(x),這個函數稱作原來函數f(x)的導函數,記作:y’、f’(x)或者。值得注意的是,導數是一個數,是指函數f(x)在點x0處導函數的函數值。但在不至于混淆的情況系,通常也可以說導函數為導數。由于對每一個可導的函數f(x),都有它的導函數f’(x)存在,我們還可以定義將函數映射到其導函數的算子。這個算子稱為微分算子。
??????? 導數與微分:微分也是一種線性描述函數在一點附近變化的方式。微分和導數是兩個不同的概念。但是,對一元函數來說,可微與可導是完全等價的。可微的函數,其微分等于導數乘以自變量的微分dx,換句話說,換句話說,函數的微分與自變量的微分之商等于該函數的導數。因此,導數也叫做微商。函數y=f(x)的微分又可記作dy=f’(x)dx。
??????? 函數可導的條件:如果一個函數在定義域為全體實數,即函數在(-∞,+∞)上都有定義,那么該函數是不是在定義域上處處可導呢?答案是否定的。函數在定義域中一點可導需要一定的條件。首先,要使函數f在一點可導,那么函數一定要在這一點處連續。換言之,函數若在某點可導,則必然在該點處連續。然而,連續性并不能保證可導性。即使函數在一點上連續,也不一定就在這一點可導。事實上,存在著在每一點都連續,但又在每一點都不可導的”病態函數”。在連續而不可導的函數里,一種常見的情況是,函數在某一點連續,并且可以定義它的左導數和右導數,然而左導數和右導數并不相等,因而函數在該處不可導。實際上,若函數導數存在,則必然可以推出左右導數相等,這是由極限的性質(極限存在則左右極限相等)得來。如果函數在一點的左右導數都存在并且相等,那么函數在該處可導。
??????? 導數與函數的性質:
??????? (1)、單調性:如果函數的導函數在某一區間內恒大于零(或恒小于零),那么函數在這一區間內單調遞增(或單調遞減),這種區間也稱為函數的單調區間。導函數等于零的點稱為函數的駐點(或極值可疑點),在這類點上的函數可能會取得極大值或極小值。
??????? (2)、凹凸性:可導函數的凹凸性與其導數的單調性有關。如果函數的導函數在某個區間上單調遞增,那么這個區間上的函數是向下凸的,反之則是向上凸的。
??????? 基本函數的導數:
??????? (1)、多項式函數:如果f(x)=xr,其中r是非零實數,那么導函數f’(x)=rxr-1。函數f的定義域可以是整個實數域,但導函數的定義域則不一定與之相同。
??????? (2)、常函數的導數是0。
??????? (3)、底數為e的指數函數y=ex的導數還是自身。一般的指數函數y=ax的導數還需要乘以一個系數即為ln(a)ax。自然對數函數ln(x)的導數是x-1.同樣的,一般的對數函數loga(x)導數則還需要乘以一個系數即為1/(xln(a))。
??????? (4)、三角函數的導數仍然是三角函數,或者由三角函數構成:
???????????????? f’(sin(x))=cos(x)??? f’(tan(x))= sec2(x)=1/(cos2(x))
???????????????? f’(cos(x))=-sin(x)??? f’(cot(s))=-csc2(x)=-1/(sin2(x))
??????? (5)、反三角函數的導數則是無理分式:
??????? 導數的求導法則:由基本函數的和、差、積、商或相互復合構成的函數的導函數則可以通過函數的求導法則來推導。基本的求導法則如下:
??????? (1)、求導的線性性:對函數的線性組合求導,等于先對其中每個部分求導后再取線性組合:(af+bg)’=af’+bg’(其中a,b為常數);
??????? (2)、兩個函數的乘積的導函數,等于其中一個的導函數乘以另一者,加上另一者的導函數與其的乘積:(fg)’=f’g+fg’
(3)、兩個函數的商的導函數也是一個分式,其中分子是分子函數的導函數乘以分母函數減去分母函數的導函數乘以分子函數后的差,而其分母是分母函數的平方:(在g(x)≠0處方有意義)
??????? (4)、復合函數的求導法則:如果有復合函數f(x)=h[g(x)],那么f’(x)=h’[g(x)]·g’(x)
??????? 若要求某個函數在某一點的導數,可以先運用以上方法求出這個函數的導函數,再看導函數在這一點的值。
二階導數:如果函數的導數f’(x)在x處可導,則稱[f’(x)]’為x的二階導數,記做:
??????? 函數在定義域中一點可導需要一定的條件是:函數在該點的左右兩側導數都存在且相等。連續的函數不一定處處可導。但處處可導的函數一定處處連續。
以上內容摘自:維基百科
??????? 之前在 ?http://blog.csdn.net/fengbingchun/article/details/73848734 和 ?http://blog.csdn.net/fengbingchun/article/details/73872828 中介紹過激活函數sigmoid、ReLU、Leaky ReLU、ELU、softplus,這里分別對它們進行求導:
??????? sigmoid:
??????? ReLU:
??????? Leaky ReLU:
??????? ELU:
??????? 對ELU求導數好像有些復雜,在Caffe和tiny-dnn中求法好像也不一致,公式中是 維基百科?中給出的求法。
??????? softplus:
??????? 根據以上公式實現的C++代碼:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"#define EXP 1.0e-5namespace fbc {// ========================= Activation Function: ELUs ========================
template<typename _Tp>
int activation_function_ELUs(const _Tp* src, _Tp* dst, int length, _Tp a = 1.)
{if (a < 0) {fprintf(stderr, "a is a hyper-parameter to be tuned and a>=0 is a constraint\n");return -1;}for (int i = 0; i < length; ++i) {dst[i] = src[i] >= (_Tp)0. ? src[i] : (a * (exp(src[i]) - (_Tp)1.));}return 0;
}template<typename _Tp>
int activation_function_ELUs_derivative()
{// to do
}// ========================= Activation Function: Leaky_ReLUs =================
template<typename _Tp>
int activation_function_Leaky_ReLUs(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = src[i] > (_Tp)0. ? src[i] : (_Tp)0.01 * src[i];}return 0;
}template<typename _Tp>
int activation_function_Leaky_ReLUs_derivative(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = src[i] > (_Tp)0. ? (_Tp)1 : (_Tp)0.01;}return 0;
}// ========================= Activation Function: ReLU =======================
template<typename _Tp>
int activation_function_ReLU(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = std::max((_Tp)0., src[i]);}return 0;
}template<typename _Tp>
int activation_function_ReLU_derivative(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = src[i] < (_Tp)0 ? (_Tp)0 : (_Tp)1;}return 0;
}// ========================= Activation Function: softplus ===================
template<typename _Tp>
int activation_function_softplus(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = log((_Tp)1. + exp(src[i])); // log1p(exp(src[i]))}return 0;
}template<typename _Tp>
int activation_function_softplus_derivative(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = (_Tp)(1. / (1. + exp(-src[i])));}return 0;
}// ============================ Activation Function: sigmoid ================
template<typename _Tp>
int activation_function_sigmoid(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = (_Tp)(1. / (1. + exp(-src[i])));}return 0;
}template<typename _Tp>
int activation_function_sigmoid_derivative(const _Tp* src, _Tp* dst, int length)
{for (int i = 0; i < length; ++i) {dst[i] = (_Tp)(exp(-src[i]) / pow((1+exp(-src[i])), 2.f));}return 0;
}int test_activation_function()
{std::vector<double> src{ 1.23f, 4.14f, -3.23f, -1.23f, 5.21f, 0.234f, -0.78f, 6.23f };int length = src.size();std::vector<double> 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);return 0;
}
GitHub:https://github.com/fengbingchun/NN_Test
總結
- 上一篇: C++中const指针用法汇总
- 下一篇: 激活函数之softmax介绍及C++实现