本项目提供了一个基于 PyTorch 实现的简化版液态神经网络 (Liquid Neural Network, LNN) 的示例。代码旨在帮助理解 LNN 的核心思想,特别是其基于微分方程的神经元动态,以及如何构建一个处理时序数据的完整网络。
什么是液态神经网络?
液态神经网络是一种受生物神经系统启发的连续时间递归神经网络 (RNN)。与传统 RNN 在离散时间步上更新状态不同,LNN 的神经元状态由一个微分方程描述,使其能够更自然地处理非均匀采样或连续的时间序列数据。其核心优势在于强大的动态适应性和处理复杂时序任务的能力。
本项目实现的是一种简化的变体,即 液态时间常数网络 (Liquid Time-Constant Network, LTC)。
文件结构与核心组件
代码主要由三个部分组成:
LiquidNeuron
(液态神经元)
这是 LNN 的最基本单元。
每个神经元的状态 h
由一个一阶常微分方程 (ODE) 决定。在代码中,我们使用欧拉法将其离散化:
dh/dt = (-h + activation_function) / tau
关键的可学习参数包括:
w_in
: 输入权重。
w_rec
: 循环(自回归)权重。
tau
: 时间常数,控制神经元对输入的遗忘速度和反应快慢,是 LNN 的核心参数之一。
bias
: 偏置项。
LiquidLayer
(液态神经元层)
由多个 LiquidNeuron
实例组成,并行处理输入。
负责在每个时间步 t
迭代更新所有神经元的状态 h
。
将整个输入序列 x_seq
处理后,输出一个包含每个时间步状态的序列 h_seq
,其维度为 [batch, seq_len, hidden_size]
。
LiquidNN
(液态神经网络)
完整的网络模型。
包含一个 LiquidLayer
用于捕捉时序动态,以及一个标准的全连接层 (nn.Linear
) 用于根据最终的隐藏状态进行分类或回归。
在本示例中,我们取序列的最后一个隐藏状态 h_seq[:, -1, :]
作为最终输出的依据。
如何运行
依赖
Python 3.x
PyTorch
代码
直接运行即可:
import torch
import torch.nn as nn
import torch.optim as optim
class LiquidNeuron(nn.Module):
"""
单个液态神经元,核心是一个带有可学习时间常数的微分方程
"""
def __init__(self, input_size):
super().__init__()
self.input_size = input_size
self.w_in = nn.Parameter(torch.randn(input_size, 1)) # 输入权重
self.w_rec = nn.Parameter(torch.randn(1)) # 自回归权重
self.tau = nn.Parameter(torch.ones(1)) # 时间常数
self.bias = nn.Parameter(torch.zeros(1))
def forward(self, x, h_prev, dt=1.0):
# x: [batch, input_size]
# h_prev: [batch, 1]
input_term = torch.matmul(x, self.w_in)
dh = (-h_prev + torch.tanh(input_term + self.w_rec * h_prev + self.bias)) / self.tau
h = h_prev + dh * dt
return h
class LiquidLayer(nn.Module):
"""
液态神经元层
"""
def __init__(self, input_size, hidden_size):
super().__init__()
self.neurons = nn.ModuleList([LiquidNeuron(input_size) for _ in range(hidden_size)])
def forward(self, x_seq):
# x_seq: [batch, seq_len, input_size]
batch, seq_len, _ = x_seq.shape
device = x_seq.device
h = torch.zeros(batch, len(self.neurons), device=device)
outputs = []
for t in range(seq_len):
x_t = x_seq[:, t, :]
h_new = []
for i, neuron in enumerate(self.neurons):
h_i = neuron(x_t, h[:, i:i+1]) # h_i: [batch, 1]
h_new.append(h_i)
h = torch.cat(h_new, dim=1) # [batch, hidden_size]
outputs.append(h.unsqueeze(1)) # [batch, 1, hidden_size]
return torch.cat(outputs, dim=1) # [batch, seq_len, hidden_size]
class LiquidNN(nn.Module):
"""
液态神经网络整体结构
"""
def __init__(self, input_size, hidden_size, output_size):
super().__init__()
self.liquid = LiquidLayer(input_size, hidden_size)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x_seq):
# x_seq: [batch, seq_len, input_size]
h_seq = self.liquid(x_seq) # [batch, seq_len, hidden_size]
out = self.fc(h_seq[:, -1, :]) # [batch, output_size]
return out
if __name__ == "__main__":
# 示例:用液态神经网络拟合一个简单的序列分类任务
batch_size = 8
seq_len = 10
input_size = 3
hidden_size = 5
output_size = 2
model = LiquidNN(input_size, hidden_size, output_size)
optimizer = optim.Adam(model.parameters(), lr=0.01)
loss_fn = nn.CrossEntropyLoss()
# 随机生成数据
x = torch.randn(batch_size, seq_len, input_size)
y = torch.randint(0, output_size, (batch_size,))
for epoch in range(200):
pred = model(x)
loss = loss_fn(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch+1) % 50 == 0:
print(f"Epoch {
epoch+1}, Loss: {
loss.item():.4f}")
print("预测结果:", torch.argmax(model(x), dim=1))
print("真实标签:", y)
脚本将执行以下操作:
构建 LiquidNN
模型。
生成随机的时序数据 x
和对应的标签 y
。
使用 Adam 优化器和交叉熵损失函数进行 200 个周期的训练。
每 50 个周期打印一次训练损失。
训练结束后,打印模型的预测结果和真实标签以作对比。
如何扩展与定制
用于真实任务:
将 if __name__ == "__main__":
部分替换为你的数据加载和预处理逻辑。
根据你的任务调整 input_size
, hidden_size
, output_size
等超参数。
如果你的任务是回归,请将损失函数 nn.CrossEntropyLoss
更改为 nn.MSELoss
或 nn.L1Loss
。
构建更深层的网络:
可以堆叠多个 LiquidLayer
来构建更深的模型,以捕捉更复杂的时序依赖关系。
使用更精确的 ODE 求解器:
本示例使用简单的欧拉法离散化 ODE。对于需要更高精度的任务,可以集成 torchdiffeq
等库,使用更先进的 ODE 求解器(如 Runge-Kutta)。
希望这个示例能帮助你快速上手液态神经网络!
暂无评论内容