pytorch---进阶篇(函数使用技巧/注意事项)

tensor.contiguous()

  • Tensor.contiguous(memory_format=torch.contiguous_format) → Tensor:主要是为了辅助pytorch中其他函数,返回原始tensor改变纬度后的深拷贝数据。
  • 常用方法
    contiguous一般与transpose,permute,view搭配使用:使用transpose或permute进行维度变换后,调用contiguous,然后方可使用view对维度进行变形,因为view操作要求tensor在内存中是连续的(如:tensor.contiguous().view() ),如下:
x = torch.Tensor(2,3)
y = x.permute(1,0)         # permute:二维tensor的维度变换,此处功能相当于转置transpose
y.view(-1)                 # 报错,view使用前需调用contiguous()函数
y = x.permute(1,0).contiguous()
y.view(-1)                 # OK
  • 说明解释
    说明:在PyTorch中,有一些对Tensor的操作不会真正改变Tensor的内容,改变的仅仅是Tensor中字节位置的索引。例如:
narrow(),view(),expand(),transpose(),permute()

这些函数是对原始数据纬度的变化,是对原始数据的浅拷贝。在执行这些操作时,pytorch并不会创建新的张量,而是修改了张量中的一些属性,但是二者在内存上是共享的。因此对执行transpose()操作后的张量的改变也会改变原始张量,如下:

x = torch.randn(3, 2)
y = x.transpose(x, 0, 1)
x[0, 0] = 233
print(y[0, 0])   # 233

在这个例子中,x是连续的,y不是连续的。y的布局方式与重新创建一个tensor的布局方式是不一样的,当对y调用了contiguous()函数之后,pytorch会强制拷贝一份tensor,使得它的布局是连续的,这也是执行view操作的条件。


[:,:,None]用法

  • 用途:用于在None纬度上增加一维,新增纬度为1
x = torch.arange(12).reshape(3,4)
y = x[:,:,None]
print(x.shape,'\n',y.shape)
# torch.Size([3, 4]) 
# torch.Size([3, 4, 1])

不同shape张量计算(+ - * /)

  • 说明:当张量的纬度长度相同时不做任何处理,对于纬度长度不同的情况,会自动填充相应的纬度使其满足纬度相同之后再进行运算。填充方式为复制。
x = torch.arange(4).reshape(1,4)
y = torch.arange(4).reshape(4,1)
print(x+y)

a = x.repeat(4,1)
b = y.repeat(1,4)
print(a+b)

register_buffer用法

在pytorch中模型的参数一种nn.Parameter()定义的,包括各种模块中的参数,这种会随着optimazer.step()更新;另一种是buffer,这种不会更新,相当于“常数”,不会在训练中改变

relative_position_index = relative_coords.sum(-1)  # Wh*Ww, Wh*Ww  
self.register_buffer("relative_position_index", relative_position_index)

DropPath层

  • 说明:若x为输入的张量,其通道为[B,C,H,W],那么drop_path的含义为在一个Batch_size中,随机有drop_prob的样本,不经过主干,而直接由分支进行恒等映射。
  • 区别于dropout:dropout是对神经元随机失效;而DropPath是对batch中的样本随机失效。
    ps:需要导入外部包from timm.models.layers import DropPath
  • 使用
from timm.models.layers import DropPath
self.drop_path = DropPath(drop_prob) if drop_prob > 0. else nn.Identity()
x = x + self.drop_path(self.mlp(self.norm2(x)))

表明有一些分支(batch中的样本)不经过norm和mlp,直接进行恒等变换。也就是加入了残差。

torch.roll()

  • torch.roll(input, shifts, dims=None) → Tensor说明:对张量沿指定纬度平移指定的places。
    shifts:int or tuple。表示延指定纬度移动的位置个数
    dims:表示shifts对应的纬度。若shifts是元组,则dims需要相对应
>>> x = torch.tensor([1, 2, 3, 4, 5, 6, 7, 8]).view(4, 2)
>>> x
tensor([[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]])

# 向0纬度正方向平移1个位置
>>> torch.roll(x, 1, 0)
tensor([[7, 8],
        [1, 2],
        [3, 4],
        [5, 6]])

# 向0纬度负方向平移1个位置
>>> torch.roll(x, -1, 0)
tensor([[3, 4],
        [5, 6],
        [7, 8],
        [1, 2]])

# 向0纬度正方向平移2个位置,1纬度正方向平移1个位置
>>> torch.roll(x, shifts=(2, 1), dims=(0, 1))
tensor([[6, 5],
        [8, 7],
        [2, 1],
        [4, 3]])

masked_fill()

  • Tensor.masked_fill(mask, value) → Tensor:将tensor中mask为true的位置替换为value。此函数不改变原始tensor,返回改变后的tensor。mask为一个张量,与tensor形状一致。
x = torch.arange(24).reshape(2,3,4)
y = x.masked_fill(x>10,10)
print(x,'\n\n',y)

# 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]]]) 

#  tensor([[[ 0,  1,  2,  3],
#          [ 4,  5,  6,  7],
#          [ 8,  9, 10, 10]],

#         [[10, 10, 10, 10],
#          [10, 10, 10, 10],
#          [10, 10, 10, 10]]])

Variable()

  • 介绍:对tensor的包装,用于记录在tensor上的操作。Variable计算时,它会逐渐地生成计算图。这个图就是将所有的计算节点都连接起来,最后进行误差反向传递的时候,一次性将所有Variable里面的梯度都计算出来,而tensor就没有这个能力。默认requires_grad=False
    参数:
    1、requires_grad (指定该节点及依赖它的节点是否求导)
    variable默认是不需要被求导的,即requires_grad属性默认为False,如果某一个节点的requires_grad为True,那么所有依赖它的节点requires_grad都为True。
    2、volatile (指定该节点及依赖它的节点是否不求导)
    variable的volatile属性默认为False,如果某一个variable的volatile属性被设为True,那么所有依赖它的节点volatile属性都为True。volatile属性为True的节点不会求导,volatile的优先级比requires_grad高。
    3、retain_graph
    多次反向传播(多层监督)时,梯度是累加的。一般来说,单次反向传播后,计算图会free掉,也就是反向传播的中间缓存会被清空【这就是动态度的特点】。为进行多次反向传播需指定retain_graph=True来保存这些缓存。
    4、backward()
    反向传播,求解Variable的梯度。放在中间缓存中。
    (from Pytorch的Variable详解)

nn.Parameter()

  • 用途:是Variable()的子类。当它被指定为Module的属性时,会被自动地添加到参数列表中,并将出现在Parameters()迭代器中,会被自动优化。Parameter()默认是求梯度的(即默认requires_grad=True),且不能被volatile(即无法设置volatile=True)
  • 使用:torch.nn.parameter.Parameter(data=None, requires_grad=True)或者torch.nn.Parameter(data=None, requires_grad=True):参数是一个tensor,类型为浮点数
y = torch.arange(24).float()  # 可以看做初始化
x = nn.Parameter(y)  # 如果在Module中则会被自动优化

torch.meshgrid()

  • 用途:用于生成坐标网格。常用于作图
  • 使用:torch.meshgrid(*tensors, indexing=None)
#二维举例
x = torch.arange(2)  # 行坐标,长度为2
y = torch.arange(2,5) # 列坐标,长度为3
a1, a2 = torch.meshgrid(x,y)   # 返回一个tuple,2个tensor(2,3)

print(a1)
# tensor([[0, 0, 0],
#         [1, 1, 1]])

print(a2)
# tensor([[2, 3, 4],
#         [2, 3, 4]])

# 三维举例
z = torch.arange(3,7) # 第三维坐标,长度为4
b1, b2, b3 = torch.meshgrid(x,y,z)  # 返回一个tuple,3个tensor(2,3,4)

print(b1)  # 只有第一维的元素不同,相当于b1 = torch.arange(2).reshape(2,1,1).repeat(1,3,4)
# tensor([[[0, 0, 0, 0],
#          [0, 0, 0, 0],
#          [0, 0, 0, 0]],

#         [[1, 1, 1, 1],
#          [1, 1, 1, 1],
#          [1, 1, 1, 1]]])

tensor.detach()

  • 用途: 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。如果继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播。
  • 注意:返回的tensor与原始tensor指向同一片内存,因此对返回张量的修改也会影响原始张量。detached tensor无法求导,但原始tensor可以;如果更改了detached tensor,则原始张量的backward会出错。
  • 举例:如果我们有两个网络 A,B, 两个关系是这样的 y=A(x),z=B(y)现在我们想用 z.backward() 来为 B网络的参数来求梯度,但是又不想求 A 网络参数的梯度,可以使用detach。
# y=A(x), z=B(y) 求B中参数的梯度,不求A中参数的梯度
y = A(x)
z = B(y.detach())
z.backward()

tensor.data()、tensor.detach()、tensor.item()

  • 相同点
    x.data()或x.detach()均会返回与x相同数据的Tensor,并且这个Tensor与原来的Tensor共用内存,一者改变,另一者也会跟着改变,并且新的tensor的requires_grad = False
  • 不同点
    当c = x.data()或c = x.detach()中的c未被改变时,x.data()与x.detach()并没有什么区别,但是当c发生改变时,x.data()并不会报错,因而导致此时即使求导结果错误,也很难发现,相比之下,x.detach()则会报错,显示需要计算的张量已经被更改。现在一般建议使用detach()
  • tensor.item()将单元素tensor转换成python的float类型。一般是在统计累计测试误差及正确率的时候使用,因为统计值一般都是float,而torch计算出来的loss是tensor类型,需要将其转换为float类型累加
a = torch.tensor([0.0], requires_grad=True)
c = a.item()
print(type(c))   # 

参考:
pytorch中的detach()、detach_()
pytorch-detach,detach_
Pytorch中x.data()与x.detach()的区别

tensor.new()

  • 作用创建一个新的Tensor,该Tensor的type和device都和原有Tensor一致,且无内容。
  • 代码
inputs = torch.randn(m, n)
 
 # 创建空的tensor
new_inputs = inputs.new()
new_inputs = torch.Tensor.new(inputs)

# 创建shape为(3,4)的tensor(与inputs的type和device相同)
new_inputs = inputs.new(3,4)

tensor.type_as()

  • Tensor.type_as(tensor) → Tensor,将tensor的dtype转换为指定张量的类型。相当于self.type(tensor.type())

你可能感兴趣的:(pytorch,pytorch,深度学习,python)