2. 预备知识

2.1 数据操作

2.1.1 相同维度张量的操作

  1. import torch # 引入PyTorch
  2. # 以默认步长1,创建行向量。默认存储在内存中并使用CPU计算
  3. x = torch.arange(6) # tensor([0, 1, 2, 3, 4, 5])
  4. # 张量的形状
  5. x.shape # torch.Size([6])
  6. # 张量的元素数
  7. x.numel() # 6
  8. # 将张量形状转化为(2,3)。可指定任一维度后,另一维度将自动计算,该功能采用-1调用。如x.reshape(-1,3)或x.reshape(2,-1)来取代。
  9. X = x.reshape((2,3)) # 注意,转化形状时元素数量必须等于各轴数乘积
  10. """
  11. tensor([[0, 1, 2],
  12. [3, 4, 5]])
  13. """
  14. # 创建维度为(2,3)的全0/1张量
  15. torch.zeros((2, 3))
  16. """
  17. tensor([[0., 0., 0.],
  18. [0., 0., 0.]])
  19. """
  20. torch.ones((2, 3))
  21. torch.zeros_like(Y) # 返回与张量Y大小相同但元素均为0的张量
  22. # 创建(2,2)的张量。其中每个元素都从均值为0、标准差为1的标准正态分布中随机采样。
  23. torch.rand((2,2))
  24. """
  25. tensor([[0.1671, 0.8407],
  26. [0.0690, 0.6150]])
  27. """
  28. # 通过给定数值创建张量
  29. torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4]])
  30. """
  31. tensor([[2, 1, 4, 3],
  32. [1, 2, 3, 4]])
  33. """
  34. # 相同形状张量按元素计算
  35. x = torch.tensor([1.0, 2, 4, 8])
  36. y = torch.tensor([2, 2, 2, 2])
  37. x + y, x - y, x * y, x / y, x ** y # 除0将置为Nan而不会出错
  38. torch.exp(x) # 对每个元素求e^x
  39. # 根据指定维度将两个张量连接
  40. X = torch.arange(0,12).reshape(3,4)
  41. Y = torch.arange(12,24).reshape(3,4)
  42. torch.cat((X,Y),dim=0) # 第一个维度拼接
  43. torch.cat((X,Y),dim=1) # 第二个维度拼接
  44. """
  45. tensor([[ 0, 1, 2, 3],
  46. [ 4, 5, 6, 7],
  47. [ 8, 9, 10, 11],
  48. [12, 13, 14, 15],
  49. [16, 17, 18, 19],
  50. [20, 21, 22, 23]])
  51. tensor([[ 0, 1, 2, 3, 12, 13, 14, 15],
  52. [ 4, 5, 6, 7, 16, 17, 18, 19],
  53. [ 8, 9, 10, 11, 20, 21, 22, 23]])
  54. """
  55. # 比较张量中每个元素是否相等
  56. X == Y
  57. """
  58. tensor([[False, True, False, True],
  59. [False, False, False, False],
  60. [False, False, False, False]])
  61. """
  62. # 对张量中的所有元素进行求和
  63. X.sum() # tensor(66)
  64. # 张量支持切片和索引操作
  65. x[-1]
  66. x[0:2, 3:4]
  67. # 将Torch转化为Numpy
  68. A = X.numpy()
  69. B = torch.tensor(A)
  70. type(A), type(B) # (numpy.ndarray, torch.Tensor)
  71. # 大小为1的张量转化为Python标量
  72. a = torch.tensor([3.5])
  73. float(a), int(a) # (3.5, 3)

2.1.2 广播机制与切片

形状不同的张量可调用广播机制执行按元素操作。首先,其自动复制元素让两个张量具有相同的形状。其次,对生成的数组执行按元素操作。如下例子:

  1. a = torch.arange(3).reshape(3, 1)
  2. b = torch.arange(2).reshape(1, 2)
  3. a + b
  4. """
  5. 0 0 0 1
  6. 1 1 + 0 1
  7. 2 2 0 1
  8. tensor([[0, 1],
  9. [1, 2],
  10. [2, 3]])
  11. """

原则是一方的长度为1,或者它们的后缘维度(从末尾开始算起)相同。如a的维度为(2,3,4),当b的维度是(3,4)时可拼接,但为(2,4)时不可。

2.2 pandas数据预处理

  1. import os
  2. import pandas as pd
  3. import torch
  4. # csv是逗号分隔符文件,以纯文本形式保存,可用记事本打开
  5. data_file = 'C:\\Users\\zpf\\Desktop\\house_tiny.csv'
  6. with open(data_file, 'w') as f:
  7. f.write('NumRooms,Alley,Price\n') # 列名
  8. f.write('NA,Pave,127500\n') # 每行表示一个数据样本
  9. f.write('2,NA,106000\n')
  10. f.write('4,NA,178100\n')
  11. f.write('NA,NA,140000\n')
  12. data = pd.read_csv(data_file)
  13. print(data)
  14. """
  15. NumRooms Alley Price
  16. 0 NaN Pave 127500
  17. 1 2.0 NaN 106000
  18. 2 4.0 NaN 178100
  19. 3 NaN NaN 140000
  20. """
  21. # 处理缺失值的方法包括插值法和删除法。下面展示插值法
  22. inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
  23. inputs = inputs.fillna(inputs.mean())
  24. print(inputs)
  25. """
  26. NumRooms Alley
  27. 0 3.0 Pave
  28. 1 2.0 NaN
  29. 2 4.0 NaN
  30. 3 3.0 NaN
  31. """
  32. # 对于离散值,将“NaN”视为一个类别。 由于“Alley”只接受两种类型“Pave”和“NaN”, pandas可自动将此列转换为两列“Alley_Pave”和“Alley_nan”。
  33. inputs = pd.get_dummies(inputs, dummy_na=True) # dummiey仿制品
  34. print(inputs)
  35. """
  36. NumRooms Alley_Pave Alley_nan
  37. 0 3.0 1 0
  38. 1 2.0 0 1
  39. 2 4.0 0 1
  40. 3 3.0 0 1
  41. """
  42. X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
  43. X, y
  44. """
  45. (tensor([[3., 1., 0.],
  46. [2., 0., 1.],
  47. [4., 0., 1.],
  48. [3., 0., 1.]], dtype=torch.float64),
  49. tensor([127500, 106000, 178100, 140000]))
  50. """

2.3 线性代数

本文中 向量的维度表示向量的长度,张量的维度表示张量具有的轴数。

标量:仅包含一个元素。
向量:标量值组成的列表,使用x∈Rn表示向量x。向量的长度称为向量的维度(dimension),len(x)。列向量是向量的默认方向,python中也是如此,向量x写为:
2. 预备知识 - 图1

矩阵:使用A∈Rm×n表示矩阵A。可以通过指定两个分量m和n来创建形状为m×n的矩阵,如torch.arange(20).reshape(5, 4)
矩阵的转置:即交换矩阵的行和列。访问矩阵的转置为A.T
对称矩阵A=A⊤,是一种特殊的方阵。使用A == A.T检验一个方阵是否为对称矩阵。

  1. A * B # 按元素相乘。两个矩阵的按元素乘法称为*Hadamard积*(数学符号⊙)。
  2. a + A # 张量中所有元素均与a相加,张量形状不变
  3. a * A # 张量中所有元素均与a相乘,张量形状不变
  4. # 轴数发生变化的求和方式(降维求和)
  5. A.sum() # 对张量所有元素求和,结果为标量
  6. A.sum(axis=0) # 求和所有列
  7. A.sum(axis=1) # 求和所有行
  8. A.sum(axis=[0,1]) # 按行与列求和
  9. A.mean(), A.sum() / A.numel() # 求张量均值
  10. A.mean(axis=0), A.sum(axis=0) / A.shape[0] # 按某维度求张量均值
  11. # 轴数固定的求和方式
  12. sum_A = A.sum(axis=1, keepdims=True)
  13. A / sum_A # 由于`sum_A`在对每行求和后仍保持两个轴,可以通过广播将`A`除以`sum_A`。
  14. A.cumsum(axis=0) # 计算累积总和

向量xy的点积(dot product)xy(或<x,y>)是相同位置的按元素乘积的和:

  1. torch.dot(x, y)
  2. # 等价于
  3. torch.sum(x * y)

现有矩阵A∈Rm×n和向量x∈Rn。我们将矩阵A用它的行向量表示:
2. 预备知识 - 图2

其中的每个元素都是行向量。矩阵向量积Ax是一个长度为m的列向量:
2. 预备知识 - 图3
这就是矩阵的向量积。可以将向量x实现从Rn到Rm的转换。例如,我们可以用方阵的乘法来表示旋转。PyTorch用mv函数来实现两个矩阵的向量积

  1. A.shape, x.shape, torch.mv(A, x) # 注意A的列维数必须与x的维数(长度)相同。
  2. # torch.Size([5, 4]), torch.Size([4])

矩阵乘法结果的每个元素是对应行与列元素相乘之和,矩阵A的列要和矩阵B的行数量相同。如:A是一个5行4列的矩阵,B是一个4行3列的矩阵。 两者相乘后得到一个5行3列的矩阵。

  1. torch.mm(a,b)

范数(norm):向量大小的一种度量,是将向量映射到标量的函数f。 给定任意向量x,向量范数要满足一些属性。

  1. 齐次性:2. 预备知识 - 图4%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)
  2. 三角不等式:2. 预备知识 - 图5%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)
  3. 正定性:2. 预备知识 - 图6%E2%89%A50#card=math&code=f%28%5Cmathbf%7Bx%7D%29%E2%89%A50&id=SCgJc),当且仅当向量全由0组成等号成立

2. 预备知识 - 图7范数:2. 预备知识 - 图8%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范数。

  1. u = torch.tensor([3.0, -4.0])
  2. torch.norm(u) # 计算L2范数
  3. # tensor(5.)
  4. torch.abs(u).sum() # 计算L1范数 
  5. # tensor(7.)

类似于向量的L2范数,矩阵X∈Rm×n的Frobenius范数(Frobenius norm)是矩阵元素平方和的平方根:2. 预备知识 - 图9

  1. torch.norm(torch.ones((2, 3))) # 计算矩阵的Frobenius范数
  2. # tensor(2.4495)

2.4 微积分

深度学习中通常选择对于模型参数可微的损失函数。即如果把参数增加或减少一个无穷小的量,就可以知道损失会以多快的速度增加或减少。如果2. 预备知识 - 图10在一个区间内的每个数上都是可微的,则此函数在此区间中是可微的。导数反映了函数在某一点的瞬时变化率。函数导数的以下表达式是等价的:
2. 预备知识 - 图11%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)
常见函数求微分规则:
2. 预备知识 - 图12%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)
在深度学习中,函数通常依赖于许多变量。设 2. 预备知识 - 图13#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 个变量的函数。 2. 预备知识 - 图14 关于第 2. 预备知识 - 图15 个参数 ![](https://g.yuque.com/gr/latex?x%7Bi%7D#card=math&code=x%7Bi%7D&id=W3KNI) 的偏导数 (partial derivative) 为:
![](https://g.yuque.com/gr/latex?%5Cfrac%7B%5Cpartial%20y%7D%7B%5Cpartial%20x
%7Bi%7D%7D%3D%5Clim%20%7Bh%20%5Crightarrow%200%7D%20%5Cfrac%7Bf%5Cleft(x%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)-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)
计算偏导数时通常将除![](https://g.yuque.com/gr/latex?x
%7Bi%7D#card=math&code=x%7Bi%7D&id=f4IYP)的其他变量看为常数处理
函数的梯度(gradient):连结多元函数对其所有变量的偏导数。
2. 预备知识 - 图16%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)
假设函数2. 预备知识 - 图17#card=math&code=y%3Df%28u%29&id=sU8kd)和2. 预备知识 - 图18#card=math&code=u%3Dg%28x%29&id=I2bXL)都是可微的,根据链式法则:2. 预备知识 - 图19。设可微分函数 y 有变量 ![](https://g.yuque.com/gr/latex?u
%7B1%7D%2C%20u%7B2%7D%2C%20%5Cldots%2C%20u%7Bm%7D#card=math&code=u%7B1%7D%2C%20u%7B2%7D%2C%20%5Cldots%2C%20u%7Bm%7D&id=UCfNk) , 其中每个可微分函数 ![](https://g.yuque.com/gr/latex?u%7Bi%7D#card=math&code=u%7Bi%7D&id=JbIBW) 都有变量![](https://g.yuque.com/gr/latex?%0Ax%7B1%7D%2C%20x%7B2%7D%2C%20%5Cldots%2C%20x%7Bn%7D#card=math&code=%0Ax%7B1%7D%2C%20x%7B2%7D%2C%20%5Cldots%2C%20x%7Bn%7D&id=WqZAC) 。对于任意 2. 预备知识 - 图20 , 链式法则给出:
![](https://g.yuque.com/gr/latex?%5Cfrac%7Bd%20y%7D%7Bd%20x
%7Bi%7D%7D%3D%5Cfrac%7Bd%20y%7D%7Bd%20u%7B1%7D%7D%20%5Cfrac%7Bd%20u%7B1%7D%7D%7Bd%20x%7Bi%7D%7D%2B%5Cfrac%7Bd%20y%7D%7Bd%20u%7B2%7D%7D%20%5Cfrac%7Bd%20u%7B2%7D%7D%7Bd%20x%7Bi%7D%7D%2B%5Ccdots%2B%5Cfrac%7Bd%20y%7D%7Bd%20u%7Bm%7D%7D%20%5Cfrac%7Bd%20u%7Bm%7D%7D%7Bd%20x%7Bi%7D%7D%0A#card=math&code=%5Cfrac%7Bd%20y%7D%7Bd%20x%7Bi%7D%7D%3D%5Cfrac%7Bd%20y%7D%7Bd%20u%7B1%7D%7D%20%5Cfrac%7Bd%20u%7B1%7D%7D%7Bd%20x%7Bi%7D%7D%2B%5Cfrac%7Bd%20y%7D%7Bd%20u%7B2%7D%7D%20%5Cfrac%7Bd%20u%7B2%7D%7D%7Bd%20x%7Bi%7D%7D%2B%5Ccdots%2B%5Cfrac%7Bd%20y%7D%7Bd%20u%7Bm%7D%7D%20%5Cfrac%7Bd%20u%7Bm%7D%7D%7Bd%20x_%7Bi%7D%7D%0A&id=m0DVd)

2.5 自动微分

深度学习框架会自动计算导数,系统会构建一个计算图跟踪计算。 自动微分使系统能够反向传播梯度,填充关于每个参数的偏导数。

2.5.1 输出标量时的反向传播

对函数2. 预备知识 - 图21关于列向量x求导。(数学公式中向量默认为列向量,因此该式所得结果为标量)

  1. import torch
  2. x = torch.arange(4.0) # tensor([0., 1., 2., 3.])。只有浮点数才能请求梯度
  3. x.requires_grad_(True)
  4. # 等价于x=torch.arange(4.0,requires_grad=True)

一个标量函数关于向量x的梯度是与x具有相同形状的向量。

  1. x.grad # 访问梯度,初始值为None
  2. y = 2 * torch.dot(x, x) # 计算结果
  3. y.backward() # 调用反向传播函数自动计算y关于x每个分量的梯度
  4. x.grad # 访问梯度 tensor([ 0., 4., 8., 12.])

计算过程:

  • 表达式:2x12+2x22+2x32+2x42
  • 梯度:2. 预备知识 - 图22%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的另一个函数:

  1. # 默认情况下会累积梯度,需要清除之前的值
  2. x.grad.zero_()
  3. y = x.sum()
  4. y.backward()
  5. x.grad # tensor([1., 1., 1., 1.])

计算过程:

  • 表达式:x1+x2+x3+x4
  • 梯度:2. 预备知识 - 图23%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]
  • 代入x值得:x.grad=[1, 1, 1, 1]

    2.5.2 输出向量时的反向传播

    1. import torch
    2. a = torch.tensor([[2.,4.]],requires_grad=True) # tensor([[2., 4.]], requires_grad=True)
    3. b = torch.zeros(1,2)
    4. b[0,0]=a[0,0]**2+a[0,1] # tensor([[8., 0.]], grad_fn=<CopySlices>)
    5. b[0,1]=a[0,1]**3+2*a[0,0] # tensor([[ 8., 68.]], grad_fn=<CopySlices>)
    6. y = 2*b # tensor([[ 16., 136.]], grad_fn=<MulBackward0>)
    7. y.backward(torch.tensor([[1,2]])) # 只有a请求了梯度,因此对a求梯度
    8. a.grad # tensor([[ 16., 194.]])) # 所得向量梯度形状与原向量相同
  • b = [[a02 + a1, a13 + 2a0]] = [[8, 68]]

  • y = [[2a02 + 2a1, 2a13 + 4a0]] = [[16, 136]]

2. 预备知识 - 图24%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. 预备知识 - 图25

2.5.3 分离计算

2. 预备知识 - 图26
想计算z关于x的梯度,且希望将y视为一个常数。此时可以分离y来返回一个新变量u,该变量与y具有相同的值, 但梯度不会向后流经ux

  1. x = torch.arange(4.0,requires_grad=True)# 仅浮点型张量可反向传播
  2. y = x * x # tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>)
  3. u = y.detach()
  4. z = u * x # tensor([ 0., 1., 8., 27.], grad_fn=<MulBackward0>)
  5. z.sum().backward()
  6. x.grad # tensor([0., 1., 4., 9.])

计算过程

  • 表达式:y = u = [x12, x22, x32, x42]; z = [x1u1, x2u2, x3u3, x4u4]
  • 梯度:2. 预备知识 - 图27%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

  1. x.grad.zero_()
  2. y.sum().backward()
  3. x.grad == 2 * x
  4. # tensor([True, True, True, True])

2.5.4. Python控制流的梯度计算

即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度。

  1. def f(a):
  2. b = a * 2
  3. while b.norm() < 1000: # b的绝对值小于1000
  4. b = b * 2
  5. if b.sum() > 0:
  6. c = b
  7. else:
  8. c = 100 * b
  9. return c
  10. # 计算梯度
  11. a = torch.randn(size=(), requires_grad=True) # 生成随机标量
  12. d = f(a)
  13. d.backward()
  14. a.grad # tensor(1024.)

2.5.5 梯度下降法的理解

在损失函数中,权重参数w和偏置b是变量,梯度下降的目标是找到一组让损失更小的权重参数w和偏置b,即零损失结果更小的位置。假设这是一个二次曲线问题,如:
2. 预备知识 - 图28%5E%7B2%7D%2B1%0A#card=math&code=y%3D%28x-5%29%5E%7B2%7D%2B1%0A&id=JoxBk)
对参数x的求导指明了当前函数的最大变化方向,我们的最终目标是找到最低点,即2. 预备知识 - 图29。首先获得y关于x的导数:
2. 预备知识 - 图30

  • 如果当前位于点x=0,那该点的导数值为-10,那么0-(-10)=10
  • 如果当前位于点x=3,那该点的导数值为-4,那么3-(-4)=7
  • 如果当前位于点x=7,那该点的导数值为4,那么7-4=3
  • 如果当前位于点x=10,那该点的导数值为10,那么10-10=0

可以看到,当在2. 预备知识 - 图31左侧时,通过梯度[1]下降的方式总是向右移动;当在2. 预备知识 - 图32右侧时,通过梯度下降的方式总是向左移动。若给定一个小于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), 即2. 预备知识 - 图33%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))表示为2. 预备知识 - 图34#card=math&code=E%5BX%5D%3D%5Csum%7Bx%7D%20x%20P%28X%3Dx%29&id=AKase)
    当函数f(x)的输入是从分布P中抽取的随机变量时,f(x)的期望值为![](https://g.yuque.com/gr/latex?E
    %7Bx%20%5Csim%20P%7D%5Bf(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与其期望值的偏置由方差来实现:2. 预备知识 - 图35%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时, 函数值偏离该函数的期望的程度:2. 预备知识 - 图36%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)

  1. 梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向 ↩︎