net.parameters()&net.state_dict()
前者用于优化器的初始化,后者多用于模型的保存
register_buffer
回顾模型保存:torch.save(model.state_dict()),model.state_dict()是一个字典,里边存着我们模型各个部分的参数。在model中,我们需要更新其中的参数,训练结束将参数保存下来。但在某些时候,我们可能希望模型中的某些参数参数不更新(从开始到结束均保持不变),但又希望参数保存下来(model.state_dict() ),这是我们就会用到 register_buffer() 。
self.register_buffer(‘my_buffer’, self.tensor):my_buffer是名字,str类型;
self.tensor是需要进行register登记的张量。这样我们就得到了一个新的张量,这个张量会保存在model.state_dict()中,也就可以随着模型一起通过.cuda()复制到gpu上
self.register_buffer('weight_epsilon',torch.FloatTensor(out_features,in_features))
torch中的参数dim
一般-1代表最后一维,也就是最小的维度,比如二维dim=0,1 那么-1等价于1。dim=0,1,2,那么-1等价于2
data=torch.rand([2,3])
print(data)
#下面两个结果一样
print(torch.cat([data,data],dim=-1))
print(torch.cat([data,data],dim=1))
with torch.no_grad()
则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用。它的作用是将该with语句包裹起来的部分停止梯度的更新,从而节省了GPU算力和显存,但是并不会影响dropout和BN层的行为
torch.eval()
eval()的作用是不启用 Batch Normalization 和 Dropout,并且不会保存中间变量、计算图。
torch.clamp()&torch.clip()数值裁剪
两个函数用法一样,效果也一样
将输入input张量每个元素的值压缩到区间 [min,max],并返回结果到一个新张量
torch.clamp(input, min, max, out=None) → Tensor
input:输入张量;min:限制范围下限; max:限制范围上限;out:输出张量。
a=torch.rand(5)
a=torch.clip(a,-0.5,0.5)
print(a)
torch.eye()
返回一个二维数组,对角线为1,其余为0
torch.eye(n,m=None,out=None)
n:行数;m:列数
print(torch.eye(2))
print(torch.eye(3,4))
torch.stack()
沿一个新维度对输入张量序列进行连接,序列中所有张量应为相同形状;stack 函数返回的结果会新增一个维度,而stack()函数指定的dim参数,就是新增维度的(下标)位置。
torch.stack(sequence, dim=0)
sequence:参与创建新张量的几个张量;dim:新增维度的(下标)位置,当dim = -1时默认最后一个维度;
import torch
a = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = torch.tensor([[11, 22, 33], [44, 55, 66], [77, 88, 99]])
#可以自己按不同的维度进行连接
c = torch.stack([a, b], dim=0)
print(a)
print(b)
print(c)
# 输出信息:
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
tensor([[11, 22, 33],
[44, 55, 66],
[77, 88, 99]])
tensor([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[11, 22, 33],
[44, 55, 66],
[77, 88, 99]]])
param.requires_grad = False
屏蔽预训练模型的权重,只训练全连接层的权重
torch.bmm()
完成三维tensor的矩阵乘法运算,矩阵必须是3维数据(nrowcol )
格式: bmm(input, mat2, *, out=None) -> Tensor
其中两个tensor的第一维必须相等,然后第一个数组的第三维和第二个数组的第二维度要求一样
矩阵维度必须为三维,不然会报错
c=torch.rand((10,2,5))
d=torch.rand((10,5,2))
res=torch.bmm(c,d)
print(res)
torch.norm()
def norm(input, p=“fro”, dim=None, keepdim=False, out=None, dtype=None):
- input:输入tensor类型的数据
- p:指定的范数
- dim:指定在哪个维度进行,如果不指定,则是在所有维度进行计算。
- keepdim:True or False,如果True,则保留dim指定的维度,False则不保留。
- out:输出的tensor,文档没说具体含义,暂时不知。
- dtype:指定输出的tensor的数据类型。
import torch
t = torch.ones(64, 3, 3, 3)
t_norm = t.norm(1, 3)
print(t_norm)
指定p=1,dim=3。也就是在t的第3个维度(从0开始)进行1范数计算。
调试一下可以发现:t_norm的shape为(64,3,3),keepdim默认设置的是False,所以第3个维度对应的3消失了,如果keepdim=True,将会保留第3个维度,但是会变成(64,3,3,1)
torch.sign()
torch.sign(input, out=None) → Tensor
该函数的作用就是输出input通过sign函数后的张量,其中sign函数就是符号函数,如下图所示。
>>> a = torch.tensor([0.7, -1.2, 0., 2.3])
>>> a
tensor([ 0.7000, -1.2000, 0.0000, 2.3000])
>>> torch.sign(a)
tensor([ 1., -1., 0., 1.])
detach()
在 PyTorch 中,detach() 方法用于返回一个新的 Tensor,这个 Tensor 和原来的 Tensor 共享相同的内存空间,但是不会被计算图所追踪,也就是说它不会参与反向传播,不会影响到原有的计算图,这使得它成为处理中间结果的一种有效方式,通常在以下两种情况下使用:
- 在计算图中间,需要截断反向传播的梯度计算时。例如,当计算某个 Tensor 的梯度时,我们希望在此处截断反向传播,而不是将梯度一直传递到计算图的顶部,从而减少计算量和内存占用。此时可以使用 detach() 方法将 Tensor 分离出来。
- 在将 Tensor 从 GPU 上拷贝到 CPU 上时,由于 Tensor 默认是在 GPU 上存储的,所以直接进行拷贝可能会导致内存不一致的问题。此时可以使用 detach() 方法先将 Tensor 分离出来,然后再将分离出来的 Tensor 拷贝到 CPU 上。
detach的例子:
首先detach()方法返回一个新的变量,这个变量跟data tensor共享同一个地址,返回的变量干了两件事:
- 将requires_grad = false
- 将 grad_fn = None’
当改变返回的变量时会被autograd追踪到,因为in-place保护机制,导致对我想对原变量进行backward()的时候就会报错。出错的机制是因为保护机制.
x=torch.rand(3,4,requires_grad=True)
y=x.detach()
print(x)
print(y)
"""
x tensor([[0.0745, 0.6469, 0.4452, 0.0843],
[0.5808, 0.3859, 0.8170, 0.4534],
[0.7095, 0.2628, 0.8021, 0.9705]], requires_grad=True)
y tensor([[0.0745, 0.6469, 0.4452, 0.0843],
[0.5808, 0.3859, 0.8170, 0.4534],
[0.7095, 0.2628, 0.8021, 0.9705]])
"""
x=torch.ones(5,requires_grad=True)
y=x.detach()*2
z=y.sum()#y没有梯度
z.backward()#RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
x=torch.ones(5,requires_grad=True)
y=x**2
z=x**3
r=(z+y).sum()
r.backward()
print(x.grad)#tensor([5., 5., 5., 5., 5.])
x=torch.ones(5,requires_grad=True)
y=x**2
z=x.detach()**3
r=(y+z).sum()
r.backward()
#梯度通过y传递
print(x.grad)#tensor([2., 2., 2., 2., 2.])
分别修改x.detach和x.data
修改x.detach 梯度不变
x=torch.ones(5,requires_grad=True)
z=x**2
x.detach=torch.tensor([2,2,2,2,2],dtype=float)
y=x**3
k=(z+y).sum()
k.backward()
print(x.grad)#tensor([5., 5., 5., 5., 5.])
修改x.data梯度改变
x=torch.ones(5,requires_grad=True)
z=x**2
x.data=torch.tensor([2,2,2,2,2],dtype=float)
y=x**3
k=(z+y).sum()
k.backward()
print(x.grad)#tensor([16., 16., 16., 16., 16.], dtype=torch.float64)