1 微积分
1.1 导数和微分
略
1.2 偏导数
略
1.3 梯度(gradient)
1.3.1 定义
对于一个多变量函数 f ( x 1 , x 2 , … , x n ) f\left(x_{1}, x_{2}, \ldots, x_{n}\right) f(x1,x2,…,xn)其中点 a = ( a 1 , a 2 , … , a n ) \mathbf{a}=(a_1,a_2,\ldots,a_n) a=(a1,a2,…,an) 处的梯度是一个向量,通常表示为 ∇ f ( a ) / grad f ( a ) \nabla f(\mathbf{a})/\operatorname{grad}f(\mathbf{a}) ∇f(a)/gradf(a)这个向量的各个分量是函数关于各个变量的偏导数,即: ∇ f ( a ) = ( ∂ f ∂ x 1 ( a ) , ∂ f ∂ x 2 ( a ) , … , ∂ f ∂ x n ( a ) ) \nabla f(\mathbf{a})=\left(\frac{\partial f}{\partial x_1}(\mathbf{a}),\frac{\partial f}{\partial x_2}(\mathbf{a}),\ldots,\frac{\partial f}{\partial x_n}(\mathbf{a})\right) ∇f(a)=(∂x1∂f(a),∂x2∂f(a),…,∂xn∂f(a))
1.3.2 梯度的意义
- 方向:梯度的方向指出了函数在该点处增长最快的方向。
- 大小:梯度的大小(或模长)表示了函数在该方向上的最大增长速率。
- 垂直性:梯度的方向与等值线(或等值面)垂直。
1.3.3 示例
假设我们有一个二维函数
f
(
x
,
y
)
=
x
2
+
y
2
f(x,y)=x^2+y^2
f(x,y)=x2+y2
计算梯度:
因此梯度为:
∇
f
(
x
,
y
)
=
(
2
x
,
2
y
)
\nabla f(x,y)=(2x,2y)
∇f(x,y)=(2x,2y)
解释梯度:
1.3.4 应用
- 优化算法:在机器学习和深度学习中,梯度下降算法利用梯度的方向来寻找函数的局部最小值。
- 图像处理:梯度可以用来检测图像中的边缘。
- 物理学:梯度可以用来描述物理场的变化率,例如电势的梯度给出电场强度。
1.4 链式法则
略
2 自动微分
深度学习框架通过自动计算导数,即自动微分(automatic differentiation)来加快求导。 实际中,根据设计好的模型,系统会构建一个计算图(computational graph), 来跟踪计算是哪些数据通过哪些操作组合起来产生输出。 自动微分使系统能够随后反向传播梯度。 这里,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。
2.1 简单梯度计算示例
假设X是列向量[0,1,2,3],我们想对函数 y = 2 x ⊤ x y=2\mathbf{x}^{\top}\mathbf{x} y=2x⊤x关于列向量X求导。首先,我们创建变量x并为其分配一个初始值。
2.1.1 手算
梯度为列向量[ 0., 4., 8., 12.]
2.1.2 代码计算
PS: 在计算前,需要一个地方来存储梯度,且不会在每次对一个参数求导时都分配新的内存,因为我们经常会成千上万次地更新相同的参数,每次都分配新的内存可能很快就会将内存耗尽
import torch
# 创建一个张量,并通过设置requires_grad属性来让PyTorch自动追踪所有涉及该张量的计算操作
# 即计算得到的梯度会保存到x.grad中
x = torch.arange(4.0,requires_grad=True)
print("x: ",x)
print("grad: ",x.grad)
y=2*torch.dot(x,x)
print("y: ",y)
# 调用反向传播函数来自动计算y关于x每个分量的梯度
y.backward()
# 打印梯度
print("grad: ",x.grad)
# result
'''
x: tensor([0., 1., 2., 3.], requires_grad=True)
grad: None
y: tensor(28., grad_fn=<MulBackward0>)
grad: tensor([ 0., 4., 8., 12.])
'''
2.2 非标量变量的反向传播
在深度学习中,神经网络的最后一层可能会输出多个向量或矩阵,而不是单一的标量值。例如,在多标签分类任务中,输出层可能会产生一个向量,其中每个元素对应一个类别的预测概率。
假设有一个向量y,由向量x通过线性变换得到:
y
=
W
x
+
b
\mathbf{y}=\mathbf{Wx}+\mathbf{b}
y=Wx+b
x是输入向量,W是权重矩阵,b是偏置向量,y是输出向量
假设:
import torch
# 定义变量
x = torch.tensor([1.0, 2.0], requires_grad=True)
W = torch.tensor([[2.0, 3.0], [4.0, 5.0]])
b = torch.tensor([1.0, 1.0])
target = torch.tensor([5.0, 10.0]) # 目标向量
# 计算输出向量 y
y = torch.mm(W, x.unsqueeze(-1)).squeeze() + b
# 定义损失函数
loss = (y - target).pow(2).sum()
# 计算梯度
loss.backward()
# 输出梯度
print("Gradient of x: ", x.grad)
2.3 分离计算
指的是使用.detach()
方法来分离一个张量的计算历史,使其不再参与自动梯度计算。
例如,假设y是作为x的函数计算的,而z则是作为y和x的函数计算的,我们想计算z关于x的梯度,但由于某种原因,希望将y视为一个常数, 并且只考虑到x在y被计算后发挥的作用。
import torch
x = torch.tensor([1.0, 2.0], requires_grad=True)
y = 2 * x + 1
# 将 y 视为常数,分离计算
y_detached = y.detach()
# 计算 z
z = y_detached + x
# 计算梯度
z.backward(torch.tensor([1.0, 1.0]))
print("Gradient of x: ", x.grad)