Matrix

Concept and Principle

  • 标量
1
2
3
4
x=torch.tensor([1.0])
y=torch.tensor([2.0])

print(x+y,x*y,x/y,x**y)
  • 向量
1
2
x=torch.arange(4)
print(x,x[3],len(x),x.shape,x.size())
  • 矩阵
1
2
3
4
x=torch.eye(20)
x=torch.arange(20).view(5,4)
print(x,x.T,x.t())
print(torch.arange(24).reshape(2,3,4))
  • 运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
A=torch.arange(20,dtype=torch.float32).view(5,4)
B=A.clone() #创建A的副本给B,A与B指向不同地址
C=B #B与C指向相同地址
# B,C都会改变
C[0,:] = 0
print(A,B,C)
# 矩阵加 点乘 每个元素求sin
print(A+B,A*B,torch.sin(A))
A=torch.arange(2*20).view(2,5,4).float()
print(A)
# 求和可指定维度,不指定则全部维度求和
print(A.sum(axis=0),A.sum([0,1]),A.sum())
# 求均值可指定维度,不指定则全部维度求均值
# keepdim=True代表不把求均值的那个维度丢掉,一般用来保证广播机制的正常运行
print(A.mean(axis=0,keepdim=True),A.mean([0,1]),A.mean())
# 求个数不可以指定维度
print(A.numel())
# 点积
X=torch.arange(4).float()
Y=torch.ones(4)
print(torch.dot(X,Y))
# 2范数,即向量长度,如果输入超过一维,会展成一维然后当成向量计算
print(torch.norm(X))
# 矩阵乘法
X=X.view(2,2)
Y=Y.view(2,2)
print(torch.mm(X,Y))

Derivative

  • 向量上的导数
    与向量相关的导数有以下四种形式

    • y标量,x向量
      y是由x中各分量计算得到的标量,最终得到y分别每个分量求导得出的向量,这也是梯度的计算过程
    • y向量,x标量
      向量y的每个分量都是x的函数,每个分量分别对x求导最终得出一个向量
    • y向量,x向量
      向量y的每个分量都是由x中各分量计算得到的标量,y的每个分量都分别对x的每个分量求导得出一个向量,最后得到一个矩阵
  • 矩阵上的导数
    导数同样也可以被扩展到矩阵

Automatic derivative

  • 链式求法则
    在神经网络中需要关注向量的链式求导,关键还是要把形状搞对

  • 自动求导
    其含义是计算一个函数在指定值上的导数,它不同于符号求导和数值求导

    • 计算图
      计算图本质上就等价于链式求导法则的求导过程,它将计算表示成一个无环图,下面是具体的例子
    • 反向传播
      反向传播解决了自动求导的问题,它利用在前向传播时计算图中存储的计算中间结果,一步一步反向算出链式求导中各步导数
    • 自动求导实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# pytorch中做Tensor的计算时默认直接构造计算图
# 计算图中入度为0的节点还应该存储关于自身的梯度,需要手动设置requires_grad=True
x=torch.arange(4.0,requires_grad=True)
y=2*torch.dot(x,x)
print(y)
y.backward()
# 计算得出的梯度存在grad中
print(x.grad)

# 要注意pytorch默认会把同一个变量上的梯度累加
# 在另一轮计算梯度时需要先清除之前的值
x.grad.zero_()
y=x.sum()
y.backward()
print(x.grad)

# 在成batch地计算损失的过程中
# 最后将一个向量对向量求导的过程,转化为了标量对向量求导
x.grad.zero_()

# y是一个向量,把它对应为一个batch的损失
y=x*x
# 如果直接求导,会得到一个矩阵,这不是我们想要的
# 将batch中每一个损失加起来得到一个batch的损失后再求导
# 这也是pytorch中所做的
y.sum().backward()
print(x.grad)

# 将某些计算移动到计算图之外
# 这在想要固定网络中某些参数时是有用的
x.grad.zero_()
y=x*x
# u不被计入为计算图的一个单元,而是一个常数
u=y.detach()
z=u*x
z.sum().backward()
print(x.grad==u)

# 控制流也可以正确构成计算图并计算梯度