如 機器學習(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()