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转化为NumpyA = 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 11 1 + 0 12 2 0 1tensor([[0, 1],[1, 2],[2, 3]])"""
原则是一方的长度为1,或者它们的后缘维度(从末尾开始算起)相同。如a的维度为(2,3,4),当b的维度是(3,4)时可拼接,但为(2,4)时不可。
2.2 pandas数据预处理
import osimport pandas as pdimport 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 Price0 NaN Pave 1275001 2.0 NaN 1060002 4.0 NaN 1781003 NaN NaN 140000"""# 处理缺失值的方法包括插值法和删除法。下面展示插值法inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]inputs = inputs.fillna(inputs.mean())print(inputs)"""NumRooms Alley0 3.0 Pave1 2.0 NaN2 4.0 NaN3 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_nan0 3.0 1 01 2.0 0 12 4.0 0 13 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 torchx = 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 # 访问梯度,初始值为Noney = 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 torcha = 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 * 2while b.norm() < 1000: # b的绝对值小于1000b = b * 2if b.sum() > 0:c = belse:c = 100 * breturn 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)
- 梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向 ↩︎
