Tensor和autograd
Tensor
从接口的角度而言,对Tensor的操作可以分为2类:
- torch.function torch.save
- tensor.function tensor.view
从存储的角度而言,对Tensor的操作可分为2类: - 不会修改自身的数据 a.add(b)加法的结果会返回一个新的tensor
- 会修改自身的数据 a.add_(b) 加法的结果仍然存住在a中,a被修改了
创建tensor
a = t.Tensor(2,3)
b = t.Tensor([ [1,2,3],[4,5,6] ])
b.tolist()
b.size()
b.numel()
c = t.Tensor(b.size())
d = t.Tensor( (2,3) )
tensor.shape() = tensor.size()
需要注意的是,t.Tensor(*sizes)创建Tensor时,系统不会马上分配空间,只会计算剩余的内存是否足够使用,使用到Tensor时才会分配内存空间,而其他操作都是在创建完Tensor之后马上分配内存空间。
t.ones(2,3)
t.zeros(2,3)
t.arange(1,6,2)
常用的Tensor操作
tensor.view方法可以调整tensor的形状,但必须保证调整前后元素总数一致,与原tensor共享内存空间
b.view(-1,3) # 当某一维度是-1时,会自动计算它的大小
squeeze添加某一维度 unsqueeze删除某一维度
resize是另外一种用来调整size的方法,但是与view不同的是,他可以修改tensor的尺寸,如果尺寸超过了原来的尺寸,则会自动分配新的内存空间,而如果尺寸小于原来的尺寸,则之前的数据依旧会被保存
索引操作,普通索引一半与原数据共享内存
高级索引 但是值得注意的是高级索引一半不与原数据共享内存
Tensor类型 默认的Tensor类型是FloatTensor t.set_default_tensor_type修改默认的tensor类型 torch.new() = torch.Tensor()
逐元素操作
归冰操作:注意dim
比较
线形代数 注意在线性代数的转置操作会导致内存空间不连续,需要调用他的.contiguous将其转换成为连续的
Tensor和Numpy
广播法则(Broadcast): - 让所有的输入数组都向其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐
- 两个数组要么在某一个维度长度一致,要么其中一个为1,否则不能计算
- 当输入数组的某一个维度是1时,计算时沿此维度复制扩充一样的形状
a = t.ones(3,2)
b = t.zeros(2,3,1)
pytorch中有自动广播法则可以直接写a+b
手动广播法则 a.unsqueeze(0).expand(2,3,2) + b.expand(2,3,2)
tensor内部的数据结构
tensor
- 头信息区(size , stride , type)
- 存储区
普通索引可以通过修改tensor的offset,stride和size实现,不会修改storage中的数据,但是高级索引不行,所以一半索引共享内存,高级索引与原数据不共享内存
计算图 - autograd根据用户对Variable的操作构建计算图,对Variable的操作抽象为Function
- 由用户创建的节点称之为叶子结点,叶子结点的grad_fn为None,叶子结点中需要求导的Variable具有AccumulateGrad标识,因其梯度是累加的
- variable默认是不需要求导的,即required_grad属性默认为False,如果一个variable的该属性值为True,则所有依赖此变量的variable此属性值均为True
- variable的volatile(ture的v不会求导)默认为False,优先级高于required_grad
- 多次反向传播时,梯度是累加的,反向传播的中间缓存会被清空,为进行多次反向传播需要指定retain_graph= true来保存这些缓存
- 非叶子结点的梯度计算完之后即被清空,可以使用autograd.grad或者hook技术进行获得
- variable的grad与data的形状一致,应避免直接修改variable.data,因为对data的操作无法利用autograd进行反向传播
⚠️:在每一次反向传播之前要记得先把梯度清零