详细区分.numpy()、.item()、.cpu()、.clone()、.detach()和.data的用法&& tensor类型的转换

本文介绍了PyTorch中Tensor类型转换的方法,包括将Tensor转为Python标量的.item(),数据设备迁移的.cpu(),转化为Numpy数组的.numpy(),创建无梯度副本的.clone(),以及脱离计算图的.detach()。这些方法在深度学习训练中用于处理GPU和CPU间的转换、损失计算和模型优化。.detach()和.data的区别在于.detach()返回的新Tensor不参与梯度计算,而.data直接获取不可求导的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

.numpy()、.item()、.cpu()、.clone()、.detach()及.data的使用

本文主要介绍 .numpy()、.item()、.cpu()、.clone()、.detach()及.data这些常用的类型转换的函数或者方法的区分,以及在实际训练中遇到的实际问题。

.item()
  • item() 将一个Tensor变量转换为python标量int float等单个的数值,但是不能是数组)常用于用于深度学习训练时,将loss值转换为标量并加,以及进行分类任务,计算准确值值时需要(如例一)。 item()是可以直接从gpu上转换为标量,看下面例一的loss.item() && 例二 运行结果。
# 例一  在gpu上运行 计算loss值和acc值
optimizer.zero_grad()
outputs = model(data)
loss = F.cross_entropy(outputs, label)
acc = (outputs.argmax(dim=1) == label).sum().cpu().item() / len(labels)     #这里也用到了.item(),可以先转换到cpu
loss.backward()
optimizer.step()
train_loss += loss.item()   #这里用到了.item(),也可以直接item()
train_acc += acc
# 例二
a = torch.tensor([5],requires_grad=True,dtype=torch.float64,device='cuda')
print(a)
b = a.item()
print(b)
#输出: 
# tensor([5.], device='cuda:0', dtype=torch.float64, requires_grad=True)  
# 5.0
.cpu()
  • .cpu() 将数据的处理设备从其他设备(如.cuda()拿到cpu上),不会改变变量类型,转换后仍然是Tensor变量。 为什么需要这一步? 因为gpu上的数组不能直接进行转换类型的操作
a = torch.tensor([[1,2,3],[4,5,6]],requires_grad=True,dtype=torch.float64).cuda()
# 正确做法
b = a.cpu().detach().numpy()
b    
输出: array([[1., 2., 3.],
             [4., 5., 6.]])
.numpy()
  • numpy() Tensor.numpy()将Tensor转化为ndarray,这里的Tensor可以是标量(即item()的作用)或者 向量(与item()不同,一般是矩阵),转换前后的dtype不会改变,但是要注意能直接numpy()的tensor的前提是没有梯度·(requires_grad=False)的。若有梯度(比如requires_grad=True,或者在神经网络的前向传播过程中),则需要 先.detach()再进行numpy()。 在后面还会讲解.detach()作用。
  • eg:
a = torch.tensor([[1.,2.]])
a_numpy = a.numpy() #[[1., 2.]]
a = torch.tensor(1.5)
a_numpy = a.numpy() #1.5
.clone()
  • .clone()函数可以返回一个完全相同的tensor,新的tensor开辟新的内存,但是仍然留在计算图中。**所以它复制完会保留原来的梯度,原来有梯度那么clone完也是有梯度的。**而 没有梯度 又可以直接用.numpy()转换为数组,用.clone()也不行,这个暂时感觉用的很少。
  • 下列是有梯度不能用numpy() 的一个错误案例。在前向传播过程中.clone()依旧有梯度,所以不可numpy()
    在这里插入图片描述
.detach()
  • .detach() 函数可以返回一个完全相同的tensor,新的tensor开辟与旧的tensor共享内存,新的tensor会脱离计算图不会牵扯梯度计算。也就是requires_grad=False, 因此可以 接着进行numpy() 的操作,解决了numpy()需要建立在无梯度的tensor的基础上的问题。

举例:前向传播过程中,如果在传播过程中用.detach()生成了新的变量,然后用这个新的变量继续往下传播,这样会导致梯度反向传播到这里就不能继续前面的参数也不会发生改变了

# enc_outputs : 前向传播产生的变量
# enc_outputs1 : 过程中自己生成的变量
for i in enc_outputs:
    a = i[0].cpu().detach().numpy()
    enc_outputs1.append(a)
return torch.tensor(enc_outputs1).to(device), enc_self_attns
# 进行训练的时候enc_outputs1脱离了计算,不进行反向传播了
  • .detach()就是返回一个新的tensor,并且这个tensor是从当前的计算图中分离出来的。但是返回的tensor和原来的tensor是共享内存空间的。当model不希望更新某部分的参数的时候,就可以用.detach()一下,如下例子:

如果A网络的输出被喂给B网络作为输入, 如果我们希望在梯度反传的时候只更新B中参数的值,而不更新A中的参数值,这时候就可以使用.detach()

a = A(input)
a = a.deatch() # 或者a.detach_()进行in_place操作
out = B(a)
loss = criterion(out, labels)
loss.backward()

.data
  • .data — tensor .data 返回和 x 的相同数据 tensor,而且这个新的tensor和原来的tensor是共用数据的,一者改变,另一者也会跟着改变,而且新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点其实detach是一样的)
a = torch.tensor([1.0], requires_grad=True)
b = a.data
print(b, b.requires_grad)
## 输出为: tensor([1.]) False
.data和.detach()不同点

参考博客

pytorch中.numpy()、.item()、.cpu()、.detach()及.data的使用

ValueError:only one element tensors can be converted to Python scalars解决办法

torch.Tensor

Tensor类型的转换:

torch.Tensor

  • CPU和GPU的Tensor之间转换 : 多用于将数据从gpu()转到cpu(),因为gpu上的数据不能直接操作

    • data.cuda():cpu –> gpu
    • data.cpu():gpu –> cpu
  • Tensor与Numpy Array之间的转换

    • data.numpy():Tensor –> Numpy.ndarray

      • 但是要注意此时需要转换的data是否有梯度
      • data有梯度时候,如果直接numpy(),会报错,正确做法是先.detach()
      a = torch.tensor([[1,2,3],[4,5,6]],requires_grad=True,dtype=torch.float64)
      b = a.numpy()
      print(b)
      # RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
      
      # 正确做法
      b = a.detach().numpy()
      b    
      输出: array([[1., 2., 3.],
                   [4., 5., 6.]])
      
      • data没有梯度的时候,可以直接numpy()
      a = torch.tensor([[1,2,3],[4,5,6]],dtype=torch.float64)
      b = a.numpy()
      print(b)
      # array([[1., 2., 3.],[4., 5., 6.]])
      
      • 若data在gpu上,需要先将数据移动到cpu上,具体操作如下:
      a = torch.tensor([[1,2,3],[4,5,6]],requires_grad=True,dtype=torch.float64).cuda()
      # 正确做法
      b = a.cpu().detach().numpy()
      b    
      输出: array([[1., 2., 3.],
                   [4., 5., 6.]])
      
    • torch.from_numpy(data):Numpy.ndarray –> Tensor

      • Numpy桥,将numpy.ndarray 转换为pytorch的 Tensor。 返回的张量tensor和numpy的ndarray共享同一内存空间。修改一个会导致另外一个也被修改。返回的张量不能改变大小。
      a = np.array([1, 2, 3])
      t = torch.from_numpy(a)
      t
      # torch.LongTensor([1, 2, 3])
      t[0] = -1
      a
      # array([-1,  2,  3]
      
  • Tensor的基本类型转换

    • tensor.long():
    • tensor.half():将tensor投射为半精度浮点(16位浮点)类型
    • tensor.int():
    • tensor.double():
    • tensor.float():
    • tensor.char():
    • tensor.byte():
    • tensor.short():
  • Tensor的基本数据类型转换

    • type(dtype=None, non_blocking=False, **kwargs):指定类型改变。例如data = data.type(torch.float32)
    • type_as(tensor):按照给定的tensor的类型转换类型。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

herry_drj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值