2. 预备知识
2.1 数据操作
2.1.1 相同维度张量的操作
import torch # 引入PyTorch
# 以默认步长1,创建行向量。默认存储在内存中并使用CPU计算
x = torch.arange(6) # tensor([0, 1, 2, 3, 4, 5])
# 张量的形状
x.shape # torch.Size([6])
# 张量的元素数
x.numel() # 6
# 将张量形状转化为(2,3)。可指定任一维度后,另一维度将自动计算,该功能采用-1调用。如x.reshape(-1,3)或x.reshape(2,-1)来取代。
X = x.reshape((2,3)) # 注意,转化形状时元素数量必须等于各轴数乘积
"""
tensor([[0, 1, 2],
[3, 4, 5]])
"""
# 创建维度为(2,3)的全0/1张量
torch.zeros((2, 3))
"""
tensor([[0., 0., 0.],
[0., 0., 0.]])
"""
torch.ones((2, 3))
torch.zeros_like(Y) # 返回与张量Y大小相同但元素均为0的张量
# 创建(2,2)的张量。其中每个元素都从均值为0、标准差为1的标准正态分布中随机采样。
torch.rand((2,2))
"""
tensor([[0.1671, 0.8407],
[0.0690, 0.6150]])
"""
# 通过给定数值创建张量
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4]])
"""
tensor([[2, 1, 4, 3],
[1, 2, 3, 4]])
"""
# 相同形状张量按元素计算
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # 除0将置为Nan而不会出错
torch.exp(x) # 对每个元素求e^x
# 根据指定维度将两个张量连接
X = torch.arange(0,12).reshape(3,4)
Y = torch.arange(12,24).reshape(3,4)
torch.cat((X,Y),dim=0) # 第一个维度拼接
torch.cat((X,Y),dim=1) # 第二个维度拼接
"""
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
tensor([[ 0, 1, 2, 3, 12, 13, 14, 15],
[ 4, 5, 6, 7, 16, 17, 18, 19],
[ 8, 9, 10, 11, 20, 21, 22, 23]])
"""
# 比较张量中每个元素是否相等
X == Y
"""
tensor([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])
"""
# 对张量中的所有元素进行求和
X.sum() # tensor(66)
# 张量支持切片和索引操作
x[-1]
x[0:2, 3:4]
# 将Torch转化为Numpy
A = X.numpy()
B = torch.tensor(A)
type(A), type(B) # (numpy.ndarray, torch.Tensor)
# 大小为1的张量转化为Python标量
a = torch.tensor([3.5])
float(a), int(a) # (3.5, 3)
2.1.2 广播机制与切片
形状不同的张量可调用广播机制执行按元素操作。首先,其自动复制元素让两个张量具有相同的形状。其次,对生成的数组执行按元素操作。如下例子:
a = torch.arange(3).reshape(3, 1)
b = torch.arange(2).reshape(1, 2)
a + b
"""
0 0 0 1
1 1 + 0 1
2 2 0 1
tensor([[0, 1],
[1, 2],
[2, 3]])
"""
原则是一方的长度为1,或者它们的后缘维度(从末尾开始算起)相同。如a的维度为(2,3,4),当b的维度是(3,4)时可拼接,但为(2,4)时不可。
2.2 pandas数据预处理
import os
import pandas as pd
import torch
# csv是逗号分隔符文件,以纯文本形式保存,可用记事本打开
data_file = 'C:\\Users\\zpf\\Desktop\\house_tiny.csv'
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')
data = pd.read_csv(data_file)
print(data)
"""
NumRooms Alley Price
0 NaN Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 NaN NaN 140000
"""
# 处理缺失值的方法包括插值法和删除法。下面展示插值法
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)
"""
NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN
"""
# 对于离散值,将“NaN”视为一个类别。 由于“Alley”只接受两种类型“Pave”和“NaN”, pandas可自动将此列转换为两列“Alley_Pave”和“Alley_nan”。
inputs = pd.get_dummies(inputs, dummy_na=True) # dummiey仿制品
print(inputs)
"""
NumRooms Alley_Pave Alley_nan
0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1
"""
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
"""
(tensor([[3., 1., 0.],
[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64),
tensor([127500, 106000, 178100, 140000]))
"""
2.3 线性代数
本文中 向量或轴的维度表示向量或轴的长度,张量的维度表示张量具有的轴数。
标量:仅包含一个元素。
向量:标量值组成的列表,使用x∈Rn表示向量x。向量的长度称为向量的维度(dimension),len(x)
。列向量是向量的默认方向,python中也是如此,向量x写为:
矩阵:使用A∈Rm×n表示矩阵A。可以通过指定两个分量m和n来创建形状为m×n的矩阵,如torch.arange(20).reshape(5, 4)
。
矩阵的转置:即交换矩阵的行和列。访问矩阵的转置为A.T
。
对称矩阵:A=A⊤,是一种特殊的方阵。使用A == A.T
检验一个方阵是否为对称矩阵。
A * B # 按元素相乘。两个矩阵的按元素乘法称为*Hadamard积*(数学符号⊙)。
a + A # 张量中所有元素均与a相加,张量形状不变
a * A # 张量中所有元素均与a相乘,张量形状不变
# 轴数发生变化的求和方式(降维求和)
A.sum() # 对张量所有元素求和,结果为标量
A.sum(axis=0) # 求和所有列
A.sum(axis=1) # 求和所有行
A.sum(axis=[0,1]) # 按行与列求和
A.mean(), A.sum() / A.numel() # 求张量均值
A.mean(axis=0), A.sum(axis=0) / A.shape[0] # 按某维度求张量均值
# 轴数固定的求和方式
sum_A = A.sum(axis=1, keepdims=True)
A / sum_A # 由于`sum_A`在对每行求和后仍保持两个轴,可以通过广播将`A`除以`sum_A`。
A.cumsum(axis=0) # 计算累积总和
向量x和y的点积(dot product)x⊤y(或<x,y>)是相同位置的按元素乘积的和:
torch.dot(x, y)
# 等价于
torch.sum(x * y)
现有矩阵A∈Rm×n和向量x∈Rn。我们将矩阵A用它的行向量表示:
其中的每个元素都是行向量。矩阵向量积Ax是一个长度为m的列向量:
这就是矩阵的向量积。可以将向量x实现从Rn到Rm的转换。例如,我们可以用方阵的乘法来表示旋转。PyTorch用mv函数来实现两个矩阵的向量积。
A.shape, x.shape, torch.mv(A, x) # 注意A的列维数必须与x的维数(长度)相同。
# torch.Size([5, 4]), torch.Size([4])
矩阵乘法结果的每个元素是对应行与列元素相乘之和,矩阵A的列要和矩阵B的行数量相同。如:A
是一个5行4列的矩阵,B
是一个4行3列的矩阵。 两者相乘后得到一个5行3列的矩阵。
torch.mm(a,b)
范数(norm):向量大小的一种度量,是将向量映射到标量的函数f。 给定任意向量x,向量范数要满足一些属性。
- 齐次性:
%3D%7C%5Calpha%7C%20f(%5Cmathbf%7Bx%7D)#card=math&code=f%28%5Calpha%20%5Cmathbf%7Bx%7D%29%3D%7C%5Calpha%7C%20f%28%5Cmathbf%7Bx%7D%29&id=oNNZJ)
- 三角不等式:
%20%5Cleq%20f(%5Cmathbf%7Bx%7D)%2Bf(%5Cmathbf%7By%7D)#card=math&code=f%28%5Cmathbf%7Bx%7D%2B%5Cmathbf%7By%7D%29%20%5Cleq%20f%28%5Cmathbf%7Bx%7D%29%2Bf%28%5Cmathbf%7By%7D%29&id=MGHWm)
- 正定性:
%E2%89%A50#card=math&code=f%28%5Cmathbf%7Bx%7D%29%E2%89%A50&id=SCgJc),当且仅当向量全由0组成等号成立
范数:
%5E%7B1%20%2F%20p%7D#card=math&code=%5C%7C%5Cmathbf%7Bx%7D%5C%7C%7Bp%7D%3D%5Cleft%28%5Csum%7Bi%3D1%7D%5E%7Bn%7D%5Cleft%7Cx_%7Bi%7D%5Cright%7C%5E%7Bp%7D%5Cright%29%5E%7B1%20%2F%20p%7D&id=VLD3X),在深度学习中经常使用L2范数的平方或L1范数。
u = torch.tensor([3.0, -4.0])
torch.norm(u) # 计算L2范数
# tensor(5.)
torch.abs(u).sum() # 计算L1范数
# tensor(7.)
类似于向量的L2范数,矩阵X∈Rm×n的Frobenius范数(Frobenius norm)是矩阵元素平方和的平方根:。
torch.norm(torch.ones((2, 3))) # 计算矩阵的Frobenius范数
# tensor(2.4495)
2.4 微积分
深度学习中通常选择对于模型参数可微的损失函数。即如果把参数增加或减少一个无穷小的量,就可以知道损失会以多快的速度增加或减少。如果在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的。导数反映了函数在某一点的瞬时变化率。函数导数的以下表达式是等价的:
%3Dy%5E%7B%5Cprime%7D%3D%5Cfrac%7Bd%20y%7D%7Bd%20x%7D%3D%5Cfrac%7Bd%20f%7D%7Bd%20x%7D%3D%5Cfrac%7Bd%7D%7Bd%20x%7D%20f(x)%3DD%20f(x)%3DD%7Bx%7D%20f(x)%0A#card=math&code=f%5E%7B%5Cprime%7D%28x%29%3Dy%5E%7B%5Cprime%7D%3D%5Cfrac%7Bd%20y%7D%7Bd%20x%7D%3D%5Cfrac%7Bd%20f%7D%7Bd%20x%7D%3D%5Cfrac%7Bd%7D%7Bd%20x%7D%20f%28x%29%3DD%20f%28x%29%3DD%7Bx%7D%20f%28x%29%0A&id=NLtRI)
常见函数求微分规则:%5C%5C%0A%20D%20x%5E%7Bn%7D%3Dn%20x%5E%7Bn-1%7D%20%20(%E5%B9%82%E5%BE%8B%20(power%20rule)%20%2C%20%20n%20%20%E6%98%AF%E4%BB%BB%E6%84%8F%E5%AE%9E%E6%95%B0)%5C%5C%0A%20D%20e%5E%7Bx%7D%3De%5E%7Bx%7D%5C%5C%0A%20D%20%5Cln%20(x)%3D1%20%2F%20x%20%5C%5C%0A%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf(x)%20g(x)%5D%3Df(x)%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bg(x)%5D%2Bg(x)%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf(x)%5D%5C%5C%0A%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Cleft%5B%5Cfrac%7Bf(x)%7D%7Bg(x)%7D%5Cright%5D%3D%5Cfrac%7Bg(x)%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf(x)%5D-f(x)%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bg(x)%5D%7D%7B%5Bg(x)%5D%5E%7B2%7D%7D%5C%5C%0A#card=math&code=D%20C%3D0%20%20%28%20%20C%20%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%B8%B8%E6%95%B0%29%5C%5C%0A%20D%20x%5E%7Bn%7D%3Dn%20x%5E%7Bn-1%7D%20%20%28%E5%B9%82%E5%BE%8B%20%28power%20rule%29%20%2C%20%20n%20%20%E6%98%AF%E4%BB%BB%E6%84%8F%E5%AE%9E%E6%95%B0%29%5C%5C%0A%20D%20e%5E%7Bx%7D%3De%5E%7Bx%7D%5C%5C%0A%20D%20%5Cln%20%28x%29%3D1%20%2F%20x%20%5C%5C%0A%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf%28x%29%20g%28x%29%5D%3Df%28x%29%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bg%28x%29%5D%2Bg%28x%29%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf%28x%29%5D%5C%5C%0A%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Cleft%5B%5Cfrac%7Bf%28x%29%7D%7Bg%28x%29%7D%5Cright%5D%3D%5Cfrac%7Bg%28x%29%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bf%28x%29%5D-f%28x%29%20%5Cfrac%7Bd%7D%7Bd%20x%7D%5Bg%28x%29%5D%7D%7B%5Bg%28x%29%5D%5E%7B2%7D%7D%5C%5C%0A&id=jsmYh)
在深度学习中,函数通常依赖于许多变量。设 #card=math&code=y%3Df%5Cleft%28x%7B1%7D%2C%20x%7B2%7D%2C%20%5Cldots%2C%20x%7Bn%7D%5Cright%29&id=WDZjd) 是一个具有 n 个变量的函数。
关于第
个参数  的偏导数 (partial derivative) 为:
-f%5Cleft(x%7B1%7D%2C%20%5Cldots%2C%20x%7Bi%7D%2C%20%5Cldots%2C%20x%7Bn%7D%5Cright)%7D%7Bh%7D%0A#card=math&code=%5Cfrac%7B%5Cpartial%20y%7D%7B%5Cpartial%20x%7Bi%7D%7D%3D%5Clim%20%7Bh%20%5Crightarrow%200%7D%20%5Cfrac%7Bf%5Cleft%28x%7B1%7D%2C%20%5Cldots%2C%20x%7Bi-1%7D%2C%20x%7Bi%7D%2Bh%2C%20x%7Bi%2B1%7D%2C%20%5Cldots%2C%20x%7Bn%7D%5Cright%29-f%5Cleft%28x%7B1%7D%2C%20%5Cldots%2C%20x%7Bi%7D%2C%20%5Cldots%2C%20x%7Bn%7D%5Cright%29%7D%7Bh%7D%0A&id=AB0SU)
计算偏导数时通常将除的其他变量看为常数处理。
函数的梯度(gradient):连结多元函数对其所有变量的偏导数。%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D%0A#card=math&code=%5Cnabla%20f%28%5Cmathbf%7Bx%7D%29%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D%0A&id=JGzKu)
假设函数#card=math&code=y%3Df%28u%29&id=sU8kd)和
#card=math&code=u%3Dg%28x%29&id=I2bXL)都是可微的,根据链式法则:
。设可微分函数 y 有变量  , 其中每个可微分函数  都有变量 。对于任意
, 链式法则给出:

2.5 自动微分
深度学习框架会自动计算导数,系统会构建一个计算图跟踪计算。 自动微分使系统能够反向传播梯度,填充关于每个参数的偏导数。
2.5.1 输出标量时的反向传播
对函数关于列向量x求导。(数学公式中向量默认为列向量,因此该式所得结果为标量)
import torch
x = torch.arange(4.0) # tensor([0., 1., 2., 3.])。只有浮点数才能请求梯度
x.requires_grad_(True)
# 等价于x=torch.arange(4.0,requires_grad=True)
一个标量函数关于向量x的梯度是与x具有相同形状的向量。
x.grad # 访问梯度,初始值为None
y = 2 * torch.dot(x, x) # 计算结果
y.backward() # 调用反向传播函数自动计算y关于x每个分量的梯度
x.grad # 访问梯度 tensor([ 0., 4., 8., 12.])
计算过程:
- 表达式:2x12+2x22+2x32+2x42
- 梯度:
%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D#card=math&code=%5Cnabla%20f%28%5Cmathbf%7Bx%7D%29%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D&id=eeFMG)=[4x1,4x2,4x3,4x4]
- 代入x值得:x.grad=[0,4,8,12]
下面计算x的另一个函数:
# 默认情况下会累积梯度,需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad # tensor([1., 1., 1., 1.])
计算过程:
- 表达式:x1+x2+x3+x4
- 梯度:
%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bx%7D)%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D#card=math&code=%5Cnabla%20f%28%5Cmathbf%7Bx%7D%29%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bx%7D%29%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D&id=CnUdQ)=[ 1, 1, 1, 1]
-
2.5.2 输出向量时的反向传播
import torch
a = torch.tensor([[2.,4.]],requires_grad=True) # tensor([[2., 4.]], requires_grad=True)
b = torch.zeros(1,2)
b[0,0]=a[0,0]**2+a[0,1] # tensor([[8., 0.]], grad_fn=<CopySlices>)
b[0,1]=a[0,1]**3+2*a[0,0] # tensor([[ 8., 68.]], grad_fn=<CopySlices>)
y = 2*b # tensor([[ 16., 136.]], grad_fn=<MulBackward0>)
y.backward(torch.tensor([[1,2]])) # 只有a请求了梯度,因此对a求梯度
a.grad # tensor([[ 16., 194.]])) # 所得向量梯度形状与原向量相同
b = [[a02 + a1, a13 + 2a0]] = [[8, 68]]
- y = [[2a02 + 2a1, 2a13 + 4a0]] = [[16, 136]]
%5C%5C%0A%5Cbegin%7Bpmatrix%7D%0A8%20%20%26%204%5C%5C%0A2%20%20%26%2096%0A%5Cend%7Bpmatrix%7D%0A%5Cbegin%7Bpmatrix%7D%0A%201%20%262%0A%5Cend%7Bpmatrix%7D%5E%7BT%7D%20%3D%5Cbegin%7Bpmatrix%7D%0A16%20%5C%5C%0A194%0A%5Cend%7Bpmatrix%7D%3D%5Cbegin%7Bpmatrix%7D%0A%2016%20%26%20194%0A%5Cend%7Bpmatrix%7D%5E%7BT%7D%0A#card=math&code=%5Cleft%28%5Cbegin%7Barray%7D%7Blc%7D%0A%5Cfrac%7B%5Cdelta%20%5Ctext%20%7B%20y%20%7D%7B0%7D%7D%7B%5Cdelta%20a%7B0%7D%7D%3D4%20a%7B0%7D%3D8%20%26%20%5Cfrac%7B%5Cdelta%20%5Ctext%20%7B%20y%20%7D%7B1%7D%7D%7B%5Cdelta%20a%7B0%7D%7D%3D4%20%5C%5C%0A%5Cfrac%7B%5Cdelta%20%5Ctext%20%7B%20y%20%7D%7B0%7D%7D%7B%5Cdelta%20a%7B1%7D%7D%3D2%20%26%20%5Cfrac%7B%5Cdelta%20y%7B1%7D%7D%7B%5Cdelta%20a%7B1%7D%7D%3D6%20a%7B1%7D%5E%7B2%7D%3D96%0A%5Cend%7Barray%7D%5Cright%29%5C%5C%0A%5Cbegin%7Bpmatrix%7D%0A8%20%20%26%204%5C%5C%0A2%20%20%26%2096%0A%5Cend%7Bpmatrix%7D%0A%5Cbegin%7Bpmatrix%7D%0A%201%20%262%0A%5Cend%7Bpmatrix%7D%5E%7BT%7D%20%3D%5Cbegin%7Bpmatrix%7D%0A16%20%5C%5C%0A194%0A%5Cend%7Bpmatrix%7D%3D%5Cbegin%7Bpmatrix%7D%0A%2016%20%26%20194%0A%5Cend%7Bpmatrix%7D%5E%7BT%7D%0A&id=PAj9S)
神经网络中每个out都是由很多输入样本的属性(也就是输入数据)线性或者非线性组合而成的,也就是说【out】中的每个数都可以对【a】中每个数求导,那么backward()的参数[k1,k2,k3….kn]的含义就是:
2.5.3 分离计算
想计算z
关于x
的梯度,且希望将y
视为一个常数。此时可以分离y
来返回一个新变量u
,该变量与y
具有相同的值, 但梯度不会向后流经u
到x
。
x = torch.arange(4.0,requires_grad=True)# 仅浮点型张量可反向传播
y = x * x # tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>)
u = y.detach()
z = u * x # tensor([ 0., 1., 8., 27.], grad_fn=<MulBackward0>)
z.sum().backward()
x.grad # tensor([0., 1., 4., 9.])
计算过程:
- 表达式:y = u = [x12, x22, x32, x42]; z = [x1u1, x2u2, x3u3, x4u4]
- 梯度:
%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bz%7D)%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bz%7D)%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f(%5Cmathbf%7Bz%7D)%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D#card=math&code=%5Cnabla%20f%28%5Cmathbf%7Bz%7D%29%3D%5Cleft%5B%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bz%7D%29%7D%7B%5Cpartial%20x%7B1%7D%7D%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bz%7D%29%7D%7B%5Cpartial%20x%7B2%7D%7D%2C%20%5Cldots%2C%20%5Cfrac%7B%5Cpartial%20f%28%5Cmathbf%7Bz%7D%29%7D%7B%5Cpartial%20x%7Bn%7D%7D%5Cright%5D%5E%7B%5Ctop%7D&id=t3KrF)=[ u1, u2, u3, u4] = = [x12, x22, x32, x42]
- 代入x值得:x.grad=[0, 1, 4, 9]
由于记录了y
的计算结果,随后可在y
上调用反向传播, 得到y=x*x
关于x
的导数,即2*x
。
x.grad.zero_()
y.sum().backward()
x.grad == 2 * x
# tensor([True, True, True, True])
2.5.4. Python控制流的梯度计算
即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度。
def f(a):
b = a * 2
while b.norm() < 1000: # b的绝对值小于1000
b = b * 2
if b.sum() > 0:
c = b
else:
c = 100 * b
return c
# 计算梯度
a = torch.randn(size=(), requires_grad=True) # 生成随机标量
d = f(a)
d.backward()
a.grad # tensor(1024.)
2.5.5 梯度下降法的理解
在损失函数中,权重参数w和偏置b是变量,梯度下降的目标是找到一组让损失更小的权重参数w和偏置b,即零损失结果更小的位置。假设这是一个二次曲线问题,如:%5E%7B2%7D%2B1%0A#card=math&code=y%3D%28x-5%29%5E%7B2%7D%2B1%0A&id=JoxBk)
对参数x的求导指明了当前函数的最大变化方向,我们的最终目标是找到最低点,即。首先获得y关于x的导数:
- 如果当前位于点x=0,那该点的导数值为-10,那么0-(-10)=10
- 如果当前位于点x=3,那该点的导数值为-4,那么3-(-4)=7
- 如果当前位于点x=7,那该点的导数值为4,那么7-4=3
- 如果当前位于点x=10,那该点的导数值为10,那么10-10=0
可以看到,当在左侧时,通过梯度[1]下降的方式总是向右移动;当在
右侧时,通过梯度下降的方式总是向左移动。若给定一个小于1的学习律,x将总是向谷底方向移动。
2.6 概率
2.6.1 基本概率论
大数定律(law of large numbers): 随着实验次数的增加,估计值会越来越接近真实的潜在概率。在投骰子问题中,将集合S={1,2,3,4,5,6}称为样本空间(sample space), 其中每个元素都是结果(outcome)。事件(event)是一组给定样本空间的随机结果。如果一个随机实验的结果在A中,则事件A已经发生。 也就是说,如果投掷出3点,因为3∈{1,3,5},我们可以说,“看到奇数”的事件发生了。
2.6.2 处理多个随机变量
- 联合概率:P(A=a,B=b)表示A=a和B=b同时满足的概率。P(A=a,B=b)≤P(A=a)。
- 条件概率:P(B=b∣A=a)表示在A=a发生的前提下,B=b发生的概率。
- 贝叶斯定理:假设P(B)>0,则P(A∣B)=P(B∣A)P(A)/P(B)。
- 边际化:求和法则(sum rule), 即
%3D%5Csum%7BA%7D%20P(A%2C%20B)#card=math&code=P%28B%29%3D%5Csum%7BA%7D%20P%28A%2C%20B%29&id=wIePU)。边际化结果的概率或分布称为边际概率(marginal probability) 或边际分布(marginal distribution)。
- 独立性:如果两个随机变量A和B是独立的,意味着事件A的发生跟B事件的发生无关,表述为A⊥B。在这种情况下根据贝叶斯定理,P(A∣B)=P(A)。在其他情况下,我们称A和B依赖。两个随机变量是独立的,当且仅当两个随机变量的联合分布是其各自分布的乘积,即P(A,B)=P(A)P(B)。同样地,给定另一个随机变量C时,两个随机变量A和B是条件独立的(conditionally independent), 当且仅当P(A,B∣C)=P(A∣C)P(B∣C)。 这个情况表示为A⊥B∣C。
2.6.3 期望和方差
一个随机变量X的期望(expectation,或平均值(average))表示为#card=math&code=E%5BX%5D%3D%5Csum%7Bx%7D%20x%20P%28X%3Dx%29&id=AKase)
当函数f(x)的输入是从分布P中抽取的随机变量时,f(x)的期望值为%5D%3D%5Csum%7Bx%7D%20f(x)%20P(x)#card=math&code=E%7Bx%20%5Csim%20P%7D%5Bf%28x%29%5D%3D%5Csum%7Bx%7D%20f%28x%29%20P%28x%29&id=pTAdC)
随机变量X与其期望值的偏置由方差来实现:%5E%7B2%7D%5Cright%5D%3DE%5Cleft%5BX%5E%7B2%7D%5Cright%5D-E%5BX%5D%5E%7B2%7D#card=math&code=%5Coperatorname%7BVar%7D%5BX%5D%3DE%5Cleft%5B%28X-E%5BX%5D%29%5E%7B2%7D%5Cright%5D%3DE%5Cleft%5BX%5E%7B2%7D%5Cright%5D-E%5BX%5D%5E%7B2%7D&id=HvdBt)
方差的平方根被称为标准差_(standard deviation)。 随机变量函数的方差衡量的是:当从该随机变量分布中采样不同值x时, 函数值偏离该函数的期望的程度:%5D%3DE%5Cleft%5B(f(x)-E%5Bf(x)%5D)%5E%7B2%7D%5Cright%5D#card=math&code=%5Coperatorname%7BVar%7D%5Bf%28x%29%5D%3DE%5Cleft%5B%28f%28x%29-E%5Bf%28x%29%5D%29%5E%7B2%7D%5Cright%5D&id=P9pqd)
- 梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向 ↩︎