【原创】torch.autograd.backward()函数解读

本文深入解析PyTorch中torch.autograd.backward()函数的使用方法与特性,包括源码定义、程序示例和自我总结,帮助读者理解如何通过该函数计算变量梯度。

torch.autograd.backward()函数解读

参考内容:

1. torch.autograd.backward()的源码定义

作为计算向量或矩阵梯度的接口,torch.autograd.backward()在pytorch中的官方源码定义如下:

# torch.autograd提供了类和函数用来对任意标量函数进行求导。要想使用自动求导,只需要对已有的代码进行微小的改变。只需要将所有的tensor包含进Variable对象中即可。
torch.autograd.backward(variables, grad_variables, retain_variables=False)

Computes the sum of gradients of given variables w.r.t. graph leaves.给定图的叶子节点variables, 计算图中变量的梯度和。 计算图可以通过链式法则(chain rule)求导。如果variables中的任何一个variable是 非标量(non-scalar)的,且requires_grad=True。那么此函数需要指定grad_variables,它的长度应该和variables的长度匹配,里面保存了相关variable的梯度(对于不需要gradient tensorvariableNone是可取的)。
此函数累积leaf variables计算的梯度。你可能需要在调用此函数之前将leaf variable的梯度置零。

  • 参数说明:

  • variables (variable 列表) – 被求微分的叶子节点,即 ys

  • grad_variables (Tensor 列表) – 对应variable的梯度。仅当variable不是标量且需要求梯度的时候使用。

  • retain_variables (bool) – True,计算梯度时所需要的buffer在计算完梯度后不会被释放。如果想对一个子图多次求微分的话,需要设置为True

2. torch.autograd.backward()一般程序示例

y = 2 x T x y=2x^Tx y=2xTx中y对x的梯度:

x.grad.zero_() #梯度初始化,防止梯度累计
x = np.arange(4.0, requires_grad = True) #x需要求梯度
y = 2 * torch.dot(x,x) # $y=2x^Tx$
y.sum.backward() # 对矢量y先求和再回溯每个叶子结点求梯度
x.grad() #y对x的梯度

x.grad.zero_() #梯度初始化,防止梯度累计
x = np.arange(4.0, requires_grad = True) #x需要求梯度
y = 2 * torch.dot(x,x) 
y.backward(torch.ones_like(y)) # 对向量y求和就等价于y点乘维度相同的全1矩阵
x.grad() #生成并存储梯度变量(y对x的梯度)

可验证梯度正确与否:

x.grad = 4 * x
tensor([True, True, True, True])

3. 自我总结

torch.autograd.backward()函数特性如下:

  • torch.autograd.backward()用于神经网络的最后一层输出——loss function上By default, pytorch expects backward() to be called for the last output of the network - the loss function.
  • torch.autograd.backward()只能用于标量,若计算向量或矩阵的梯度,须将向量或矩阵使用sum()函数转化成标量再求梯度;
  • sum()或ones()的方式并不会影响梯度计算结果,因为调用backward()后会根据链式法则(chain rule)自动计算并返回要求梯度的向量或矩阵的所有叶子节点的梯度值。
下面的代码是干什么用的,请生成深度说明注释,让我理解每一行代码含义: 【import torch.nn as nn import torch import numpy as np input_size = 1 hidden_size1 =50 hidden_size2 =20 output_size = 1 N2 = nn.Sequential( nn.Linear(input_size, hidden_size1), nn.Tanh(), nn.Linear(hidden_size1, hidden_size2), nn.Tanh(), nn.Linear(hidden_size2, output_size) ) device=torch.device(“cuda:0” if torch.cuda.is_available() else “cpu”) w=60000 l=2.7 I=0.000038929334 E=200*10**9 N2 = N2.to(device) def f(x): return -w/(E*I) def loss(x): x.requires_grad = True y = N2(x) dy_1 = torch.autograd.grad(y.sum(), x, create_graph=True)[0] dy_2 = torch.autograd.grad(dy_1.sum(), x, create_graph=True)[0] dy_3 = torch.autograd.grad(dy_2.sum(), x, create_graph=True)[0] dy_4 = torch.autograd.grad(dy_3.sum(), x, create_graph=True)[0] return torch.mean( (dy_4-f(x))**2 + (y[0, 0] - 0)**2 +(y[-1, 0] - 0)**2+(dy_2[0, 0] - 0)**2+(dy_2[-1, 0] - 0)**2 ) optimizer = torch.optim.Adam(N2.parameters(),lr=0.01) x = torch.linspace(0, l, 100)[:, None] def closure(): optimizer.zero_grad() l = loss(x) l.backward() return l epochs = 2000 for i in range(epochs): optimizer.step(closure) if(i%100==0): print(‘cost function:’,loss(x).detach().numpy()) xx = torch.linspace(0, l, 100)[:, None] with torch.no_grad(): yy = N2(xx) true_y= (w/(24EI))(-xx**4+2lxx3-l3xx) import matplotlib.pyplot as plt plt.title(‘Deflection of the Simply Supported Beam with Udl w(x)’) plt.plot(xx, true_y,c=‘blue’) plt.scatter(xx, yy,c=‘red’) plt.xlabel(‘Along The length(x)’) plt.ylabel(‘Deflection y(x)’) plt.legend([‘Analytical’,‘Deep NN’]) plt.grid() plt.show()
03-29
``` import pandas as pd from sklearn.preprocessing import MinMaxScaler # 加载台风数据(示例格式:时间,经度,纬度,风速,气压) data = pd.read_csv('typhoon_data.csv') # 归一化处理(经纬度需特殊处理) scaler_lon = MinMaxScaler(feature_range=(-1,1)) scaler_lat = MinMaxScaler(feature_range=(-1,1)) data['经度'] = scaler_lon.fit_transform(data[['经度']]) data['纬度'] = scaler_lat.fit_transform(data[['纬度']]) # 时间序列间隔处理 data['时间'] = (data['时间'] - data['时间'].min()) / (data['时间'].max() - data['时间'].min()) import torch import torch.nn as nn class TyphoonPINN(nn.Module): def __init__(self): super().__init__() self.net = nn.Sequential( nn.Linear(3, 64), # 输入: 时间,经度,纬度 nn.Tanh(), nn.Linear(64, 64), nn.Tanh(), nn.Linear(64, 4) # 输出: 风速,气压,经度变化率,纬度变化率 ) def forward(self, t, lon, lat): inputs = torch.cat([t, lon, lat], dim=1) return self.net(inputs) def physics_loss(outputs, inputs): # 输出解构 v_pred, p_pred, dlon_pred, dlat_pred = outputs[:,0], outputs[:,1], outputs[:,2], outputs[:,3] # 自动微分计算梯度 t = inputs[:,0].requires_grad_(True) lon = inputs[:,1].requires_grad_(True) lat = inputs[:,2].requires_grad_(True) # 运动学约束 dv_dt = torch.autograd.grad(v_pred, t, grad_outputs=torch.ones_like(v_pred), create_graph=True)[0] # 构建动量方程残差 momentum_residual = dv_dt - (dlon_pred**2 + dlat_pred**2)**0.5 # 梯度风平衡约束 pressure_grad = torch.autograd.grad(p_pred, lon, grad_outputs=torch.ones_like(p_pred), create_graph=True)[0] wind_balance = v_pred - torch.sqrt(torch.abs(lon * pressure_grad / 1.2)) # 空气密度取1.2kg/m³ return torch.mean(momentum_residual**2) + torch.mean(wind_balance**2) model = TyphoonPINN() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) for epoch in range(10000): # 从数据集中采样 inputs = torch.tensor(data[['时间','经度','纬度']].values, dtype=torch.float32) targets = torch.tensor(data[['风速','气压']].values, dtype=torch.float32) # 模型预测 outputs = model(inputs[:,0:1], inputs[:,1:2], inputs[:,2:3]) # 损失计算 data_loss = nn.MSELoss()(outputs[:,0:2], targets) physics_loss = physics_loss(outputs, inputs) total_loss = data_loss + 0.1*physics_loss # 物理约束权重系数 # 反向传播 optimizer.zero_grad() total_loss.backward() optimizer.step() import matplotlib.pyplot as plt # 绘制预测路径 with torch.no_grad(): pred = model(inputs[:,0:1], inputs[:,1:2], inputs[:,2:3]) plt.figure(figsize=(10,6)) plt.scatter(data['经度'], data['纬度'], c='r', label='真实路径') plt.plot(pred[:,2].numpy(), pred[:,3].numpy(), 'b--', label='预测路径') plt.xlabel('归一化经度') plt.ylabel('归一化纬度') plt.legend()```帮我解读每一句话的含义和用法
04-02
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值