機器學習09--神經網絡的激活函數(Activation Function)及python代碼實現

在前面的一些關於機器案例中使用了激活函數,
機器學習(1)--神經網絡初探 開篇中的 tanh(x)與tanh_deriv(x)兩個函數
    TensorFlow實例(5.1)--MNIST手寫數字進階算法(卷積神經網絡CNN) 中在最大池化時使用的 tf.nn.relu

我們爲什麼要使用激活函數,通常他有如下一些性質:

非線性: 如果是線性的時候,多層的神經網絡是無意義的
可微性: 做梯度下降,這是不可少的
單調性: 如果是非單調的,那麼無法保證網絡是凸函數。
全是高數的東東,看着暈,相當的感覺用處不大,如果你數學足夠好,自己能創建或寫出新的激活函數,
立馬覺得我這寫得太簡單,然後一塊豆腐把我拍個半死,丫的什麼都不懂
如果你數學和我一樣不太好,那就用用別人常用的就好了,所以卵用沒有,純粹爲了假裝很懂,讓你不明覺厲

激活函數用在什麼地方

當我們定義好神經網絡層,並在每兩層間做完矩陣乘法計算weight時,即np.dot後,

我們設val=np.dot(w,x),這時我們會再調用激活函數,如tanh(val)

當神經網絡正向計算完後,進行反向計算時,

通過 y(實際值)-y(計算值)求出誤差error  ,通過error * tanh_deriv() 可以得到我們要調整的值

基中tanh_deriv是tanh的導數,所以激活函數一定是成對出現,正向使用激活函數,反向使用激活函數的導數
又是一串的高等數學,高數基本幹什麼不太明白?不想深入就算了,想深入還是翻翻書吧。


再問一次,我們爲什麼要使用激活函數

如果上面導數的部份理解,那下面好理解, 導數不理解的話,就簡單記記吧

如果我們不使用激活函數,那麼正向運算時,val=np.dot(w,x)計算完就結束了,同樣反向計算時,計算到 error=y(實際值)-y(計算值)後也結束了
這時,雖然最後也會有效果,但中間層完全沒有作用,都是直來直去的嘛
數理上也簡單,如果不使用激活函數,那麼可以假設這個激活函數爲f(x)=x 同樣,導數f'(x)=1,在反向調整誤差時,中間層沒發生變化
所以綜合一句,如果不使用激活函數,則神經網絡的效果只相當於只有輸入層與輸出層兩層,設置多少層中間層也沒卵用


先介紹幾個激活函數,同時後面有相應的python代碼,同樣會繪製出相關的曲線
1、Sigmoid 與 tanh  函數,這兩個函數差不多,從下圖中就能看得出來,能夠把輸入的連續實際值進行壓縮。 
主要差異在於Sigmoid 把值壓到0-1之間,tanh把值壓到-1,1之間
仔細看看圖再想想也就看得出來了,這兩種函數都有一個共同的缺點,

當輸入非常大或者非常小的時候,這些神經元的梯度是接近於0的,

也就是說,當初始值沒設好,會導致很多值接近於0,而在梯度下降時,就會跳過

所以對初始值的設置與調試非常重要
同樣這兩個函數比較的話,tanh會更好點,因爲Sigmoid 把值壓到0-1之間,假設所有x正負值相同時,Sigmoid對應的y值不是零均值,而tanh是零均值,因此,在實際應用中,tanh 會比 sigmoid 更好,


# -*- coding:utf-8 -*-
#tanh 函數
import numpy as np
import matplotlib.pyplot as plt
def tanh(x):  
    return np.tanh(x)  
def tanh_deriv(x):  
    return 1.0 - np.tanh(x) * np.tanh(x)  
x = np.linspace(-6,6,200)
plt.scatter(x,tanh(x),label="tanh") 
plt.scatter(x,tanh_deriv(x),label="tanh_deriv")
plt.title('tanh Function')
plt.legend(loc = 'upper left')  
plt.show()
#Sigmoid  

import numpy as np
import matplotlib.pyplot as plt

def sigmoid(z):  
    return 1.0 / (1.0 + np.exp(-z))  
  
def sigmoid_deriv(z):  
    return sigmoid(z) * (1 - sigmoid(z)) 

x = np.linspace(-6,6,200)
plt.scatter(x,sigmoid(x),label="sigmoid") 
plt.scatter(x,sigmoid_deriv(x),label="sigmoid_deriv")
plt.title('sigmoid Function')
plt.legend(loc = 'upper left')  
plt.show()




2、RELU 與 Leaky RELU函數
   2.1 RELU 函數現在好像越來越受歡迎,看了好多關於爲什麼RELU對神經網絡最後效果明顯的根本原因
       但沒感覺有哪個有特別的說服力,無所謂了,大家說好了,我也贊一下,
       這個函數很簡單f(x)=max(0,x),文字表達就是,x小於零時取零,x大於零時就是x,更簡單的說負數不要
       在實操中,如果你的學習率很大時,那麼很有可能非常多的神經元無效。 
       當然,較小的學習率,這個問題就不明顯,但因爲學習率的降低,最後的計算量也就大了。
   2.2 Leaky RELU 是RELU的一個簡單變形,就是把x小於零的部份乘以一個很小的值,這樣把負值的部份進行等比壓縮
       至於最終的效果好不好我也不清楚,有人說好有人說不好,反正我沒試過,


#RELU 
import numpy as np
import matplotlib.pyplot as plt

def RELU(z):  
    return np.array([x if x > 0 else 0 for x in z])
  
def RELU_deriv(z):  
    return np.array([1 if x > 0 else 0 for x in z])

x = np.linspace(-6,6,200)
plt.scatter(x,RELU(x),label="RELU") 
plt.scatter(x,RELU_deriv(x),marker='.',label="RELU_deriv",)
plt.title('RELU Function')
plt.legend(loc = 'upper left')  
plt.show()
#Leaky RELU  

import numpy as np
import matplotlib.pyplot as plt

def LeakyRELU(z,a=0.3):  
    return np.array([x if x > 0 else a * x for x in z])
  
def LeakyRELU_deriv(z,a=0.3):  
    return np.array([1 if x > 0 else a for x in z])


x = np.linspace(-6,6,200)
plt.scatter(x,LeakyRELU(x),label="LeakyRELU") 
plt.scatter(x,LeakyRELU_deriv(x),marker='.',label="LeakyRELU_deriv",)
plt.title('LeakyRELU_deriv Function')
plt.legend(loc = 'upper left')  
plt.show()



以上四種激活函數怎麼選擇?
我也不知道,...,怎麼眼前全是豆腐,
個人感覺,純屬個人感覺,使用RELU,調整學習率很重要,tanh比Sigmoid好用一點,

又是屁話,學習率很重要?初始化、學習率,網絡層設置哪個不重要?全部都重要好的吧


寫了這麼多,就一句話的意思,多層神經網絡要使用激活函數

再畫幾個激活函數,有用?沒用?好用?難用?我也沒用過,不知道,只想裝個X,



#BentIdentity

import numpy as np
import matplotlib.pyplot as plt

def BentIdentity(z):  
    return (np.sqrt(z ** 2 + 1) - 1) / 2 + z 
  
def BentIdentity_deriv(z):  
    return z / (2 * np.sqrt(x ** 2 + 1)) + 1

x = np.linspace(-6,6,200)
plt.scatter(x,BentIdentity(x),label="BentIdentity") 
plt.scatter(x,BentIdentity_deriv(x),marker='.',label="BentIdentity_deriv",)
plt.title('BentIdentity Function')
plt.legend(loc = 'upper left')  
plt.show()
#Sinusoid
import numpy as np
import matplotlib.pyplot as plt

def Sinusoid(z):  
    return np.sin(z)
  
def Sinusoid_deriv(z):  
    return np.cos(z)

x = np.linspace(-np.pi,np.pi,200)
plt.scatter(x,Sinusoid(x),label="Sinusoid") 
plt.scatter(x,Sinusoid_deriv(x),marker='.',label="Sinusoid",)
plt.title('Sinusoid Function')
plt.legend(loc = 'upper left')  
plt.show()



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章