一、什麼是數值微分
數值微分就是用求導數近似值的方法。
取 或其他較小的數,則函數在x點處的導數等於:
用python等計算機語言實現時,要注意, 並不是越小越好,因爲計算機的存儲空間有限,32位單精度浮點數可表達的數字範圍在-3.40E+38 ~ +3.40E+38之間。
例子:,求其在x=1處的導數
# 函數表達式
def fx(x):
return x**2
# 數值微分求導數
# 精度較低的前向差分的數值微分
def numerical_differential(x):
dx = 10**(-4)
return (fx(x+dx)-fx(x))/dx
# 求x=1處導數
if __name__ == '__main__':
x = 1
print(numerical_differential(x))
# 輸出:2.000099999999172 誤差:1e-4
----------------------------------------------------
# 精度更高的中心差分的數值微分
def numerical_diff(fx, x):
dx = 10**(-4)
return (fx(x+dx)-fx(x-dx))/(2*dx)
if __name__ == '__main__':
x = 1
print(numerical_diff(fx, x))
# 輸出:1.9999999999992246 誤差:1e-12
結果:()
二、什麼是梯度?如何通過數值微分計算梯度?
梯度方向的反方向是函數值下降得最快速的方向。梯度是由偏導構成的向量:,比如函數 的梯度爲:
用Matplotlib繪製上圖代碼爲:
a = np.arange(-2, 2, 0.05)
b = np.arange(-2, 2, 0.05)
a, b = np.meshgrid(a, b)
y = function_2(a, b)
fig = plt.figure()
ax = Axes3D(fig)
ax.set_xlabel('x1', fontsize=14)
ax.set_ylabel('x2', fontsize=14)
ax.set_zlabel('y', fontsize=14)
# 具體函數方法可用 help(function) 查看,如:help(ax.plot_surface)
ax.plot_surface(a, b, y, cmap='rainbow',rcount=100, ccount= 100)
plt.show()
def function_2(a, b):
return a**2 + b**2
用數值微分計算梯度:比如 ,有兩個變量,那麼求點 處的梯度時,分別求出 即可,其中 a,b爲常量,是已知數。
那麼這兩個偏導數可以採用類似數值微分求導數的方式來求:
也就是說我們只要將numerical_diff函數稍作改變即可
def numerical_gradient(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x) # 生成和x形狀相同的數組
for idx in range(x.size):
tmp_val = x[idx]
# f(x+h)的計算
x[idx] = tmp_val + h
print("tempx = ", x)
fxh1 = f(x)
print("fh1 = ", fxh1)
# f(x-h)的計算
x[idx] = tmp_val - h
print("tempx = ", x)
fxh2 = f(x)
print("fh2 = ", fxh2)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 還原值
return grad
三、如何實現使用mini-bbatch數據的隨機梯度下降法(stochastic gradient descent, SGD)?
回顧一下,神經網絡的評價標準是“損失函數”,損失函數值越小表示網絡的性能越好,利用隨機梯度下降法可以在逐漸迭代中使“損失函數”值越來越小。損失函數一般是評價方差或者交叉熵誤差函數,其變量是各層網絡的權重W。
所以神經網絡的損失函數E是關於權重變量W的函數,那麼認爲,每次迭代中計算出W的梯度,然後令,迭代多次後可以使損失函數最小,即網絡性能最優。
當然,也不是嚴格意義上的最優,很可能是次優。
如何求梯度呢?
在求每一個權重參數的梯度時,令其他參數不變,利用數值微分求其偏導即可。