深度學習入門筆記 Day6/15 神經網絡(四)

一、什麼是數值微分

數值微分就是用\frac{\Delta f(x)}{\Delta x}f(x)導數近似值的方法。

取 \Delta x = 1e^{-4} 或其他較小的數,則函數在x點處的導數等於:

\frac{d f(x)}{dx} = \frac{f(x+\Delta x)-f(x)}{\Delta x}

用python等計算機語言實現時,要注意,\Delta x 並不是越小越好,因爲計算機的存儲空間有限,32位單精度浮點數可表達的數字範圍在-3.40E+38 ~ +3.40E+38之間。

例子:f(x) = x^2,求其在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

結果:(f(x)'=2x,f(1)'=2

二、什麼是梯度?如何通過數值微分計算梯度?

梯度方向的反方向是函數值下降得最快速的方向。梯度是由偏導構成的向量:Gradient = ( \frac{\partial f }{\partial x_0}, \frac{\partial f }{\partial x_1},...,\frac{\partial f }{\partial x_n} ),比如函數 f(x_0,x_1) = x_0^2+x_1^2 的梯度爲:(2x_0,2x_1)

用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

用數值微分計算梯度:比如 x =[x_0, x_1],有兩個變量,那麼求點 [x_0=a,x_1=b] 處的梯度時,分別求出 \frac{\partial f }{\partial x_0}, \frac{\partial f }{\partial x_1}即可,其中 a,b爲常量,是已知數。

那麼這兩個偏導數可以採用類似數值微分求導數的方式來求:

\frac{\partial f }{\partial x_0}=\frac{f(x_0+h,x_1)-f(x_0-h,x_1)}{2h}| _{x_0=a,x_1=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的函數,那麼認爲f(x)=E(W),每次迭代中計算出W的梯度\frac{\partial E}{\partial W},然後令W = W - \eta \frac{\partial E}{\partial W},迭代多次後可以使損失函數最小,即網絡性能最優。

當然,也不是嚴格意義上的最優,很可能是次優。

如何求梯度呢?

在求每一個權重參數的梯度時,令其他參數不變,利用數值微分求其偏導即可。

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