用Tensorflow进行线性回归和逻辑回归(五)

发布于:2025-06-25 ⋅ 阅读:(23) ⋅ 点赞:(0)

5.梯度下降

这一章,你学习了用函数最小化来代理机器学习。最小化合适的函数足于解决希望的任务。要使用这种框架,你需要使用合适的损失函数,如L2 或 H(p, q)交叉熵以转换回归或分类问题到合适的损失函数。

自动微分系统与梯度计算

机器学习是定义适合于数据集的损失函数并最小化它们的艺术。为了最小化损失函数,我们需要计算梯度并用梯度下降算法来不断减少损失。但是我们仍然需要讨论梯度是如何计算的。至今,答案是“手工”。机器学习专家通过计算学习系统的所有梯度的解析式手工计算矩阵微分。这些公式然后写成代码以实施学习算法。这种过程很古怪,不止一个专家有偶然的梯度错误。随着自动微分工程的出现,这种状况有了很大的改变。像TensorFlow这样的系统可以自动为所有损失函数计算梯度。自动微分是TensorFlow之类的系统的优点,因为机器学习实践者不用是矩阵微积分的专家。但是从高层次理解TensorFlow如何自动微分复杂的函数是值得的。对于学习微积分入门课程有困难的读者,求函数的微分是非常机械的。可以用一些简单的规则来求函数的微分。例如:

                             

这些规则可以通过链式法则组合:

                        

其中f′是f的微分而g′是g的微分。通过这些法则, 可以直接展望到如何为一维微积分编写自动微分工程。实际上,编写这种微分工程是Lisp课程第一年的练习。(事实上解析函数比取微分更难,使用Lisp解析公式很难,但是学过编译课程后会变得容易)。这些规则如何扩展到高维函数呢?数学本身很难,因为有许多数要考虑。例如,假定X = AB ,其中 X, A, B都是矩阵,则公式为

                      

可以用这种公式来为向量和张量微积分提供符号微分系统。

微分和梯度计算在model.fit()和model.fitDataset()的底层进行。但是对于有些问题,如找到卷积滤波器的最大激活图像,有必要计算微分和梯度。TensorFlow提供了APIs 来完成任务。

自动微分对实现机器学习算法(例如用于训练神经网络的反向传播)十分有用。在 Eager Execution 期间,请使用 tf.GradientTape 跟踪运算以便稍后计算梯度。您可以在 Eager Execution 中使用 tf.GradientTape 来训练和/或计算梯度。这对复杂的训练循环特别有用。由于在每次调用期间都可能进行不同运算,所有前向传递的运算都会记录到“条带”中。要计算梯度,请反向播放条带,然后丢弃。特定 tf.GradientTape 只能计算一个梯度;后续调用会引发运行时错误。

我们从最简单的情况开始。即只有一个输入张量并返回一个输出张量的函数:

f = tf.atan(x);

为了计算函数(f)关于输入(x)的微分,我们用GradientTapegradient() 函数:

#List3-13

x = tf.Variable([-4.0, -2.0, 0.0, 2.0, 4.0])

with tf.GradientTape() as t:

    f = tf.atan(x)

grad = t.gradient(f, {'x': x})

它会给你atan()函数在x值为-4.0, -2.0, 0.0, 2.0, 4.0处的微分的相应输出值,那就是你要的df/dx的值:

{'x': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.05882353, 0.2, 1., 0.2, 0.05882353], dtype=float32)>}

                     

图3-17 函数atan(x)的绘图

让我们考虑数学函数y = 2x^3。我们想要计算x = 1的梯度dy/dx。下面的代码计算这个梯度:

#List3-14

import tensorflow as tf

x = tf.Variable(1.0,tf.float32)

with tf.GradientTape() as tape:

      y = 2*x*x*x

      grad = tape.gradient(y, x)

print(grad)

tf.Tensor(6.0, shape=(), dtype=float32)

如果你的函数有多个输入张量,该如何呢? 我们考虑一个例子,f(x, y),它是两个张量的积:

#List3-15

f = x.mul(y);

为了计算函数(f)关于输入(x,y)的微分,可以这样:

x = tf.Variable([1.0, 2.0])

y = tf.Variable([-1.0, -2.0])

with tf.GradientTape() as t:

  f = x*y

grad = t.gradient(f, {'x': x, 'y': y})

print(grad)

结果是

{'x': <tf.Tensor: shape=(2,), dtype=float32, numpy=array([-1., -2.], dtype=float32)>, 'y': <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)>}

这些结果是对的,因为x * y 关于x的偏微分是y,而关于y的偏微分是x。

GradientTape上下文管理器内的运算会被记录下来,以供自动微分。如果在该上下文中计算梯度,梯度计算也会被记录。因此,完全相同的 API 也适用于高阶梯度。例如:

x = tf.Variable(1.0)  # Create a Tensorflow variable initialized to 1.0

with tf.GradientTape() as t2:

  with tf.GradientTape() as t1:

    y = x * x * x

  # Compute the gradient inside the outer `t2` context manager

  # which means the gradient computation is differentiable as well.

  dy_dx = t1.gradient(y, x)

d2y_dx2 = t2.gradient(dy_dx, x)

print('dy_dx:', dy_dx.numpy())  # 3 * x**2 => 3.0

print('d2y_dx2:', d2y_dx2.numpy())  # 6 * x => 6.0

dy_dx: 3.0
d2y_dx2: 6.0

深度学习里常见的场景包括用权重进行计算的函数。这些权重用 tf.Variable对象表示,并不显式的传递到函数作为参数。对于这些函数,在训练时,我们通常要计算函数关于权重的微分。

可学习的权重Learnable Weights

现在我们已经解释了机器学习就是最小化损失函数ℒ( x, y) 。即我们要找到使损失函数ℒ最小的参数。但是认真的读者将会记得(x,y)是固定不可变的。那么我们在学习过程中改变了 ℒ的什么参数呢?

进入可学习的权重W。假如 f(x)是我们想要拟合机器学习模型的可微函数。我们选择w作为f的参数。即,实际上我们的函数有两个参数f(W, x)。固定 W 导致函数只依赖于数据点 x。这些可学习的权重是通过最小化损失函数选择到的。后面我们会看到 TensorFlow如何用 tf.Variable来编码可学习权重的。

现在如何用合适的损失函数编码学习问题?我们如何找到损失的最小值?最小化的关键技巧是使用梯度。假如f 是依赖于权重W的函数。则 ∇W 是使f增加最快的W的方向。相反的方向更快接近f的最小值。

标记梯度Notation for Gradients

我们记可学习权重W 的梯度为∇W。有时用下面的标记很方便

                              

这种方程式说梯度 ∇W 编码了使损失变化最大的方面。


网站公告

今日签到

点亮在社区的每一天
去签到