import torch
线性代数实现
#标量
a=torch.tensor([3.0])
a
tensor([3.])
#向量
x=torch.arange(4)
#按下标访问
x[3]
tensor(3)
#长度
len(x)
4
#形状
x.shape
torch.Size([4])
#矩阵
A=torch.arange(20).reshape(5,4)
A
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
#矩阵转置
A.T
tensor([[ 0, 4, 8, 12, 16],
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])
#对称矩阵
B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])
#判断是否为对称矩阵
B==B.T
tensor([[True, True, True],
[True, True, True],
[True, True, True]])
#多维....注意建立直觉
X=torch.arange(24).reshape(2,3,4)
X
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]]])
#通过分配新内存,将A的一个副本分配给B....A.clone(),否则是给索引,并非分配内存
A=torch.arange(20).reshape(5,4)
B=A.clone()
#判断
id(A)==id(B)
False
#矩阵乘法
A*B
tensor([[ 0, 1, 4, 9],
[ 16, 25, 36, 49],
[ 64, 81, 100, 121],
[144, 169, 196, 225],
[256, 289, 324, 361]])
#若是张量和一个标量进行运算,意味着对张量的所有元素都与该标量进行运算
a=2
X=torch.arange(20).reshape(4,5)
a*X
tensor([[ 0, 2, 4, 6, 8],
[10, 12, 14, 16, 18],
[20, 22, 24, 26, 28],
[30, 32, 34, 36, 38]])
#计算各元素的和
x=torch.arange(4).reshape(2,2)
x.sum()
tensor(6)
#我们还可以指定张量沿哪一个轴来通过求和
#axis=0表示按列求和 axis=1表示按行求和
#即为0则消去第一个维度,1则消第二个维度,以此类推(例如shape(2,5)则消去2)(可以拓展到多维)
#{0,1
#2,3}
x.sum(axis=0)
tensor([2, 4])
#(2,5,4)->(2,4)
a=torch.ones((2,5,4))
a.sum(axis=1).shape
torch.Size([2, 4])
#keepdims=True保持该维度为1并非直接去掉(2,2)->(1,2)
x.sum(axis=0,keepdims=True).shape
torch.Size([1, 2])
矩阵计算
求导理论 (不太懂)
向量和标量混合求导,求出来依然是向量,向量关于向量求导较为复杂,求取出来为一个矩阵
矩阵求导公式的数学推导(矩阵求导——基础篇):https://zhuanlan.zhihu.com/p/273729929
矩阵求导公式的数学推导(矩阵求导——进阶篇):https://zhuanlan.zhihu.com/p/288541909
#自动求导分为两种一是正向积累,即先求链式求导后面的,二是反向积累,即先求链式前面的
自动求导实现
#计算y=2x(T)x求导
x=torch.arange(4.0)
#计算y关于x的梯度之前需要一个地方来存储梯度
x.requires_grad_(True)#等价于x=torch.arange(4.0,requires_grad=True)
#用于访问梯度
x.grad #默认None
#计算y
y= 2*torch.dot(x,x)
y
tensor(28., grad_fn=<MulBackward0>)
#通过调用反向传播函数来自动计算y关于x每个分量的梯度
y.backward()
x.grad
tensor([ 0., 4., 8., 12.])
#验证
x.grad==4*x
tensor([True, True, True, True])
#计算x的另外一个函数
#默认情况下,Pytorch会累积梯度,我们需要清空之前的值
#清0
x.grad.zero_()
#另外一个函数
y=x.sum()
y.backward()
x.grad
tensor([1., 1., 1., 1.])
#将某些计算移动到记录的计算图之外
x.grad.zero_()
y=x*x
#把y当作常量,若无detach则求导得出不一致
u=y.detach()
z=u*x
z.sum().backward()
#等于u
x.grad==u
tensor([True, True, True, True])
x.grad.zero_()
y.sum().backward()
x.grad==2*x
tensor([True, True, True, True])
#使用自动微分的一个好处是: 即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),
#我们仍然可以计算得到的变量的梯度。 在下面的代码中,while循环的迭代次数和if语句的结果都取决于输入a的值。
def f(a):
b = a * 2
while b.norm() < 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()
#验证
#相当于d=n*a,求导去除了a
a.grad==d/a
tensor(True)