深入Pytorch中的Tensor,梯度以及权重

前言

我们在使用pytorch搭建模型的时候,一般只关注模型的forward前向传播,backward后向传播过程中,模型梯度的计算以及参数的更新都是pytorch框架后台自动进行计算的,那么有的时候就会思考,pytorch到底是怎么进行计算的,产生的这些梯度以及参数是如何保存的,而我们想要访问又可以怎样来访问。带着这些疑问,我们来一一解开这些神秘的面纱

tensor的grad属性

首先我们从tensor入手,pytorch中创建的张量,也就是tensor,默认情况下是没有grad梯度属性的。检查一个tensor是否有grad属性可以通过tensor.requires_grad来查看,如果tensor中有grad属性,则返回Ture,反之返回False。

那么我们如何在创建tensor的时候就让tensor具有grad属性呢?那就是要在创建tensor的时候将tensor的requires_grad属性设置为True。举个例子:

import torch
import torch.nn as nn

input = torch.tensor([1., 2., 3., 4.,])
print(input.requires_grad)
#False

input = torch.tensor([1., 2., 3., 4.,], requires_grad=True)
print(input.requires_grad)
#True

我们知道pytorch模型在训练过程中都是以tensor的数据结构进行输入输出计算的,那么tensor具有了grad属性是不是就意味着模型在训练的过程中,计算出来的grad都保存在相应的tensor中呢?我们可以使用tensor.grad查看tensor的梯度,接着上面的例子

input = torch.tensor([1., 2., 3., 4.,], requires_grad=True)
print(input.grad)
#None

输出为空,因为tensor还没有进行计算,虽然具有grad属性,但是暂时并没有梯度值

模型中的梯度grad

在模型运行过程中,所有tensor之间的运算,在所有的输入中,若有一个输入需要求导,那么输出一定会需要求导。
举个例子,我们在训练模型的过程中,Dataloader返回的mini-batch作为输入数据,我们并没有指定需要求导,默认情况下的requires_grad属性也是False。Ground Truth数据同理,默认情况下也不需要求导,那么都不需要求导,那我们的模型在求出loss值之后还怎么进行后向传播计算梯度呢?答案就是上面的规则,其实模型中的weight参数默认情况下是requires_grad属性为True,是需要求导的。所以,虽然输入的数据默认是不需要求导的,但是,模型中的参数是需要求导的,这样一来,只要有一个需要求导,那么模型的输出就是需要求导的。验证一下。

input = torch.randn(4, 3, 256, 256)
print(input.requires_grad)
#False

#初始化一个网络模型
model = nn.Sequential(
		nn.Conv2d(3, 8, 3, 1, 1),
		nn.Conv2d(8, 16, 3, 1, 1)
)
#输出模型中的参数是否有梯度
for param in model.named_parameters():
	print(param[0], param[1].requires_grad)
# 0.weight True
# 0.bias True
# 1.weight True
# 1.bias True

output = model(input)
print(output.requires_grad)
#True

果然输入的时候没有梯度,经过模型计算之后的输出便有了梯度。

通过上面的例子是不是同样也发现了什么?pytorch中的tensor都可以指定requires_grad属性,这是不是就说明了模型中经过后向传播计算出来的梯度值都保存在tensor中,我们来做个后向传播来验证一下

import torch
import torch.nn.functional as F

net1 = torch.nn.Linear(1, 1)   
loss_fcn = torch.nn.BCELoss()

x = torch.zeros((1,1))
y = F.sigmoid(net1(x))

loss = loss_fcn(y, x)
loss.backward()

for param in net1.named_parameters():
    print(param[0], param[1].grad)
#weight tensor([[0.]])
#bias tensor([0.2995])

我们可以看到,通过调用tensor的grad属性就可以获取tensor的梯度值,所以,反向传播过程中计算的梯度值都保存在模型参数或者中间变量中,通过grad属性就可以调用。

这里需要强调的一点是,由于pytorch的内存管理机制,中间变量在计算过程中产生的梯度值在使用过后就被释放了,所以如果要获取中间变量的梯度值,需要通过retain_grad()函数事先声明保留变量的梯度值,这样在变量使用完后还会保存其梯度值,我们接着上面的例子

net1 = torch.nn.Linear(1, 1)

loss_fcn = torch.nn.BCELoss()
x = torch.zeros((1,1))
y = F.sigmoid(net1(x))
loss = loss_fcn(y, x)
loss.backward()
print(y.grad)
#None

y = F.sigmoid(net1(x))
y.retain_grad()
loss = loss_fcn(y, x)
loss.backward()
print(y.grad)
#tensor([[1.9580]])

模型中的参数weight

其实通过上面的一些例子我们就已经可以看出,模型在训练过程中的参数是保存在模型中的,通过model.parameters()或者model.named_parameters()就可以获得,还是通过上面的例子来看:

import torch
import torch.nn.functional as F

net = torch.nn.Linear(1, 1)   
for param in net.named_parameters():
    print(param[0], param[1].data)
#weight tensor([[-0.4321]])
#bias tensor([0.6777])

for param in net.parameters():
    print(param.data)
#tensor([[-0.4321]])
#tensor([0.6777])

通过上面的例子也可以看出,模型在声明的时候,就会自动初始化参数值。

总结

通过深挖pytorch中的tensor,梯度以及权重,了解了梯度、权重的存放位置,获取方式以及传播规律,这样我们就可以在以后的模型训练中更好地了解模型内在的运行规律,同时也可以在模型代码出bug的时候更快地找到问题所在。

  • 25
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
PyTorch是一个深度学习框架,它提供了强大的自动求导功能。在PyTorch,可训练参数的梯度是通过计算图和反向传播来自动计算的,计算图的每个操作都有一个grad_fn属性,它指示了该操作是如何计算得到的。 grad_fn属性是一个指向创建当前Tensor的Function的引用,它在反向传播时用于计算梯度grad_fn属性构成了一个计算图,使用反向传播算法将梯度从输出向输入进行传播。通过grad_fn属性,我们可以追踪Tensor的计算历史,了解它是如何通过哪些操作得到的。 当我们使用PyTorch进行深度学习时,有时可能会遇到权重梯度不更新的问题。这可能是由于以下几个原因导致的: 1. 参数未设置为可训练(requires_grad=True):在定义模型参数时,需要将requires_grad参数设置为True,以确保该参数参与反向传播计算梯度。 2. 权重梯度被手动清零:在优化器的步骤,可能会使用optimizer.zero_grad()手动将权重梯度清零,以避免梯度累积的问题。 3. 学习率设置过小:如果学习率设置过小,可能导致参数更新过慢,可以尝试增大学习率。 4. 非常规的优化器:某些优化器可能会出现权重不更新的问题,可以尝试使用其他常用的优化器,如SGD、Adam等。 5. 数据集问题:如果训练数据集太小,模型可能无法从学到足够的信息来更新权重,因此可以尝试增加训练数据量或进行数据扩充。 以上是一些可能导致权重梯度不更新的常见问题和解决方法。当遇到权重梯度不更新的问题时,可以根据具体情况逐个排查,并结合PyTorch的自动求导机制,通过检查grad_fn属性来了解计算历史,以找到问题所在并进行修正。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值