《动手学深度学习(Dive into Deeplearning)》(第二版)——第二章 _2.4 微分

《动手学深度学习(Dive into Deeplearning)》(第二版)——第二章 _2.4 微分

  • 第二章 预备知识
    • § 前情回顾
    • § 2.4 微分
      • 2.4.1 导数和微分
      • 2.4.2 偏导数
      • 2.4.3 梯度
      • 2.4.4 链式法则
      • 2.4.5 总结
      • *课后练习*

第二章 预备知识

§ 前情回顾

  前面我们回顾了线性代数相关的知识,但是也只是一些基本的。有的人说学习机器学习、深度学习不太需要了解特别详细的数学知识,但我认为还是十分有必要学习这些基础知识的。当你清楚的知道这些数学知识,就能清晰的知道一些函数的底层逻辑,而这也能让你更加得心应手地利用这些函数。


§ 2.4 微分

  在机器学习当中,我们通常会定义一个 损失函数(loss function)来衡量模型的训练程度,而根据损失函数来调整模型参数就需要利用到求导微分。


2.4.1 导数和微分

  我们先来简单过一过导数的计算,这是所有深度学习优化算法的关键步骤。

   f f f 的导数定义为:
f ′ ( x ) = lim ⁡ h → 0 f ( x + h ) − f ( x ) h f'(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h} f(x)=h0limhf(x+h)f(x)
如果极限 f ′ ( a ) f'(a) f(a) 存在,则称 f f f a a a 处是可微的。一般我们将这个导数 f ′ ( x ) f'(x) f(x) 称为 f ( x ) f(x) f(x) 相对于 x x x 的瞬时变化率。

  我们不妨来做个实验,定义一个函数 f ( x ) = 3 x 2 − 4 x f(x)=3x^2-4x f(x)=3x24x 如下:

import numpy as np
from IPython import display
from d2l import torch as d2l
%matplotlib inline

def f(x):
    return 3 * x ** 2 - 4 * x

我们令 x = 1 x=1 x=1 并让 h h h 接近 0 0 0 ,式中 f ( x + h ) − f ( x ) h \frac{f(x+h)−f(x)}{h} hf(x+h)f(x) 的数值结果接近 2 2 2 。虽然这个实验不是一个数学证明,但之后我们就会知道,当 x = 1 x=1 x=1 时,导数 u ′ u′ u 2 2 2

def numerical_lim(f, x, h):
    return (f(x + h) - f(x)) / h

h = 0.1
for i in range(5):
    print(f'h={
       h:.5f}, numerical limit={
       numerical_lim(f, 1, h):.5f}')
    h *= 0.1
h=0.10000, numerical limit=2.30000
h=0.01000, numerical limit=2.03000
h=0.00100, numerical limit=2.00300
h=0.00010, numerical limit=2.00030
h=0.00001, numerical limit=2.00003

  接着我们来熟悉一下导数的几个符号,我相信朋友们肯定都知道这些,让我们一起回顾一下,以下的表达式是等价的:
f ′ ( x ) = y ′ = d y d x = d f d x = d d x f ( x ) = d f ( x ) = d f x ( x ) f'(x)=y'=\frac{dy}{dx}=\frac{df}{dx}=\frac{d}{dx}f(x)=df(x)=df_{x}(x) f(x)=y=dxdy=dxdf=dxdf(x)=df(x)=dfx(x)
其中符号 d d x \frac{d}{dx} dxd D D D微分运算符, 表示微分操作。还有一些常见的规则:

  • d C = 0 dC=0 dC=0 C C C是一个常数)
  • d x n = n x n − 1 dx^{n}=nx^{n-1} dxn=nxn1幂律 n n n是任意实数)
  • d e x = e x de^{x}=e^{x} dex=ex
  • d l n ( x ) = 1 x dln(x)=\frac{1}{x} dln(x)=x1

为了微分一个由一些简单函数(如上面的常见函数)组成的函数,下面有一些常用的规则。假设函数 f f f g g g 都是可微的, C C C 是一个常数,我们有:

  • 常数相乘法则:
    d d x [ C f ( x ) ] = C d d x f ( x ) \frac{d}{dx}[Cf(x)]=C\frac{d}{dx}f(x) dxd[Cf(x)]=Cdxdf(x)
  • 加法法则:
    d d x [ f ( x ) + g ( x ) ] = d d x f ( x ) + d d x g ( x ) \frac{d}{dx}[f(x)+g(x)]=\frac{d}{dx}f(x)+\frac{d}{dx}g(x) dxd[f(x)+g(x)]=dxdf(x)+dxdg(x)
  • 乘法法则:
    d d x [ f ( x ) g ( x ) ] = f ( x ) d d x [ g ( x ) ] + g ( x ) d d x [ f ( x ) ] \frac{d}{dx}[f(x)g(x)]=f(x)\frac{d}{dx}[g(x)]+g(x)\frac{d}{dx}[f(x)] dxd[f(x)g(x)]=f(x)dxd[g(x)]+g(x)dxd[f(x)]
  • 除法法则:
    d d x [ f ( x ) g ( x ) ] = g ( x ) d d x [ f ( x ) ] − f ( x ) d d x [ g ( x ) ] [ g ( x ) ] 2 \frac{d}{dx}[\frac{f(x)}{g(x)}]=\frac{g(x)\frac{d}{dx}[f(x)]-f(x)\frac{d}{dx}[g(x)]}{[g(x)]^{2}} dxd[g(x)f(x)]=[g(x)]2g(x)dxd[f(x)]f(x)dxd[g(x)]

  我们利用这些规则计算一下之前我们设置的函数 f ( x ) = 3 x 2 − 4 x f(x)=3x^2-4x f(x)=3x24x 的导数 f ′ ( x ) = 3 d d x x 2 − 4 d d x x = 6 x − 4 f'(x)=3\frac{d}{dx}x^2-4\frac{d}{dx}x=6x-4 f(x)=3dxdx24dxdx=6x4。然后我们带入 x = 1 x=1 x=1 ,我们就能得到 f ′ ( x ) = 2 f'(x)=2 f(x)=2 ;这一点和我们之前的实验得出的结果一致。

  为了对导数的这种解释进行可视化,我们将使用matplotlib,这是一个Python中流行的绘图库。在d2l包中有封装了几个需要用到的函数定义如下。

  • use_svg_display函数指定matplotlib软件包输出svg图表以获得更清晰的图像:
def use_svg_display():  #@save
    """使用svg格式在Jupyter中显示绘图。"""
    display.set_matplotlib_formats('svg')
  • 定义set_figsize函数来设置图表大小(注意:此处直接调用 d2l.plt,因为包中已经调用了函数):
def set_figsize(figsize=(3.5, 2.5)):  #@save
    """设置matplotlib的图表大小。"""
    use_svg_display()
    d2l.plt.rcParams['figure.figsize'] = figsize
  • set_axes函数用于设置由matplotlib生成图表的轴的属性:
#@save
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴。"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
  • 通过这三个用于图形配置的函数,我们定义了plot函数来简洁地绘制多条曲线,因为我们需要在整个书中可视化许多曲线:
#@save
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
    """绘制数据点。"""
    if legend is None:
        legend = []

    set_figsize(figsize)
    axes = axes if axes else d2l.plt.gca()

    # 如果 `X` 有一个轴,输出True
    def has_one_axis(X):
        return (hasattr(X, "ndim") and X.ndim == 1 or
                isinstance(X, list) and not hasattr(X[0], "__len__"))

    if has_one_axis(X):
        X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        if len(x):
            axes.plot(x, y, fmt)
        else:
            axes.plot(y, fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
  • 现在我们就能绘制函数 f ( x ) f(x) f(x) 以及其在 x = 1 x=1 x=1 处的切线 y = 2 x − 3 y=2x-3 y=2x3,而切线的系数就是我们之前得到的导数值:
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])

《动手学深度学习(Dive into Deeplearning)》(第二版)——第二章 _2.4 微分_第1张图片


2.4.2 偏导数

  在深度学习中,函数通常有许多的变量,而我们将微分的思想推广到这样的多元函数中后,偏导数的意义也就出现了。

  设 y = f ( x 1 , x 2 , ⋯   , x n ) y=f(x_1,x_2,\cdots,x_n) y=f(x1,x2,,xn) 是一个具有 n n n元变量的函数。而 y = f ( x 1 , x 2 , ⋯   , x n ) y=f(x_1,x_2,\cdots,x_n) y=f(x1,x2,,xn) 是一个具有 n n n个变量的函数。 y y y关于第 i i i个参数 x i x_i xi的偏导数为:
∂ y ∂ x i = lim ⁡ h → 0 f ( x 1 , ⋯   , x i − 1 , x i + h , x i + 1 , ⋯   , x n ) − f ( x 1 , ⋯   , x i , ⋯   , x n ) h \frac{\partial y}{\partial x_i}=\lim_{h\to 0}\frac{f(x_1,\cdots,x_{i-1},x_i+h,x_{i+1},\cdots,x_n)-f(x_1,\cdots,x_i,\cdots,x_n)}{h} xiy=h0limhf(x1,,xi1,xi+h,xi+1,,xn)f(x1,,xi,,xn)
为了计算 ∂ y ∂ x i \frac{\partial y}{\partial x_i} xiy 我们通常会将其他变量简单的看作是常数,计算 y y y关于 x i x_i xi的导数。


2.4.3 梯度

  我们可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度(gradient)向量。设函数 f : R n → R f:R_n→R f:RnR 的输入是一个 n n n 维向量 x = [ x 1 , x 2 , … , x n ] ⊤ x=[x_1,x_2,…,x_n]^\top x=[x1,x2,,xn] ,并且输出是一个标量。 函数 f ( x ) f(x) f(x) 相对于 x x x 的梯度是一个包含 n n n 个偏导数的向量:
∇ x f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , ⋯   , ∂ f ( x ) ∂ x n ] ⊤ \nabla_xf(x)=[\frac{\partial f(x)}{\partial x_1},\frac{\partial f(x)}{\partial x_2},\cdots,\frac{\partial f(x)}{\partial x_n}]^\top xf(x)=[x1f(x),x2f(x),,xnf(x)]
梯度对于我们设计深度学习的优化算法有很大的用处。


2.4.4 链式法则

  在深度学习中,多元函数通常是以复合 的形式出现的。然而链式法则就能帮助我们很好的微分复合函数。具体的请朋友们查阅相关资料了解。


2.4.5 总结

  • 微分和积分是微积分的两个分支,其中前者可以应用于深度学习中无处不在的优化问题。
  • 导数可以被解释为函数相对于其变量的瞬时变化率。它也是函数曲线的切线的斜率。
  • 梯度是一个向量,其分量是多变量函数相对于其所有变量的偏导数。
  • 链式法则使我们能够微分复合函数。

课后练习

  • 绘制函数 y = f ( x ) = x 3 − 1 x y=f(x)=x^3−\frac{1}{x} y=f(x)=x3x1 和其在 x = 1 x=1 x=1 处切线的图像。
"""首先,看看该函数在x = 1处的极限值也即切线的斜率"""
from d2l import torch as d2l
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

def f(x):
	return x ** 3 - 1 / x

def num_lim(f, x, h):
	return (f( x + h ) - f(x)) / h

h = 0.1
for i in range(5):
	print(f'h={
        h:.5f}, num_lim={
        num_lim(f, 1, h):.5f}')
	h *= 0.1


"""然后再利用已有函数直接进行绘制"""
x = np.arange(0, 3, 0.1)
d2l.plot(x, [f(x), 4 * x - 4], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])

得到如下结果:
《动手学深度学习(Dive into Deeplearning)》(第二版)——第二章 _2.4 微分_第2张图片

  • 求函数 f ( x ) = 3 x 1 2 + 5 e x 2 f(\mathbf x)=3x^2_1+5e^{x_2} f(x)=3x12+5ex2 的梯度。
    ∇ x f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 ] = [ 6 x 1 + 5 e x 2 , 3 x 1 2 + 5 e x 2 ] \nabla_\mathbf xf(\mathbf x)=[\frac{\partial f(\mathbf x)}{\partial x_1},\frac{\partial f(\mathbf x)}{\partial x_2}]=[6x_1+5e^{x_2},3x^2_1+5e^{x_2}] xf(x)=[x1f(x),x2f(x)]=[6x1+5ex2,3x12+5ex2]
  • 函数 f ( x ) = ∥ x ∥ 2 f(\mathbf x)=∥\mathbf x∥_2 f(x)=x2 的梯度是什么?
    f ′ ( x ) = 2 x ⊤ f'(\mathbf x)=2\mathbf x^\top f(x)=2x
  • 你可以写出函数 u = f ( x , y , z ) u=f(x,y,z) u=f(x,y,z) ,其中 x = x ( a , b ) , y = y ( a , b ) , z = z ( a , b ) x=x(a,b) , y=y(a,b) , z=z(a,b) x=x(a,b)y=y(a,b)z=z(a,b) 的链式法则吗?
    u ′ = f ′ ( x , y , z ) = ∂ f ( x , y , z ) ∂ x ∂ f ( x , y , z ) ∂ y ∂ f ( x , y , z ) ∂ z = [ ∂ f ( x , y , z ) ∂ x ( a , b ) ∂ x ( a , b ) ∂ a ∂ x ( a , b ) ∂ b ] [ ∂ f ( x , y , z ) ∂ y ( a , b ) ∂ y ( a , b ) ∂ a ∂ y ( a , b ) ∂ b ] [ ∂ f ( x , y , z ) ∂ z ( a , b ) ∂ z ( a , b ) ∂ a ∂ z ( a , b ) ∂ b ] u'=f'(x,y,z)=\frac{\partial f(x,y,z)}{\partial x}\frac{\partial f(x,y,z)}{\partial y}\frac{\partial f(x,y,z)}{\partial z}=[\frac{\partial f(x,y,z)}{\partial x(a,b)}\frac{\partial x(a,b)}{\partial a}\frac{\partial x(a,b)}{\partial b}][\frac{\partial f(x,y,z)}{\partial y(a,b)}\frac{\partial y(a,b)}{\partial a}\frac{\partial y(a,b)}{\partial b}][\frac{\partial f(x,y,z)}{\partial z(a,b)}\frac{\partial z(a,b)}{\partial a}\frac{\partial z(a,b)}{\partial b}] u=f(x,y,z)=xf(x,y,z)yf(x,y,z)zf(x,y,z)=[x(a,b)f(x,y,z)ax(a,b)bx(a,b)][y(a,b)f(x,y,z)ay(a,b)by(a,b)][z(a,b)f(x,y,z)az(a,b)bz(a,b)]

这一节就到这了,我们下一节再见~~

你可能感兴趣的:(《动手学深度学习》自学之路,机器学习,深度学习,人工智能,python,算法)