Tensor的基本概念
张量:可以是任意维度
arrange(),左闭右开的
dtype:类型
indices:是坐标值,values:是真实的值
Tensor的运算:
p=torch.arrange(1,3).view(1,2)
print(p)
q=torch.arrange(1,4).view(3,1)
print(q)
print(p+q)
-------------------------
运行结果:
tensor([[1,2]])
tensor([ [1],
[2],
[3] ])
tensor([ [2,3],
[3,4],
[4,5] ])
在[1,2]上,行,列分别加上1,2,3
finite:是否有界,inf:是否无穷
Tensor相关函数:
查看tensor的维度:两种方式
print(k.shape)
print(k.size())
Tensor的索引方式与numpy类似:
print(o[:,1])
这里的 :代表取所有的行,1是指取第二列,因为是从0开始的
print(o[0,:])
这里的 0代表取第0行,:是指所有列
改变tensor形状的神器:view
print(o.view((3,2)))
print(o.view(-1,2))
o原本是个2*3的,print(o.view((3,2)))之后,变成3*2, print(o.view(-1,2)) 这个也是3*2, -1可以自动填充
扩展&压缩tensor的维度:squeeze
压缩 不是想压缩哪个就压缩哪个的 只有当这一维度是1的时候,也就是说这一维 没有实际的数字,只是多了这一维用于后续的计算。
print(o)
r=o.unsqueeze(1)
print(r)
print(r.shape)
运行结果:
tensor([ [1.4017,1.5790,1.8938],
[1.7815,1.5270,1.0005] ])
tensor([ [1.4017,1.5790,1.8938],
[1.7815,1.5270,1.0005] ])
tensor.size( [2,1,3] )
解释:这个o是2*3的,没有1维的,所有我们先进行扩展unsqueeze,发现变成了tensor.size( [2,1,3] ),不是2*3的了,r=o.unsqueeze(1),这里的1 代表在第二个维度上给他强行加上一个,没有实际的数字
///
s=r.squeeze(0)
print(s)
print(s.shape)
运行结果:
tensor([ [1.4017,1.5790,1.8938],
[1.7815,1.5270,1.0005] ])
tensor.size( [2,1,3] )
这里挖了个坑,只有这一维是1的时候才能压缩 ,s=r.squeeze(0),对第0维进行压缩,但第0 维上 不算1,所有不能压缩,失败了 但不会报错,还保持原样。
///
t=r.squeeze(1)
print(t)
print(t.shape)
运行结果:
tensor([ [1.4017,1.5790,1.8938],
[1.7815,1.5270,1.0005] ])
tensor.size( [2,3] )
这个是正确的操作
自动求导
静态图是 A*B=C, C+1=D 需要进行计算
动态图 只需要定义数值就好了,D是从 A B 1 来的。
自动求导案例:
这里将通过一个简单的函数 y=x1+2*x2 来说明pytorch自动求导的过程。
import torch
x1= torch.tensor(1.0,requires_grad=True)
x2= torch.tensor(2.0,requires_grad=True)
y=x1+2*x2
print(y)
运行结果:
tensor(5.,grad_fn=<AddBackward0>)
#首先查看每个变量是否可以求导
print(x1.requires_grad)
print(x2.requires_grad)
print(y.requires_grad)
运行结果:
True
True
True
说明都是可以求导的。
#查看每个变量导数大小,此时因为还没有反向传播,因此导数不存在。
print(x1.grad.data)
print(x2.grad.data)
print(y.grad.data)
运行结果:
报错:AttributeError:'NoneType' object has no attribute 'data'
x1
输出: tensor(1.,requires_grad=True)
#反向传播后看导数大小
y=x1+2*x2
y.backward() #反向传播
print(x1.grad.data)
print(x2.grad.data)
输出: tensor(1.)
tensor(2.)
#导数是会累积的,重复运行相同命令,grad会增加
y=x1+2*x2
y.backward() #反向传播
print(x1.grad.data)
print(x2.grad.data)
输出: tensor(2.)
tensor(4.) #没运行前是tensor(1.) tensor(2.)
在运行一次 是tensor(4.)
tensor(8.)
所以导数是会累积的
#所以每次计算前需要清除当前导数值避免累积,这一功能可以通过pytorch的optimizer实现,后续会讲到
#尝试,如果不允许求导,会出现什么情况?
x1= torch.tensor(1.0,requires_grad=False)
x2= torch.tensor(2.0,requires_grad=False)
y=x1+2*x2
y.backward()
运行结果:
报错,如果不允许求导,它只能正向传播,不能反向传播
y
输出:tensor(5.) #y是有值的 也就是说前向传播完成了,反向传播没有完成。
并行计算
前两个层放到GPU1,后两个层放到GPU2里。