(一) pytorch中API总结

1、unsqueeze(增维度)和squeeze(减维度)函数分析

import torch
import numpy as np
import matplotlib.pyplot as plt

a = torch.arange(0,6).view(2,3)  
 #tensor([[0, 1, 2],[3, 4, 5]])      维度:(2,3)    
print(a)    

#在第二维增加一个维度
b= a.unsqueeze(1)
#tensor([[[0, 1, 2]],[[3, 4, 5]]])  维度:(2,1,3)
print(b)


c = torch.arange(0,6).view(1,2,3)
#tensor([[[0, 1, 2],[3, 4, 5]]])      维度:(1,2,3)   
print(c)

#在第一维降低一个维度
d = c.squeeze(0)
#tensor([[0, 1, 2],[3, 4, 5]])      维度:(2,3)   
print(d)

e = c.squeeze(1)
#tensor([[[0, 1, 2],[3, 4, 5]]])      维度:(1,2,3) 
#可以看出维度并没有变化,仍然为(1,2,3)
print(e)

2、torch.stack()进行汇总,需要注意维度

import torch
import numpy as np
import matplotlib.pyplot as plt

a = torch.arange(0,6).view(2,3)  
b = torch.arange(7,13).view(2,3)
#默认按照维度dim=0
c = torch.stack([a,b],dim=2)
#a: tensor([[0, 1, 2],[3, 4, 5]])
print(a)
#b: tensor([[ 7,  8,  9],[10, 11, 12]])
print(b)
#c: tensor([[[ 0,  7],[ 1,  8], [ 2,  9]], [[ 3, 10],[ 4, 11],[ 5, 12]]])
print(c)

3、torch.split()函数

它不仅可以按份数均匀分割,还可以按特定方案进行分割

源码定义:torch.split(tensor,split_size_or_sections,dim=0)

第一个参数:待分割张量

第二个参数:分割份数;分割方案(list),待分割张量将会分割len(list)份,每一份的大小取决于list中的元素

第三个参数:分割维度,按照索引值+1切分,序列中1代表的是第一行或第一列,不是第二行或第二列。

注意:当第二个参数输入一个序列时,序列的各数值的和必须等于对应维度下形状分量的取值。例如,下面代码中,是按照第一个维度进行切分,而a总共有4行,因此序列的求和必须等于4,也就是1+3=4,而序列中每个分量的取值,则代表切块大小。

tensor的split方法和array的split方法有很大的区别,array的split方法是根据索引进行切分,tensor的split方法是根据索引值再加上1来切分的。

import torch
import numpy as np
import matplotlib.pyplot as plt

a = torch.arange(0,12).reshape(4,3)  
c,d = torch.split(a,[1,3],dim=0)
#a: tensor([[0, 1, 2],[3, 4, 5],[6, 7, 8],[9, 10, 11]])
print(a)
#c: tensor([[0,1,2]])
print(c)
#d: tensor([[3,4,5],[6,7,8],[9,10,11]])
print(d)

4、torch.chunk()

能够按照某维度,对张量进行均匀切分,并且返回结果是原张量的视图,当原张量不能均分时,chunk不会报错,但会返回其他均分的结果

chunk(input: Tensor, chunks: _int, dim: _int=0)

第一个参数:代分割张量

第二个参数:等分的块数

第三个参数:按照的维度

import torch
import numpy as np
import matplotlib.pyplot as plt

a = torch.arange(0,12).reshape(4,3)  
c,d = torch.chunk(a,2,dim=0)
#a: tensor([[0, 1, 2],[3, 4, 5],[6, 7, 8],[9, 10, 11]])
print(a)
#c: tensor([[0, 1, 2],[3, 4, 5]])
print(c)
#d: tensor([[6, 7, 8],[9, 10, 11]])
print(d)

4、对tensor进行reshape的两种常用方法.view和.reshape

view()返回的结果是原始张量数据的另一个视图,即返回的张量与原始张量共享基础数据(但是不是共享内存地址)。同时使用.view()对原始张量进行reshape,一个必要的条件是原始的张量必须在内存空间中连续分布(contiguous)。比如当我们使用.view()方法前使用了诸如.permute()或者.transpose()等张量维度调换的操作,就会产生该张量在内存空间分布不连续的情况,再使用.view()操作时报错。当遇到类似情况时,可以先将tensor进行tensor.contiguous()变换后再进行.view()就不会报错。

.view()方法进行形状重构需要保证原始tensor在内存空间中分布连续,不然无法进行重构。而.reshape()方法却不需要这个条件,因为.reshape()方法既可以返回原始tensor的视图(view),也可以返回原始tensor的一个copy,具体哪种情况取决于这个原始tensor的内存空间分布是否连续。即如果发现这个原始tensor因为经过.permute()或.transpose()等操作变得在内存空间不连续,那么.reshape()方法会返回copy,而如果是正常情况,使用.reshape()也和.view()一样返回view
5、tensor.detach和tensor.detach_

当我们在训练网络的时候可能希望保持一部分的网络参数不变,只对其中一部分的参数进行调整;或者训练部分分支网络,并不让其梯度对主网络的梯度造成影响,这时候需要使用detach()函数来切断一些分支的反向传播。

(1) tensor.detach()

返回一个新的tensor,从当前计算图中分离下来的,新的tensor和原始tensor共同一个内存,即一个修改另一个也会跟着改变。但是分离下来的tensor的requires_grad为false,永远不会计算其梯度,不具有grad。即使之后重新将它的require_grad置为true,它也不会具有梯度grad。继续使用这个新的tensor进行计算,后面当我们进行反向传播,到该调用detach()的tensor就会停止,不能再继续向前进行传播。

import torch
# detach
def detach_test():
    a=torch.tensor([1.5,2.5,3.],requires_grad=True)
    print(a.grad)        #None
    out=a.sigmoid()
    out.sum().backward()
    print(a.grad)        #tensor([0.1491, 0.0701, 0.0452])

if __name__=="__main__":
    detach_test()

(2) 当使用detach()分离tensor但是没有更改这个tensor时,并不影响backward():

import torch
def detach_test():
    a=torch.tensor([1.5,2.5,3.],requires_grad=True)
    print(a.grad)     #None
    out=a.sigmoid()
    print(out)        #tensor([0.8176, 0.9241, 0.9526], grad_fn=<SigmoidBackward0>)

    #添加detach(),c的require_grad为false
    c=out.detach()
    print(c)          #tensor([0.8176, 0.9241, 0.9526])

    #这时候没有对c进行修改,所以并不会影响backward()
    out.sum().backward()
    print(a.grad)     #tensor([0.1491, 0.0701, 0.0452])

  

if __name__=="__main__":
    detach_test()

(3)当使用detach()分离tensor,然后用这个分离出来的tensor去求导数,会影响backward(),会出现错误

import torch
def detach_test():
    a=torch.tensor([1.5,2.5,3.],requires_grad=True)
    print(a.grad)     #None
    out=a.sigmoid()
    print(out)        #tensor([0.8176, 0.9241, 0.9526], grad_fn=<SigmoidBackward0>)

    #添加detach(),c的require_grad为false
    c=out.detach()
    print(c)          #tensor([0.8176, 0.9241, 0.9526])

    #这时候没有对c进行修改,所以并不会影响backward()
    c.sum().backward()
    print(a.grad)     #RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn  


if __name__=="__main__":
    detach_test()

(3) 当使用detach()分离tensor并且更改这个tensor时,即使再对原来的out求导数,会影响backward(),会出现错误。

import torch
def detach_test():
    a=torch.tensor([1.5,2.5,3.],requires_grad=True)
    print(a.grad)     #None
    out=a.sigmoid()
    print(out)        #tensor([0.8176, 0.9241, 0.9526], grad_fn=<SigmoidBackward0>)

    #添加detach(),c的require_grad为false
    c=out.detach()
    print(c)          #tensor([0.8176, 0.9241, 0.9526])
    c.zero_()

    #会发现c的修改同时会影响out的值
    print(c)          #tensor([0., 0., 0.])
    print(out)        #tensor([0., 0., 0.], grad_fn=<SigmoidBackward0>)

    #这时候没有对c进行修改,所以并不会影响backward()
    out.sum().backward()
    print(a.grad)     #RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation


if __name__=="__main__":
    detach_test()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值