突破数学/统计魔障,打好AI学习基础 (2) -- 再战梯度下降

梯度下降(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()

结果如下:
http://img2.58codes.com/2024/20001976fZrDswz5Cz.png

上面程式的 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,本範例以手写阿拉伯数字资料集做为测试样本。

结语

透过以上的简短说明,希望对读者有一丝丝的帮助,如有谬误请不吝指正。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章