动手学深度学习2 |线性代数篇

130 阅读5分钟

线性代数的实现

截屏2023-09-22 09.21.52.png

就像向量是标量的推广一样,矩阵是向量的推广,我们可以构建具有更多轴的数据结构。

截屏2023-09-22 09.24.03.png

对称矩阵的转置是他本身

截屏2023-09-22 09.20.43.png

B = A.clone() 通过分配新内存,将A的一个副本给B

截屏2023-09-22 09.30.49.png

计算操作

  • 矩阵的按元素乘法被称为哈达玛积

张量的求和

  • 如果是一个标量和一个张量相加,就是张量所有元素加上标量
  • 无论是任意形状张量的元素和x.sum()结果都是标量

axis用来为超过一维的数组定义属性。0表示最高维,1表示次高维,2表示再低一维

截屏2023-09-22 10.16.30.png

  • 对于axis的补充说明:

截屏2023-09-23 13.39.42.png

从图上代码可以看出来,当axis=0时是上下两个维度同一位置的元素相加;而axis=1时是两个维度中的元素做纵向相加;axis=2时是两个维度的元素做横向相加


求均值

  • 求均值A.mean()A.sum() / A.numel()。numel()函数可以获取张量元素个数
  • 按某个轴求平均值:A.mean(axis=0)A.sum(axis=0) / A.shape[0]
  • 计算总和或均值是保持轴数不变:sum_A = A.sum(axis=1,keepdims=True) 如果按照某一维度求和,那个维度就会被丢掉,如果是三维数组求和就会变成二维数组
  • 通过广播将A除以sum_A:A / sum_A
  • cumsum()函数可以将输入的数组或序列按元素顺序进行累加,并返回一个新的数组,其中新数组的每个元素都是原数组中前面所有元素的和。新数组b的第一个元素是原数组的第一个元素,第二个元素是原数组的前两个元素的和,以此类推。

截屏2023-09-23 14.01.47.png

乘积

  • 点积是相同位置按元素乘积的和。torch.dot(x,y)x,y是两个向量

    • 也可以用元素乘法然后进行求和来表示两个向量点积torch.sum(x * y)
  • 矩阵向量积:torch.mv(A, x) 矩阵和向量的积是一个列向量

  • 矩阵相乘:torch.mm(A, B)

范数

  • L2范数是向量元素平方和的平方根:torch.norm(u)
  • L1范数是向量元素的绝对值之和:torch.abs(u).sum() 或者 torch.norm(u,1)

截屏2023-09-23 15.43.41.png

norm要求向量必须是浮点数

  • 矩阵的范数是矩阵元素的平方和的平方根:torch.norm(A)

矩阵计算

  1. 标量的导数拓展到向量就是梯度。梯度指向变化值最大的地方。
  2. 标量对向量求导:

截屏2023-09-23 19.14.04.png

3.矩阵求导

截屏2023-09-23 16.00.26.png

  1. 拓展到矩阵

截屏2023-09-23 16.02.58.png

矩阵求导

这里学习了: 矩阵求导的本质与分子布局、分母布局的本质(矩阵求导——本质篇): zhuanlan.zhihu.com/p/263777564

函数与变元

这里考虑一个函数function(input),针对function和input类型我们可以将其划分成不同种类

  • function作为标量,变元分为三种:标量、向量、矩阵
  • function作为向量,f是由若干个f组成的一个向量,变元同样分为三种
    • function作为向量,变元也是向量的例子:
    • 先将y拆解成列向量,和每个x求导,是个行向量,最后展开变成矩阵 截屏2023-09-23 15.56.35.png
  • function作为矩阵,F是由若干个f组成的矩阵

矩阵求导的本质

在高数中,对于多元函数求导,一般是分别对每个变元求偏导。而矩阵求导就是将求出来的结果写成列向量的形式。所以如果一个 function有m个f,变元中有n个元素,那么,每个f对变元的每个元素逐个求编导,就会产生m乘n个结果

截屏2023-09-23 17.21.58.png

矩阵求导结果的布局

  • 分子布局:分子是列向量,分母是行向量
    • 本质是,分子是标量列向量、矩阵向量化后的列向量;分母是标量、列向量转置后的行向量、矩阵的转置矩阵、矩阵向量化后的列向量转置后的行向量
  • 分母布局:分母是列向量,分子是行向量
    • 本质是,分子是标量、列向量转置后的行向量、矩阵向量化后的列向量转置后的行向量;分母是标量列向量矩阵自己、矩阵向量化后的列向量

总结:谁转置了,就是另一方的布局。分子转置了,就是分母布局;分母转置了,就是分子布局。

矩阵求导公式的数学推导(矩阵求导——基础篇): zhuanlan.zhihu.com/p/273729929

矩阵求导公式的数学推导(矩阵求导——进阶篇): zhuanlan.zhihu.com/p/288541909


自动求导

截屏2023-09-23 16.41.26.png


截屏2023-09-23 16.40.33.png

这里的<x,w>是标量,标量对向量的求导,向量取转置。


截屏2023-09-23 19.12.37.png


自动求导

截屏2023-09-23 19.23.34.png

截屏2023-09-23 19.24.24.png

截屏2023-09-23 19.25.41.png

  • 显示构造
from mxnet import sym
a = sym.var()
b = sym.var()
c = 2 * a + b

截屏2023-09-23 19.30.30.png

截屏2023-09-23 19.32.15.png 需要读取之前的结果,来计算

截屏2023-09-23 19.33.58.png

截屏2023-09-23 19.34.11.png

自动求导实现

  • 假设对函数y=2x^Tx关于列向量x求导
import torch
x = torch.arange(4.0)
x
  • 在计算y关于x梯度之前,需要一个地方来存储梯度
x.requires_grad_(True) # 等价于 `x = torch.arange(4.0, requires_grad=True)`

x.grad # 默认值是None

设置一个tensor的 requires_grad为True 会保存该Tensor是否记录所有操作用于计算梯度 x.grad查看梯度值

  • 现在计算y 截屏2023-09-23 19.53.50.png

dot():返回内积
grad_fn用来记录变量是怎么来的,方便计算梯度

  • 通过调用反向传播函数来自动计算y关于x每个分量的梯度,最后验证是否正确 截屏2023-09-23 19.57.24.png

grad:当执行完了backward()之后,通过x.grad查看x的梯度值
backward函数实际上是通过传递参数来计算梯度,它通过backward图一直到每个叶节点,每个叶节点都可以从调用的根张量追溯到叶节点。然后将计算出的梯度存储在每个叶节点的.gard中

  • 现在计算x的另一个函数 截屏2023-09-23 20.21.11.png

_ 表示重写内容,zero_表示将所有梯度清零
sum()函数求导全1,相当于对x1+x2+...+xn求偏导

  • 深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样 本单独计算的偏导数之和。 截屏2023-09-23 20.27.44.png

  • 将某些计算移动到记录的计算图之外

截屏2023-10-07 20.26.16.png

detach() 将y作为一个常数u

  • 即使构建函数的计算图需要通过python控制流,我们仍然可以计算得到的变量的梯度

截屏2023-10-07 20.44.22.png

torch.randn(size=(), requires_grad=True) 生成随机数,size随机