微积分
🏷sec_calculus
参考动手学深度学习教材对应章节:https://zh-v2.d2l.ai/
根据课程相关章节的Jupyter文件进行运行得到结果并导出。
在2500年前,古希腊人把一个多边形分成三角形,并把它们的面积相加,才找到计算多边形面积的方法。
为了求出曲线形状(比如圆)的面积,古希腊人在这样的形状上刻内接多边形。
如 :numref:fig_circle_area
所示,内接多边形的等长边越多,就越接近圆。
这个过程也被称为逼近法(method of exhaustion)。
🏷fig_circle_area
事实上,逼近法就是积分(integral calculus)的起源,
我们将在 :numref:sec_integral_calculus
中详细描述。
2000多年后,微积分的另一支,微分(differential calculus)被发明出来。
在微分学最重要的应用是优化问题,即考虑如何把事情做到最好.
正如在 :numref:subsec_norms_and_objectives
中讨论的那样,
这种问题在深度学习中是无处不在的。
在深度学习中,我们“训练”模型,不断更新它们,使它们在看到越来越多的数据时变得越来越好。
通常情况下,变得更好意味着最小化一个损失函数(loss function),
即一个衡量“我们的模型有多糟糕”这个问题的分数。
最终,我们真正关心的是生成一个模型,它能够在从未见过的数据上表现良好。
但“训练”模型只能将模型与我们实际能看到的数据相拟合。
因此,我们可以将拟合模型的任务分解为两个关键问题:
- 优化(optimization):用模型拟合观测数据的过程;
- 泛化(generalization):数学原理和实践者的智慧,能够指导我们生成出有效性超出用于训练的数据集本身的模型。
为了帮助你在后面的章节中更好地理解优化问题和方法,
本节提供了一个非常简短的入门教程,帮你快速掌握深度学习中常用的微分知识。
导数和微分
我们首先讨论导数的计算,这是几乎所有深度学习优化算法的关键步骤。
在深度学习中,我们通常选择对于模型参数可微的损失函数。
简而言之,对于每个参数,
如果我们把这个参数增加或减少一个无穷小的量,我们可以知道损失会以多快的速度增加或减少,
假设我们有一个函数
f
:
R
n
→
R
f: \mathbb{R}^n \rightarrow \mathbb{R}
f:Rn→R,其输入和输出都是标量。
(如果
f
f
f的导数存在,这个极限被定义为)
(
f
′
(
x
)
=
lim
h
→
0
f
(
x
+
h
)
−
f
(
x
)
h
.
f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h}.
f′(x)=h→0limhf(x+h)−f(x).)
:eqlabel:eq_derivative
如果
f
′
(
a
)
f'(a)
f′(a)存在,则称
f
f
f在
a
a
a处是可微(differentiable)的。
如果
f
f
f在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的。
我们可以将 :eqref:eq_derivative
中的导数
f
′
(
x
)
f'(x)
f′(x)解释为
f
(
x
)
f(x)
f(x)相对于
x
x
x的瞬时(instantaneous)变化率。
所谓的瞬时变化率是基于
x
x
x中的变化
h
h
h,且
h
h
h接近
0
0
0。
为了更好地解释导数,让我们做一个实验。
(定义
u
=
f
(
x
)
=
3
x
2
−
4
x
u=f(x)=3x^2-4x
u=f(x)=3x2−4x)如下:
%matplotlib inline
import numpy as np
from IPython import display
from d2l import torch as d2l
def f(x):
return 3 * x ** 2 - 4 * x
[通过令
x
=
1
x=1
x=1并让
h
h
h接近
0
0
0,] :eqref:eq_derivative
中(
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
让我们熟悉一下导数的几个等价符号。
给定
y
=
f
(
x
)
y=f(x)
y=f(x),其中
x
x
x和
y
y
y分别是函数
f
f
f的自变量和因变量。以下表达式是等价的:
f ′ ( x ) = y ′ = d y d x = d f d x = d d x f ( x ) = D f ( x ) = D x f ( x ) , f'(x) = y' = \frac{dy}{dx} = \frac{df}{dx} = \frac{d}{dx} f(x) = Df(x) = D_x f(x), f′(x)=y′=dxdy=dxdf=dxdf(x)=Df(x)=Dxf(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=nxn−1(幂律(power rule), n n n是任意实数)
- D e x = e x De^x = e^x Dex=ex
- D ln ( x ) = 1 / x D\ln(x) = 1/x Dln(x)=1/x
为了微分一个由一些常见函数组成的函数,下面的一些法则方便使用。
假设函数
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} \left[\frac{f(x)}{g(x)}\right] = \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)].
现在我们可以应用上述几个法则来计算
u
′
=
f
′
(
x
)
=
3
d
d
x
x
2
−
4
d
d
x
x
=
6
x
−
4
u'=f'(x)=3\frac{d}{dx}x^2-4\frac{d}{dx}x=6x-4
u′=f′(x)=3dxdx2−4dxdx=6x−4。
令
x
=
1
x=1
x=1,我们有
u
′
=
2
u'=2
u′=2:在这个实验中,数值结果接近
2
2
2,
这一点得到了我们在本节前面的实验的支持。
当
x
=
1
x=1
x=1时,此导数也是曲线
u
=
f
(
x
)
u=f(x)
u=f(x)切线的斜率。
[为了对导数的这种解释进行可视化,我们将使用matplotlib
],
这是一个Python中流行的绘图库。
要配置matplotlib
生成图形的属性,我们需要(定义几个函数)。
在下面,use_svg_display
函数指定matplotlib
软件包输出svg图表以获得更清晰的图像。
注意,注释#@save
是一个特殊的标记,会将对应的函数、类或语句保存在d2l
包中。
因此,以后无须重新定义就可以直接调用它们(例如,d2l.use_svg_display()
)。
def use_svg_display(): #@save
"""使用svg格式在Jupyter中显示绘图"""
display.set_matplotlib_formats('svg')
我们定义set_figsize
函数来设置图表大小。
注意,这里我们直接使用d2l.plt
,因为导入语句
from matplotlib import pyplot as plt
已标记为保存到d2l
包中。
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() # Axes.grid()函数用于配置网格线
通过这三个用于图形配置的函数,我们定义了plot
函数来简洁地绘制多条曲线,
因为我们需要在整个书中可视化许多曲线。
#@save
# https://finthon.com/category/data-processing/matplotlib/
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() # plt.gcf()当前图表、plt.gca()获取子图,分别表示Get Current Figure和Get Current Axes
# 如果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__"))
# hasattr(x, "ndim"):hasattr()函数用于判断是否包含对应的属性 ,ndim表示维度的个数
# hasattr(X[0], "__len__"):用来判断x列表中的第一个元素是否有长度属性,也就是判断是否为数据
if has_one_axis(X):
X = [X] # 将数组数据类型转变为列表数据类型
if Y is None:
X, Y = [[]] * len(X), X # 默认情况下,赋值给X, Y
elif has_one_axis(Y):
Y = [Y] # 将数组数据类型转变为列表数据类型
if len(X) != len(Y):
X = X * len(Y)
axes.cla() # axiss模块中的Axes.cla()函数用于清除当前轴
for x, y, fmt in zip(X, Y, fmts):
if len(x):
axes.plot(x, y, fmt) # axes.plot用于绘制XY坐标系的点、线或其他标记形状
else:
axes.plot(y, fmt)
set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend) # 设置axes模块的属性
现在我们可以[绘制函数
u
=
f
(
x
)
u=f(x)
u=f(x)及其在
x
=
1
x=1
x=1处的切线
y
=
2
x
−
3
y=2x-3
y=2x−3],
其中系数
2
2
2是切线的斜率。
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
x, [f(x), 2 * x - 3]
C:\Users\Administrator\AppData\Local\Temp\ipykernel_42036\1575940066.py:3: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
display.set_matplotlib_formats('svg')
(array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5,
2.6, 2.7, 2.8, 2.9]),
[array([ 0. , -0.37, -0.68, -0.93, -1.12, -1.25, -1.32, -1.33, -1.28,
-1.17, -1. , -0.77, -0.48, -0.13, 0.28, 0.75, 1.28, 1.87,
2.52, 3.23, 4. , 4.83, 5.72, 6.67, 7.68, 8.75, 9.88,
11.07, 12.32, 13.63]),
array([-3. , -2.8, -2.6, -2.4, -2.2, -2. , -1.8, -1.6, -1.4, -1.2, -1. ,
-0.8, -0.6, -0.4, -0.2, 0. , 0.2, 0.4, 0.6, 0.8, 1. , 1.2,
1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8])])
x, type(x), f(x), type(f(x)), 2 * x + 3, # x, f(x), 2*x + 3: 函数输入、函数输出、函数导数
(hasattr(x, "ndim") and x.ndim == 1 or isinstance(x, list)
and not hasattr(x[0], "__len__"))
x, [x],type([x]), x[0],x[1],hasattr(x[0], "__len__")
x2, y2 = [[]] * len(x), x
Y = [[f(x), 2 * x - 3]]
x = [x]
for x,y in zip([([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5,
2.6, 2.7, 2.8, 2.9]), ([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5,
2.6, 2.7, 2.8, 2.9])],[([ 0. , -0.37, -0.68, -0.93, -1.12, -1.25, -1.32, -1.33, -1.28,
-1.17, -1. , -0.77, -0.48, -0.13, 0.28, 0.75, 1.28, 1.87,
2.52, 3.23, 4. , 4.83, 5.72, 6.67, 7.68, 8.75, 9.88,
11.07, 12.32, 13.63]), ([-3. , -2.8, -2.6, -2.4, -2.2, -2. , -1.8, -1.6, -1.4, -1.2, -1. ,
-0.8, -0.6, -0.4, -0.2, 0. , 0.2, 0.4, 0.6, 0.8, 1. , 1.2,
1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8])]):
print(x,y) # 进行分组
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9] [0.0, -0.37, -0.68, -0.93, -1.12, -1.25, -1.32, -1.33, -1.28, -1.17, -1.0, -0.77, -0.48, -0.13, 0.28, 0.75, 1.28, 1.87, 2.52, 3.23, 4.0, 4.83, 5.72, 6.67, 7.68, 8.75, 9.88, 11.07, 12.32, 13.63]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9] [-3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8]
偏导数
到目前为止,我们只讨论了仅含一个变量的函数的微分。
在深度学习中,函数通常依赖于许多变量。
因此,我们需要将微分的思想推广到多元函数(multivariate function)上。
设
y
=
f
(
x
1
,
x
2
,
…
,
x
n
)
y = f(x_1, x_2, \ldots, x_n)
y=f(x1,x2,…,xn)是一个具有
n
n
n个变量的函数。
y
y
y关于第
i
i
i个参数
x
i
x_i
xi的偏导数(partial derivative)为:
∂ 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 \rightarrow 0} \frac{f(x_1, \ldots, x_{i-1}, x_i+h, x_{i+1}, \ldots, x_n) - f(x_1, \ldots, x_i, \ldots, x_n)}{h}. ∂xi∂y=h→0limhf(x1,…,xi−1,xi+h,xi+1,…,xn)−f(x1,…,xi,…,xn).
为了计算
∂
y
∂
x
i
\frac{\partial y}{\partial x_i}
∂xi∂y,
我们可以简单地将
x
1
,
…
,
x
i
−
1
,
x
i
+
1
,
…
,
x
n
x_1, \ldots, x_{i-1}, x_{i+1}, \ldots, x_n
x1,…,xi−1,xi+1,…,xn看作常数,
并计算
y
y
y关于
x
i
x_i
xi的导数。
对于偏导数的表示,以下是等价的:
∂ y ∂ x i = ∂ f ∂ x i = f x i = f i = D i f = D x i f . \frac{\partial y}{\partial x_i} = \frac{\partial f}{\partial x_i} = f_{x_i} = f_i = D_i f = D_{x_i} f. ∂xi∂y=∂xi∂f=fxi=fi=Dif=Dxif.
梯度
🏷subsec_calculus-grad
我们可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度(gradient)向量。
具体而言,设函数
f
:
R
n
→
R
f:\mathbb{R}^n\rightarrow\mathbb{R}
f:Rn→R的输入是
一个
n
n
n维向量
x
=
[
x
1
,
x
2
,
…
,
x
n
]
⊤
\mathbf{x}=[x_1,x_2,\ldots,x_n]^\top
x=[x1,x2,…,xn]⊤,并且输出是一个标量。
函数
f
(
x
)
f(\mathbf{x})
f(x)相对于
x
\mathbf{x}
x的梯度是一个包含
n
n
n个偏导数的向量:
∇ x f ( x ) = [ ∂ f ( x ) ∂ x 1 , ∂ f ( x ) ∂ x 2 , … , ∂ f ( x ) ∂ x n ] ⊤ , \nabla_{\mathbf{x}} f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_n}\bigg]^\top, ∇xf(x)=[∂x1∂f(x),∂x2∂f(x),…,∂xn∂f(x)]⊤,
其中 ∇ x f ( x ) \nabla_{\mathbf{x}} f(\mathbf{x}) ∇xf(x)通常在没有歧义时被 ∇ f ( x ) \nabla f(\mathbf{x}) ∇f(x)取代。
假设 x \mathbf{x} x为 n n n维向量,在微分多元函数时经常使用以下规则:
- 对于所有 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rm×n,都有 ∇ x A x = A ⊤ \nabla_{\mathbf{x}} \mathbf{A} \mathbf{x} = \mathbf{A}^\top ∇xAx=A⊤
- 对于所有 A ∈ R n × m \mathbf{A} \in \mathbb{R}^{n \times m} A∈Rn×m,都有 ∇ x x ⊤ A = A \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} = \mathbf{A} ∇xx⊤A=A
- 对于所有 A ∈ R n × n \mathbf{A} \in \mathbb{R}^{n \times n} A∈Rn×n,都有 ∇ x x ⊤ A x = ( A + A ⊤ ) x \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} \mathbf{x} = (\mathbf{A} + \mathbf{A}^\top)\mathbf{x} ∇xx⊤Ax=(A+A⊤)x
- ∇ x ∥ x ∥ 2 = ∇ x x ⊤ x = 2 x \nabla_{\mathbf{x}} \|\mathbf{x} \|^2 = \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{x} = 2\mathbf{x} ∇x∥x∥2=∇xx⊤x=2x
同样,对于任何矩阵
X
\mathbf{X}
X,都有
∇
X
∥
X
∥
F
2
=
2
X
\nabla_{\mathbf{X}} \|\mathbf{X} \|_F^2 = 2\mathbf{X}
∇X∥X∥F2=2X。
正如我们之后将看到的,梯度对于设计深度学习中的优化算法有很大用处。
链式法则
然而,上面方法可能很难找到梯度。
这是因为在深度学习中,多元函数通常是复合(composite)的,
所以我们可能没法应用上述任何规则来微分这些函数。
幸运的是,链式法则使我们能够微分复合函数。
让我们先考虑单变量函数。假设函数 y = f ( u ) y=f(u) y=f(u)和 u = g ( x ) u=g(x) u=g(x)都是可微的,根据链式法则:
d y d x = d y d u d u d x . \frac{dy}{dx} = \frac{dy}{du} \frac{du}{dx}. dxdy=dudydxdu.
现在让我们把注意力转向一个更一般的场景,即函数具有任意数量的变量的情况。
假设可微分函数
y
y
y有变量
u
1
,
u
2
,
…
,
u
m
u_1, u_2, \ldots, u_m
u1,u2,…,um,其中每个可微分函数
u
i
u_i
ui都有变量
x
1
,
x
2
,
…
,
x
n
x_1, x_2, \ldots, x_n
x1,x2,…,xn。
注意,
y
y
y是
x
1
,
x
2
,
…
,
x
n
x_1, x_2, \ldots, x_n
x1,x2,…,xn的函数。
对于任意
i
=
1
,
2
,
…
,
n
i = 1, 2, \ldots, n
i=1,2,…,n,链式法则给出:
d y d x i = d y d u 1 d u 1 d x i + d y d u 2 d u 2 d x i + ⋯ + d y d u m d u m d x i \frac{dy}{dx_i} = \frac{dy}{du_1} \frac{du_1}{dx_i} + \frac{dy}{du_2} \frac{du_2}{dx_i} + \cdots + \frac{dy}{du_m} \frac{du_m}{dx_i} dxidy=du1dydxidu1+du2dydxidu2+⋯+dumdydxidum
小结
- 微分和积分是微积分的两个分支,前者可以应用于深度学习中的优化问题。
- 导数可以被解释为函数相对于其变量的瞬时变化率,它也是函数曲线的切线的斜率。
- 梯度是一个向量,其分量是多变量函数相对于其所有变量的偏导数。
- 链式法则使我们能够微分复合函数。
练习
- 绘制函数 y = f ( x ) = x 3 − 1 x y = f(x) = x^3 - \frac{1}{x} y=f(x)=x3−x1和其在 x = 1 x = 1 x=1处切线的图像。
- 求函数 f ( x ) = 3 x 1 2 + 5 e x 2 f(\mathbf{x}) = 3x_1^2 + 5e^{x_2} f(x)=3x12+5ex2的梯度。
- 函数 f ( x ) = ∥ x ∥ 2 f(\mathbf{x}) = \|\mathbf{x}\|_2 f(x)=∥x∥2的梯度是什么?
- 你可以写出函数 u = f ( x , y , z ) u = f(x, y, z) u=f(x,y,z),其中 x = x ( a , b ) x = x(a, b) x=x(a,b), y = y ( a , b ) y = y(a, b) y=y(a,b), z = z ( a , b ) z = z(a, b) z=z(a,b)的链式法则吗?
# 练习一
def f(x): # 定义函数
return x * x * x - 1 / x
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)}')
h *= 0.1
h=0.10000,numerical limit=4.219090909090913
h=0.01000,numerical limit=4.020199009900981
h=0.00100,numerical limit=4.002001999000359
h=0.00010,numerical limit=4.000200019997901
h=0.00001,numerical limit=4.000020000216596
x = np.arange(0.5, 1.5, 0.1)
plot(x, [f(x), 4*x - 4], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
C:\Users\Administrator\AppData\Local\Temp\ipykernel_42036\1575940066.py:3: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
display.set_matplotlib_formats('svg')
# 练习2
# f(x)对x1求导为: 6 * x1
# f(x)对x2求导为:5 * e^(x2)
# 梯度为:[6*x1, 5*e^(x2)]
# 练习3
# 梯度为: X/||X||2
# 练习4
# 链式法则:
# f`(a) = f`(x) * x`a + f`(y) * y`a + f`(z) * z`a
# f`(b) = f`(x) * x`b + f`(y) * y`b + f`(z) * z`b