我有一个 LSTM 模型,它采用 3 个温度数据序列并输出下一个序列。
input => [array([0.20408163, 0.40816327, 0.6122449 ]),
array([0.40816327, 0.6122449 , 0.81632653])]
output=> [tensor(0.81632653, dtype=torch.float64),
tensor(0.91667510, dtype=torch.float64)]
现在,我想将这个 LSTM 模型与基于牛顿冷却定律的物理信息神经网络 (PINN) 结合起来。这个想法是使用 LSTM 预测温度,然后计算预测温度相对于时间的导数,将物理定律纳入损失函数中。
但是,当我尝试计算 LSTM 输出相对于时间 (t) 的梯度时,返回的梯度为 None。我不确定我是否正确使用 torch.autograd 来实现此目的。
这是我的代码的简化版本:
import torch
import torch.nn as nn
def create_lstm_model(input_size, hidden_size, num_layers, output_size):
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super(LSTMModel, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
out, _ = self.lstm(x, (h0, c0))
out = self.fc(out[:, -1, :])
return out
return LSTMModel(input_size, hidden_size, num_layers, output_size)
def physics_loss_autograd(outputs, time_step):
"""
Compute the physics-informed loss using autograd to get dT/dt.
"""
# Compute dT/dt using autograd
dT_dt = torch.autograd.grad(outputs, time_step, grad_outputs=torch.ones_like(outputs), create_graph=True)[0]
# Newton's law of cooling: dT/dt = -k(T - T_ambient)
residual = dT_dt + k * (outputs - T_ambient)
# Physics loss is the L2 norm of the residual
physics_loss = torch.mean(residual**2)
return physics_loss
t = torch.arange(0,100)
input_size = 1
hidden_size = 64
num_layers = 1
output_size = 1
# Create an instance of the LSTMModel using the function
model = create_lstm_model(input_size, hidden_size, num_layers, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
num_epochs = 100
for epoch in range(num_epochs):
model.train()
total_loss = 0
for inputs, targets in train_loader:
inputs, targets = inputs.float(), targets.float() # Convert to float
# print(inputs.shape)
optimizer.zero_grad()
outputs = model(inputs)
data_loss = criterion(outputs, targets)
# DO SOMETHING LIKE
phys_loss = physics_loss_autograd(outputs, t)
loss = data_loss + phys_loss
loss.backward()
optimizer.step()
total_loss += loss.item()
if (epoch+1) % 20 == 0:
print(f'Epoch {epoch+1}/{num_epochs}, Loss: {total_loss/len(train_loader)}')
有人解决过类似的问题吗?任何关于如何计算 LSTM 输出的时间导数的指导都会非常有帮助!
附加信息:
当我尝试通过 torch.autograd.grad 计算物理信息损失时,问题就出现了:
dT_dt = torch.autograd.grad(outputs, t, grad_outputs=torch.ones_like(outputs), create_graph=True)[0]
这对 dT_dt 返回 None。我怀疑我处理 time_step 或 autograd 设置的方式存在问题,但我不确定到底出了什么问题。
Pytorch 使用 autograd 计算梯度。 Autograd 的工作原理是跟踪计算图中前向传递中的计算,然后向后遍历该计算图以计算梯度。
这意味着计算两个值之间的梯度需要在计算图中链接这些值。相反,Pytorch 无法计算未通过计算图链接的变量之间的梯度。一个简单的例子:
a = torch.randn(8, requires_grad=True)
b = torch.randn(8, requires_grad=True)
c = torch.randn(8, requires_grad=True)
y = a*b
dy_da = torch.autograd.grad(y, a, grad_outputs=torch.ones_like(y), retain_graph=True)[0]
dy_db = torch.autograd.grad(y, b, grad_outputs=torch.ones_like(y), retain_graph=True)[0]
dy_dc = torch.autograd.grad(y, c, grad_outputs=torch.ones_like(y), retain_graph=True, allow_unused=True)[0]
在上面,
dy_da
和dy_db
是张量,而dy_dc
是None
。这是因为 c
不参与生成 y
的计算图 - 没有计算将 c
链接到 y
。
对于您的示例,您的值
t
不参与outputs
的计算,因此无法计算输出相对于t
的梯度。
如果您希望这成为可能,您需要设计模型,使
t
成为生成 outputs
的模型函数的输入。