机器学习 - 梯度下降

31

(本系列的 Jupyter Notebook 可以到我的码云下载。)

概述

线性回归中我们令最小二乘函数的导数等于 $0$ 求得了最小二乘法的最优解。然而并不是所有的函数都可以用这种令导数等于 $0$ 的方法求得最优解,尤其是在机器学习中,一个模型可能有成千上万的参数,每个参数的指数也可能不为 $1$ 。因此我们需要一种更通用的求解最优化问题的算法。本篇介绍的梯度下降法就是最常用的一个。

梯度下降法的基本思想是用迭代的方式调整模型参数以减小损失函数的值。当损失函数达到最小值(或极小值)时模型的参数就是最优解。

想象你站在山顶,发现山脚下有一箱闪闪发光的宝物,如何以最快的速度冲到山下呢?一种合理的策略是感受当前位置山坡的斜度,向着斜度最大的方向迈一步,然后继续感受当前位置山坡的斜度,再向着斜度最大的方向迈一步,如此往复,你就可以用最快的速度冲到山下了。

图1 - 夺宝奇兵

斜度最大的方向就是梯度方向。如果把山的表面看做是一个曲面,梯度就表示从曲面上的某一点出发,能使曲面高度变化最大的方向。比如下图中,将一只球放到山顶,它总是会向着梯度方向(红色)滚落到山谷。

图2 - 梯度下降

在详细讲解梯度下降算法之前,首先来复习一些基础知识。

基础知识

导数的定义

设函数 $y=f(x)$ 在点 $x_0$ 的某个邻域内有定义,当自变量 $x$ 在 $x_0$ 处取得增量 $\Delta{x}$ (点 $x_0 + \Delta{x}$ 仍在该邻域内)时,相应的函数取得增量 $\Delta{y} = f(x_0 + \Delta{x}) - f(x_0)$; 如果 $\Delta{y}$ 与 $\Delta{x}$ 之比当 $\Delta{x} \to 0$ 时的极限存在,则称函数 $y=f(x)$ 在点 $x_0$ 处可导,并称这个极限为函数 $y=f(x)$ 在点 $x_0$ 处的导数,记为 $f’ (x_0)$,即


$$ f’ (x_0) = \lim\limits_{\Delta{x} \to 0} \dfrac{\Delta{y}}{\Delta{x}} = \lim\limits_{\Delta{x} \to 0} \dfrac{f(x_0 + \Delta{x}) - f(x_0)}{\Delta{x}} \tag{1} $$

也可记作 $ \left. y’ \right| _{x=x_0} $ , $ \left. \dfrac{\mathrm{d} y}{\mathrm{d} x} \right| _{x=x_0}$ 或 $ \left. \dfrac{\mathrm{d} f(x)}{\mathrm{d} x} \right| _{x=x_0}$

导函数的定义

如果函数 $y=f(x)$ 在开区间 $I$ 内的每点处都可导,就称函数 $f(x)$ 在开区间 $I$ 内可导。这时,对于任一 $x \in I$ ,都对应着 $f(x)$ 的一个确定的值。这样就构成了一个新的函数,这个函数叫做原来函数 $y=f(x)$ 的导函数,记作 $y’$, $f’(x)$, $\dfrac{\mathrm{d} y}{\mathrm{d} x}$ 或 $\dfrac{\mathrm{d} f(x)}{\mathrm{d} x}$ 。

导函数简称导数。

偏导数的定义

设函数 $z = f(x, y)$ 在点 $(x_0, y_0)$ 的某一邻域内有定义,当 $y$ 固定在 $y_0$ 而 $x$ 在 $x_0$ 处有增量 $\Delta{x}$ 时,相应的函数有增量


$$ f(x_0 + \Delta{x}, y_0) - f(x_0, y_0) \tag{2}$$

, 如果


$$ \lim\limits_{\Delta{x} \to 0} \dfrac{f(x_0 + \Delta{x}, y_0) - f(x_0, y_0)}{\Delta{x}} \tag{3} $$

存在,则称此极限为函数 $z=f(x, y)$ 在点 $(x_0, y_0)$ 处对 $x$ 的偏导数,记作 $\left. \dfrac{\partial z}{\partial x} \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$, $\left. \dfrac{\partial f}{\partial x} \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$, $\left. z_x \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$ 或 $f_x (x_0, y_0)$ .

类似地,函数 $z = f(x, y)$ 在点 $(x_0, y_0)$ 处对 $y$ 的偏导数为


$$ \lim\limits_{\Delta{y} \to 0} \dfrac{f(x_0, y_0 + \Delta{y}) - f(x_0, y_0)}{\Delta{y}} \tag{4} $$

, 记作 $\left. \dfrac{\partial z}{\partial y} \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$, $\left. \dfrac{\partial f}{\partial y} \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$, $\left. z_y \right| _{\begin{array} \ {x} = x_0 \\ y = y_0 \end{array} }$ 或 $f_y (x_0, y_0)$ .

偏导函数的定义

如果函数 $z=f(x,y)$ 在区域 $D$ 内每一点 $(x, y)$ 处对 $x$ 的偏导数都存在,那么这个偏导数就是 $x$、$y$ 的函数,它就称为函数 $z = f(x,y)$ 对自变量 $x$ 的偏导函数,记作 $ \dfrac{\partial z}{\partial x} $, $\dfrac{\partial f}{\partial x}$, $z_x$, 或 $f_x(x, y)$ .

类似地,可以定义函数 $z=f(x,y)$ 对自变量 $y$ 的偏导函数,记作 $ \dfrac{\partial z}{\partial y} $, $\dfrac{\partial f}{\partial y}$, $z_y$, 或 $f_y(x, y)$ .

偏导函数简称偏导数。

方向导数的定义

设 $l$ 是 $xOy$ 平面上以 $P_0(x_0, y_0)$ 为始点的一条射线,$ \boldsymbol{e}_l = (\cos\alpha, \cos\beta)$ 是与 $l$ 同方向的单位向量。射线 $l$ 的参数方程为


$$ \left\{ \begin{array} \ x = x_0 + t \cos\alpha \\ y = y_0 + t \cos\beta \end{array} \ (t \geqslant 0) \right. \tag{5}$$

设函数 $z=f(x, y)$ 在点 $P_0(x_0, y_0)$ 的某个邻域 $U(P_0)$ 内有定义,$P(x_0 + t \cos\alpha, y_0 + t \cos\beta)$ 为 $l$ 上另一点,且 $P \in U(P_0)$. 如果函数增量 $f(x_0 + t \cos\alpha, y_0 + t \cos\beta) - f(x_0, y_0)$ 与 $P$ 到 $P_0$ 的距离 $\left| PP_0 \right| = t$ 的比值


$$ \dfrac{f(x_0 + t\cos\alpha, y_0 + t \cos\beta) - f(x_0, y_0)}{t} \tag{6}$$

当 $P$ 沿着 $l$ 趋于 $P_0$ (即 $t \to 0^+$) 时的极限存在,则称此极限为函数 $f(x, y)$ 在点 $P_0$ 沿方向 $l$ 的方向导数,记作 $\left. \dfrac{\partial f}{\partial l} \right|_{x_0, y_0}$,即


$$ \left. \dfrac{\partial f}{\partial l} \right|_{x_0, y_0} = \lim\limits_{t \to 0^+} \dfrac{f(x_0 + t\cos\alpha, y_0 + t \cos\beta) - f(x_0, y_0)}{t} \tag{7}$$

定理 如果函数 $f(x,y)$ 在点 $P_0(x_0, y_0)$ 可微分,那么函数在该点沿任一方向 $l$ 的方向导数存在,且有


$$ \left. \dfrac{\partial f}{\partial l} \right| _{(x_0, y_0)} = f_x(x_0, y_0) \cos\alpha + f_y(x_0, y_0) \cos\beta \tag{8} $$

其中 $\cos \alpha$, $\cos \beta$ 是方向 $l$ 的方向余弦。

梯度的定义

设函数 $f(x,y)$ 在平面区域 $D$ 内具有一阶连续偏导数,则对于每一点 $P_0(x_0, y_0) \in D$, 都可以定义出一个向量


$$ f_x(x_0, y_0) \boldsymbol{i} + f_y(x_0, y_0) \boldsymbol{j} \tag{9}$$

这向量称为函数 $f(x,y)$ 在点 $P_0(x_0, y_0)$ 的梯度,记作 $\textbf{grad}\ f(x_0, y_0)$ 或 $\nabla f(x_0, y_0)$,即


$$ \textbf{grad}\ f(x_0, y_0) = \nabla f(x_0, y_0) = f_x(x_0, y_0) \boldsymbol{i} + f_y(x_0, y_0) \boldsymbol{j} \tag{10}$$

其中 $\nabla = \dfrac{\partial}{\partial x} \boldsymbol{i} + \dfrac{\partial}{\partial y} \boldsymbol{j} $ 称为(二维的)向量微分算子或 Nabla 算子,$ \nabla f = \dfrac{\partial f}{\partial x} \boldsymbol{i} + \dfrac{\partial f}{\partial y} \boldsymbol{j}$ .

方向导数与梯度的关系

如果函数 $f(x, y)$ 在点 $P_0(x_0, y_0)$ 可微分,$\boldsymbol{e}_l = (\cos\alpha, \cos\beta)$ 是与方向 $l$ 同向的单位向量,则


\begin{align*} \left. \dfrac{\partial f}{\partial l} \right| _{(x_0, y_0)} &= f_x(x_0, y_0) \cos\alpha + f_y(x_0, y_0) \cos\beta \\ &= \textbf{grad}\ f(x_0, y_0) \cdot \boldsymbol{e}_l = \left| \textbf{grad} \ f(x_0, y_0) \right| \cos\theta \tag{11} \end{align*}

其中 $ \theta = \left( \textbf{grad} f(x_0, \overset{\bigwedge}{ y_0), \boldsymbol{e}_l} \right) $

上式表明了函数在一点的梯度与函数在这点的方向导数间的关系:

(1)当 $\theta = 0$, 即方向 $\boldsymbol{e}_l$ 与梯度 $\textbf{grad}\ f(x_0, y_0)$ 的方向相同时,函数 $f(x, y)$ 增加最快。此时,函数在这个方向的方向导数达到最大值,这个最大值就是梯度 $\textbf{grad}\ f(x_0, y_0)$ 的模,即


$$ \left. \dfrac{\partial f}{\partial l} \right|_{(x_0, y_0)} = \left| \textbf{grad}\ f(x_0, y_0) \right| \tag{12} $$

这个结果也表示:函数 $f(x,y)$ 在一点的梯度 $\mathbf{grad}\ f$ 是这样一个向量,它的方向是函数在这点的方向导数取得最大值的方向,它的模就等于方向导数的最大值。

(2)当 $\theta = \pi$,即方向 $\boldsymbol{e}_l$ 与梯度 $\textbf{grad}\ f(x_0, y_0)$ 的方向相反时,函数 $f(x, y)$ 减少最快,函数在这个方向的方向导数达到最小值,即


$$ \left. \dfrac{\partial f}{\partial l} \right|_{(x_0, y_0)} = - \left| \textbf{grad}\ f(x_0, y_0) \right| \tag{13} $$

(3)当 $\theta = \dfrac{\pi}{2}$,即方向 $\boldsymbol{e}_l$ 与梯度 $\textbf{grad}\ f(x_0, y_0)$ 的方向正交时,函数的变化率为零,即


$$ \left. \dfrac{\partial f}{\partial l} \right|_{(x_0, y_0)} = \left| \textbf{grad}\ f(x_0, y_0) \right| \cos \theta = 0 \tag{14} $$

梯度下降

梯度下降就是方向导数与梯度的关系中的第(2)种情况,也就是计算损失函数在当前点(由当前的模型参数决定)的梯度后,向着梯度反方向移动一步,下降到一个新的点,然后再计算这个新的点的梯度,再向着梯度反方向移动一步,再下降到一个 “更” 新的点,如此往复,如果发现函数值在一段时间内不能继续降低了,就停止算法,将当前模型的参数作为最优解。

上面提到 “移动一步” ,那么一步是多少呢?这个步长通常使用一个模型超参数(所谓超参数是指能够调整模型训练行为的参数,而不是需要训练的模型参数)来指定,这个超参数叫做学习率(learning rate),通常用 $\eta$ 来表示。因此步长就等于 $\eta \times \nabla{f}$。

上面提到 “如此往复”,那么往复都少次呢?这个次数是另外一个模型超参数,叫做时期(epoch)。

以上就是梯度下降过程,该过程可用下图表示:

图3 - 梯度下降

梯度下降求解

根据以上讨论,我们可以知道如何使用梯度下降计算最优解了,假设 $\mathbf{C}$ 为损失函数,$\mathbf{w}$ 为模型参数,$\mathbf{w}^{(i)}$ 为第 $i$ 次迭代时 $\mathbf{w}$ 的值,$\eta$ 为学习率,那么梯度下降法可以表示为:


$$ \mathbf{w}^{(i+1)} = \mathbf{w}^{(i)} - \eta \nabla_{\mathbf{w}} \mathbf{C}\left(\mathbf{w^{(i)}}\right) \tag{15} $$

最小二乘问题

下面举例说明如何运用梯度下降法求解最小二乘问题。

为什么可以使用梯度下降求解呢?因为我们在线性回归一讲中已经证明了最小二乘函数为凸函数,因此不会出现局部最优解和平原地带(见下图7)。

线性回归中已经知道,最小二乘函数的矩阵形式为:


$$ \mathcal{L} = \dfrac{1}{m} (\mathbf{y}^T \mathbf{y} - 2 \mathbf{y}^T \mathbf{X} \mathbf{w} + \mathbf{w}^T \mathbf{X}^T \mathbf{X} \mathbf{w}) \tag{16} $$

为了方便计算,我们将上面的常系数 $\dfrac{1}{m}$ 换成 $\dfrac{1}{2}$,得到损失函数为:


$$ \mathbf{C}(\mathbf{w}) = \dfrac{1}{2} \left(\mathbf{y}^T \mathbf{y} - 2 \mathbf{y}^T \mathbf{X} \mathbf{w} + \mathbf{w}^T \mathbf{X}^T \mathbf{X} \mathbf{w}\right) \tag{17} $$

计算梯度:


\begin{align*} \nabla_{\mathbf{w}} \mathbf{C}(\mathbf{w}) = \dfrac{1}{2} \left( - 2 \mathbf{X}^T \mathbf{y} + 2 \mathbf{X}^T \mathbf{X} \mathbf{w} \right) = \mathbf{X}^T \left(\mathbf{X} \mathbf{w} - \mathbf{y} \right) \tag{18} \end{align*}

将上式代入 $(15)$ 式得:


\begin{align*} \mathbf{w}^{(i+1)} &= \mathbf{w}^{(i)} - \eta \mathbf{X}^T \left(\mathbf{X} \mathbf{w}^{(i)} - \mathbf{y} \right) \tag{19} \end{align*}

下面就可以通过 $(18)$$(19)$ 式应用梯度下降算法了,不过首先需要构造一个样本集,这可以用如下代码实现:

1
2
3
4
5
6
7
8
9
10
np.random.seed(42)

m = 100
w = np.array([3, 4]).reshape([-1, 1])
x = np.linspace(-10, 10, m, [-1, 1])
X = np.c_[np.ones([m, 1]), x]
y = X.dot(w) + np.random.normal(0, 5, m).reshape([-1, 1])

plt.scatter(x, y, s=10)
plt.show()

样本集如下图:

图4 - 数据集

套用 $(18)$$(19)$ 式,可以得到:

1
2
3
4
5
6
7
8
9
eta = 0.0001
epoches = 2000
w = np.random.randn(2, 1)

for epoch in range(epoches):
gradients = X.T.dot(X.dot(w) - y)
w -= eta * gradients

print(w)

打印结果为:

1
2
[[2.48076741]
[4.03448317]]

我们可以对比使用正规方程得到的最优解:

1
2
w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
print(w)

打印结果为:

1
2
[[2.48076741]
[4.03448317]]

可以看到两个结果一模一样,说明梯度下降的确计算出了最优解。最优解如下图所示:

图5 - 最优解

最大似然问题

最大似然问题也可以通过梯度下降来求解,在线性回归中提到,最大似然法是要求下面的对数似然函数的最大值:


$$ \log{\mathcal{L}} = - \dfrac{m}{2} \log{ 2 \pi } - m \log \sigma - \dfrac{1}{2 \sigma^2} \left(\mathbf{y}^T \mathbf{y} - 2 \mathbf{y}^T \mathbf{X} \mathbf{w} + \mathbf{w}^T \mathbf{X}^T \mathbf{X} \mathbf{w} \right) \tag{20} $$

上式并不像最小二乘函数一样描述的是真实值与预测值之间的差距,而是描述模型输出真实值的最大可能性,这是目标,因此该函数被称为目标函数。我们的目是最求解目标函数的最大值,这是方向导数与梯度的关系中的第(1)种情况,因此实际上这里使用的是梯度上升法,而不是梯度下降法。首先我们需要求对数似然函数的梯度,这在线性回归中已经求得:


$$ \dfrac{\partial{\log \mathcal{L}}}{\partial \mathbf{w}} = \frac{1}{\sigma^2} \mathbf{X}^T \mathbf{y} - \frac{1}{\sigma^2} \mathbf{X}^T \mathbf{X} \mathbf{w} \tag{21} $$

首先计算梯度,用 $\mathbf{T}$ 表示目标函数,为了简化计算,将与 $\mathbf{w}$ 无关的常量 $\dfrac{1}{\sigma^2}$ 去掉,则上式化简为:


$$ \nabla_\mathbf{w} \mathbf{T}(\mathbf{w}) = \mathbf{X}^T \mathbf{y} - \mathbf{X}^T \mathbf{X} \mathbf{w} = \mathbf{X}^T( \mathbf{y} - \mathbf{X} \mathbf{w} ) \tag{22} $$

梯度上升法就表示为:


$$ \mathbf{w}^{(i+1)} = \mathbf{w}^{(i)} + \eta \mathbf{X}^T \left( \mathbf{y} - \mathbf{X} \mathbf{w}^{(i)} \right) \tag{23} $$

上面的 $(22)$$(23)$ 式是不是很熟悉呢?$(22)$ 式就是 $(18)$ 式的负数,而 $(23)$ 式就是 $(19)$ 式。也就是说求目标函数的最大值,可以转化为求目标函数的负数的最小值,从而继续使用梯度下降求解,这样就与最小二乘问题一样了。当然也可以使用 $(22)$$(23)$ 式求解,结果是一样的。这里就不列出代码了,读者可自行完成。

下面我们来看看如何选取学习率。

学习率

学习率的大小是影响训练时长和训练结果的重要参数。

如果学习率太小,那么在每一次迭代中,模型参数调整的幅度将非常小,导致整个算法收敛得非常缓慢,训练时间变得很长,但是一旦进入最优解附近,则可以很好地接近最优解。见下图:

图6 - 学习率过小

学习率太小有时还会造成在高原地区停滞不前,或陷入局部最优解提前结束算法。如下图所示:

图7 - 局部最优与高原地带

而如果学习率太大,那么在每一次迭代中,模型参数调整的幅度将非常大,算法开始时收敛很快,训练时间也会变短,但是在接近最优解时会跳过最优解,并在最优解附近徘徊。如下图所示:

图8 - 学习率过大

下面我们做一些实验,看看不同的学习率对模型收敛速度的影响,还是使用上面最小二乘问题的数据集,下面分别列出学习率适中,学习率过小和学习率过大的情况。

下面是学习率为 $0.00005$ 的情况(请点击图像下面的 “开始” 按钮开始训练),此时学习率适中,可以看到模型收敛得很好:

图9 - 学习率适中

下面是学习率为 $0.000001$ 的情况,此时学习率过小,可以看到收敛速度慢了很多,在经过 $1000$ 个 epoch 后仍未达到最优值:

图10 - 学习率过小

下面是学习率为 $0.0006$ 的情况,此时学习率过大,可以看到模型并不会收敛,而是如图8一样来回摆动:

图11 - 学习率过大

下面是上述三种情况的均方差随 epoch 的变化曲线(仅列出前 100 epoch):

图12 - 学习率对 MSE 曲线的影响

从上图可以看到学习率过大会造成曲线上升,而学习率过小会造成曲线下降缓慢。如何根据上图选取合适的学习率呢?一个策略是找到上升和下降的临界点,比如一开始选择的学习率为 $0.01$,如果曲线向下,那么就增大这个值,比如 $0.1$, $1.0$, $…$ 直到找到曲线上升或横向波动的学习率。如果学习率为 $0.01$ 时曲线向上,那就减少这个值,比如 $0.001$, $0.0001$, $…$ 直到找到曲线上升或横向波动的学习率。找到这个临界点之后,我们一般取临界点的一半作为最后的学习率。比如 $0.0001$ 为临界点,那么我们就选择 $0.00005$ 作为最后的学习率。

选取学习率的另外一个方案是开始时使用较大的学习率以跳过平原地带和局部最优解,然后不断减小学习率,接近尾声时,将学习率降到最小,那么就可以很好地接近最优解。这种方法叫做学习计划(Learning Schedule)。当然这同样也存在问题,如果学习率减小得太快,那么可能陷入局部最优解或高原地带,如果学习率减小得太慢,则会在最优解附近徘徊很久才能很好地接近最优解。因此学习率和学习计划是一个需要根据实际模型进行调整的参数,不能一概而论。

梯度下降法的种类

批量梯度下降

注意上面在求解梯度时,每次迭代使用的都是整个样本集,因此这种梯度下降被称为批量梯度下降。在实际训练模型时,样本集有可能相当大,计算这样的梯度会很耗时,另外也很难用于在线学习算法中,为了解决这个问题,可以使用随机梯度下降。

随机梯度下降

随机梯度下降与批量梯度下降不同的是随机梯度下降在每次迭代中仅计算一个样本的梯度,并将其作为模型的梯度进行梯度下降,该算法在每一个 Epoch 中,从样本集中随机抽取等同于样本数量的样本(有放回抽样),并对每一个抽取的样本应用梯度下降算法。上面的例子也可以利用随机梯度下降法求解:

1
2
3
4
5
6
7
8
9
10
11
12
epoches = 2000
eta = 0.0001
w = np.random.randn(2, 1)

for epoch in range(epoches):
for sample in range(m):
index = np.random.randint(m)
xi = X[index:index+1]
yi = y[index:index+1]
gradients = xi.T.dot(xi.dot(w) - yi)
w -= eta * gradients
print(w)

打印结果:

1
2
[[2.4483796 ]
[4.03874205]]

下图是收敛情况:

图13 - 随机梯度下降收敛情况

下图是均方差随 epoch 而变化的曲线图:

图14 - 随机梯度下降 MSE 曲线

可以看到由于单个样本的梯度有时会与模型的梯度方向相差很大,因此在随机梯度下降时会有很大波动,不过总的来说,收敛方向是向着最优解方向的。

小批量梯度下降

介于批量梯度下降和随机梯度下降之间的是小批量梯度下降,该算法既不用整个模型计算梯度,也不用单个样本计算梯度,而是在样本中选出一部分子集作为训练对象,这样既避免了算法速度慢的问题,也避免了收敛时的波动。小批量中样本的数量是一个模型超参数。

上面的例子使用小批量梯度下降求解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
epoches = 2000
eta = 0.0001
batch_size = 10
batches = m // batch_size

for epoch in range(epoches):
shuffled_indices = np.random.permutation(m)
X_suffled = X[shuffled_indices]
y_suffled = y[shuffled_indices]
for batch in range(batches):
X_batch = X_suffled[batch:batch*batch_size]
y_batch = y_suffled[batch:batch*batch_size]
gradients = X_batch.T.dot(X_batch.dot(w) - y_batch)
w -= eta * gradients

print(w)

输出结果为:

1
2
[[2.4938418 ]
[4.05653076]]

下图是收敛情况:

图15 - 小批量梯度下降收敛情况

下图是均方差随 epoch 而变化的曲线图:

图16 - 小批量梯度下降 MSE 曲线

可以看到小批量梯度下降仍会有波动,但是比随机梯度下降小。

模型参数曲线

下图是上述三种梯度下降的模型参数的变化曲线,可以进一步看到,随机梯度下降在收敛时参数有更大的波动,而小批量梯度下降参数的波动较小,批量梯度下降则没有波动。

图17 - 模型参数变化曲线

以上就是梯度下降的讲解,感谢阅读!如果有任何疑问或建议请在评论区留言!

参考资料

  1. 《高等数学》同济大学第六版
  2. 《Hands-On Machine Learning with Scikit-Learn and TensorFlow》
  3. Neural Networks and Deep Learning

版权声明:本文为原创文章,转载请注明出处。http://cynhard.com/2018/06/24/ML-Gradient-Descent/

推荐文章