pytorch自定义函数实现自动梯度

Motivation

构建模型有时需要使用自定义的函数,为了不影响模型的反向传播,需要实现自动梯度计算(即把自定义函数嵌入计算图)。


实现

要点:

  1. 将函数定义为类,需继承自torch.autograd.Function
  2. 需实现两个静态方法:forward()和backward(),分别对应前向传播和反向传播
  3. 函数使用前需调用apply方法从而嵌入计算图,实现自动求导

用一个例子来说明:
假设我们要实现一个多项式拟合模型: y = a + b P 2 ( c x + d ) y = a + bP_2(cx + d) y=a+bP2(cx+d) ,用来拟合正切函数,其中 P 2 P_2 P2为一个二次函数: P 2 ( x ) = x 2 + 2 x P_2(x) = x^2 + 2x P2(x)=x2+2x,需要我们自定义实现

import torch
import math

dtype = torch.float
#构建训练集,使用随机数据
x = torch.linspace(-math.pi, math.pi, 2000, dtype = dtype)
y = torch.tan(x)

#将权重值a,b,c,d随机初始化,设置requires_grad=True以实现自动求偏导
a = torch.randn((), dtype = dtype, requires_grad = True)
b = torch.randn((), dtype = dtype, requires_grad = True)
c = torch.randn((), dtype = dtype, requires_grad = True)
d = torch.randn((), dtype = dtype, requires_grad = True)

#实现P2
class P2(torch.autograd.Function): 
	#定义forward方法,以在前向传播中实现函数的功能
	@staticmethod
	def forward(ctx, input):
		#保存input值,反向传播计算梯度时会用到
		ctx.save_for_backward(input)
		return input**2 + 2*input
	
	#定义backward方法
	@staticmethod
	def backward(ctx,grad_output): 
		#输入参数grad_output是目标函数对输出结果的梯度
		#这里需要计算函数输出值相对于输入input的梯度u,
		#返回grad_output与u的乘积以实现链式法则
		input, = ctx.saved_tensors
		return grad_output * (2 * inptu + 2)

learning_rate = 1e-6
#全量学习
for t in range(2000):
	#对刚刚定义的函数fun调用apply方法,使其嵌入计算图
	p2 = P2.apply
	#前向传播
	y_pred = a + b * p2(c * x + d)
	#定义损失函数
	loss = (y_pred - y).pow(2).sum()
	if t%100 == 99:
		print(t, loss.item())
	#反向传播计算梯度
	loss.backward()
	#更新参数
	#这里每个参数的梯度自定在反向传播时自动计算好并保存在param.grad中了
	with torch.no_grad():
		a -= learning_rate * a.grad
		b -= learning_rate * b.grad
		c -= learning_rate * c.grad
		d -= learning_rate * d.grad

		#将梯度重置为0
		a.grad = b.grad = c.grad = d.grad = None
print(f'Result: y = {a.item()} + {b.item()} * P2({c.item} x + {d.item()}')
	

运行结果:
在这里插入图片描述
(由于参数选择很随意,且权重是随机初始化的,所以拟合效果不好)


参考资料

链接:Learning pytorch with examples

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch中,您可以通过编写自定义的backward函数实现定义梯度计算。这可以用于自定义损失函数、自定义层或其他需要自定义梯度计算的情况。 要自定义backward函数,您需要定义一个函数,它接受输入张量的梯度和其他参数,并返回相对于输入张量的梯度。然后,您可以将这个函数作为一个属性附加到您定义的自定义函数上。 下面是一个简单的示例,展示了如何实现一个自定义梯度计算函数: ```python import torch class MyFunction(torch.autograd.Function): @staticmethod def forward(ctx, input): # 在forward函数中,您可以保存任何需要在backward函数中使用的中间结果 ctx.save_for_backward(input) return input @staticmethod def backward(ctx, grad_output): # 在backward函数中,您可以根据需要计算相对于输入的梯度 input, = ctx.saved_tensors grad_input = grad_output * 2 * input # 这里只是一个示例,您可以根据自己的需求编写梯度计算逻辑 return grad_input # 使用自定义函数创建输入张量 x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True) # 使用自定义函数进行前向传播 output = MyFunction.apply(x) # 计算损失 loss = output.sum() # 执行反向传播 loss.backward() # 打印输入张量的梯度 print(x.grad) ``` 在这个示例中,我们定义了一个名为`MyFunction`的自定义函数,它将输入张量作为输出返回,并且在backward函数中计算相对于输入张量的梯度。我们使用`MyFunction.apply`方法应用自定义函数,并且可以通过调用`backward`方法来计算梯度。 请注意,自定义函数需要继承自`torch.autograd.Function`类,并且前向传播和反向传播函数都需要用`@staticmethod`修饰。 这只是一个简单的示例,您可以根据自己的需求编写更复杂的自定义backward函数。希望对您有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值