梯度下降(Gradient Descent)
上一篇我们介绍单一变数的斜率,今天我们就进一步探讨多个变数的个别斜率,即梯度(Gradient),并且利用『梯度下降』(Gradient Descent)的原理,计算深度学习模型的权重,有关深度学习模型的求解过程请参考『Day 03:Neural Network 的概念探讨』。
简单的说,深度学习模型的求解过程就是利用正向传导(Forward Propagation)的过程,求算目标估计值,再利用反向传导(Backpropagation),计算梯度,进而调整权重,使成本函数逐渐变变小,重複正向/反向循环,直到成本函数已无显着改善时,我们就认为已找到最佳的权重值了。有关『梯度下降』(Gradient Descent)的详细说明,请参考『Day N+1:进一步理解梯度下降』(Gradient Descent)。
单变数求解
计算梯度(Gradient)可利用偏微分(partial differentiation),对个别变数求一阶导数(First Derivative)。以下先以一个变数为例,参考下图,我们可以沿着切线往下走,步幅的大小由学习率(Learning Rate, lr)控制,逐步往下找到最低点。
import numpy as npimport matplotlib.pyplot as plt# 目标函数:y=x^2def func(x): return np.square(x) # 目标函数一阶导数:dy/dx=2*xdef dfunc(x): return 2 * x def GD(x_start, df, epochs, lr): """ 梯度下降法。给定起始点与目标函数的一阶导函数,求在epochs次反覆运算中x的更新值 :param x_start: x的起始点 :param df: 目标函数的一阶导函数 :param epochs: 反覆运算週期 :param lr: 学习率 :return: x在每次反覆运算后的位置(包括起始点),长度为epochs+1 """ xs = np.zeros(epochs+1) x = x_start xs[0] = x for i in range(epochs): dx = df(x) # v表示x要改变的幅度 v = - dx * lr x += v xs[i+1] = x return xs# Main# 起始权重x_start = 5 # 执行週期数epochs = 15 # 学习率 lr = 0.3 # 梯度下降法 # *** Function 可以直接当参数传递 ***x = GD(x_start, dfunc, epochs, lr=lr) print (x)color = list('rgbrgb') from numpy import aranget = arange(-6.0, 6.0, 0.01)plt.plot(t, func(t), c='y')line_offset=2 #切线长度for i in range(5, -1, -1): #print(linear_regression([i+0.001, i], [func(i+0.001), func(i)])) # 取相近两个点,画切线(tangent line) z=np.array([i+0.001, i]) vec=np.vectorize(func) cls = np.polyfit(z, vec(z), deg=1) p = np.poly1d(cls) print(p) x=np.array([i+line_offset, i-line_offset]) y=np.array([(i+line_offset)*p[1]+p[0], (i-line_offset)*p[1]+p[0]]) plt.plot(x, y, c=color[i-1]) plt.show()
结果如下:
上面程式的 dfunc 函数是偏微分,我们可以使用SymPy自动计算,程式如下,这样,我们就不用手算了。
from sympy import *x = symbols('x')derivative1 = diff(x**2, x)# 计算某一点(2)的微分值derivative1.subs(x, 2)
为节省篇幅,上述程式修改后,请参考 github 的 gd_diff.py。
以下,我们就举两个完整的範例,均以实际的资料集实作,两个範例均来自『Python机器学习』一书。
单层感知器求解
假设 y=w0+w1*x,要分别对w0、w1作梯度下降,只要个别对w0、w1偏微分即可,这部份程式可以参考『Python机器学习』的第二章範例程式即可,作者实作了一个感知器(Perceptron),并以鸢尾花资料集做为测试样本,我修剪后放在 github 的 ch2_short.ipynb。
重点在权重(w0、w1)的更新,如下:
update = self.eta * (target - self.predict(xi))self.w_[1:] += update * xiself.w_[0] += update
多层感知器求解
『Python机器学习』的第十二章更进一步实作多层感知器,并加上『启动函数』(Activation Function)、『L2正则化』(regularization),是一个相当完整的範例,有兴趣的读者可参考 ch12.ipynb,本範例以手写阿拉伯数字资料集做为测试样本。
结语
透过以上的简短说明,希望对读者有一丝丝的帮助,如有谬误请不吝指正。