函數的最小值
假設有一個函數 $(y=x^2)$,這個函數的圖型如下藍色線。

問題來了,這個函數的最小 y 值為多少? 又為什麼會有這個問題呢?
我們在取得一個損失函數時,即然是函數,不管是複雜的損失函數還是簡單 $(y=x^2)$,就會有取得最小值的需求。所以可以把上面的 y 值看成是損失值,愈小愈好。
微分求最小值
$(y=x^2)$ 要取得 y 的最小值,可由 y 對 x 的微分取得。
$(y’=\frac{dy}{dx}=2x)$
由上圖可知,$(y’)$ 即為斜率,當斜率為 0 時,擁有最小值,$(2x=0)$,所以 x 為 0,因此 y 的最小值就是 0。
微分不是萬靈藥
如果是多次方程式,就可能產生如下單的鞍點,這時微分求極值的方法就失效了。
底下是 4 次方程式 $(f(x)=x^{4}-60x^{3}-x+1)$ 所產生的鞍點圖形。

即然微分無法滿足所有方程式的極值求法,那麼就要發明一個可以大小通吃的方法,這就是梯度下降逼近法。此法就是在 x 軸中一小步一小步逼進,進而找到斜率最接近 0 (水平斜率) 時的值。比如在底下的 $(y=x^{2})$ 函數中,要找到 y 的最小值,就必需沿著 x 軸一步一步逼進,求出 f(x) 的微分 $(\bigtriangledown f(x))$ 何時最接近 0 ,進而求出 y 值。
3D鞍點
網路上有一個很酷的3D鞍點製作程式,如下代碼所示

逼近法
請先安裝如下套件
上述 $(y=x^2)$ 的逼近法代碼如下
in place
x = torch.tensor(x – x.grad * lr, requires_grad=True) 會產生新的 tensor x 物件。
x -= x.grad * lr 則使用 in-place 修改原本的 x 物件。速度較快,但需要 x.grad.zero_()。這點和 Python 的系統語法不同,需特別注意。
批次梯度下降法(Batch Gradient Descent : BGD)
BGD 是最基本的梯度下降法,一般是使用 $(x_{t+1} = x_{t} – f'(x_t)*\bigtriangledown x)$ 來逼近,$(f'(x_t))$ 是 y 函數在 $(x_t)$ 時的微分(斜率)。 $(\bigtriangledown x)$ 的值非常小,通常會是在 $(1*10^{-6})$ 左右。
因為 $(\bigtriangledown x)$ 在電腦上不好顯示,所以用 lr 來表示。也就是說 $(\bigtriangledown x)$ = lr,所以公式會變成 $(x_{t+1} = x_t – f'(x_t) * lr)$,我們把 lr 稱為學習率。
說白了,$(f'(x_t) * lr)$ 就是 x 軸下一次的 “步進值”。
怪異現像
這裏有一個很怪異的問題,為什麼負斜率逐漸變成水平後,不會再度變成正斜率再度往上爬升呢? 這是因為微分後的導數斜率接近於 0,而 $(\bigtriangledown f(x) \rightarrow 0)$ 又是極小的數 ,二者相乘就更加接近 0 。
也因如此, $(y = y – f'(x_{t}) * \bigtriangledown f(x) \doteq y – 0 \doteq y)$,所以 y 就會停留在原本的位置,不會繼續往上爬升。
放大學習率
將上述的程式碼中,把 lr 更改為 0.95 ,就會看到導線左右二邊跳動。
..........
xs = np.linspace(-5, 5, 100)
ys = f(xs)
epochs = 200
lr = 0.95
ax=plt.subplot()
t=threading.Thread(target=runnable)
t.start()
plt.show()

過大的學習率
接下來把學習率 lr 改成 1.0,會發現導線在左右二邊持續跳動,根本就無法收斂。

Tensorflosw 版
底下是使用 Tensorflow 的版本
