神经算子在流体模拟中的应用
神经算子(Neural Operators)是一类学习无限维函数空间之间映射的深度学习方法。与传统算子(如偏微分方程求解器)相比,神经算子可以学习复杂的物理映射,并在推理时快速评估。本章介绍神经算子在计算流体力学中的核心方法和应用。
1. 从偏微分方程到神经算子
1.1 问题定义
考虑参数化偏微分方程族:
其中 是参数(如边界条件、物理系数), 是解。神经算子的目标是学习映射:
传统方法需要针对每个 求解一次PDE,而神经算子学习这个映射,实现”一次训练,多次推理”。
1.2 算子学习方法对比
| 方法 | 特点 | 计算复杂度 |
|---|---|---|
| 传统求解器 | 有限元/有限差分 | per query |
| 物理信息NN | 逐点预测 | per query |
| 神经算子 | 学习算子 | per query |
| FNO | 频域学习 | |
| DeepONet | 分支-主干网 |
2. Fourier神经算子(FNO)
2.1 核心思想
FNO在频域学习 PDE 解算子,利用傅里叶变换的高效计算:
其中 是傅里叶变换, 是学习的频域变换核(谱层)。1
2.2 FNO架构
class SpectralConv2D(nn.Module):
"""谱卷积层"""
def __init__(self, in_channels, out_channels, modes1, modes2):
super().__init__()
self.in_channels = in_channels
self.out_channels = out_channels
self.modes1 = modes1 # 截断模式数
self.modes2 = modes2
# 可学习的频域权重
self.weights = nn.Parameter(
torch.randn(in_channels, out_channels, modes1, modes2, 2)
)
def forward(self, x):
# x: (batch, channels, x, y)
batch, channels, x_dim, y_dim = x.shape
# 傅里叶变换
x_ft = torch.fft.rfft2(x)
# 在频域应用权重(仅截断模式)
out_ft = torch.zeros(batch, self.out_channels,
x_dim, y_dim // 2 + 1, device=x.device)
# 取截断模式
out_ft[:, :, :self.modes1, :self.modes2] = self._apply_weight(x_ft)
# 逆傅里叶变换
return torch.fft.irfft2(out_ft, s=(x_dim, y_dim))
class FNO2D(nn.Module):
"""2D FNO"""
def __init__(self, modes, width, n_layers):
super().__init__()
self.fc0 = nn.Linear(3, width) # 输入: (x, y, u)
self.spectral_layers = nn.ModuleList([
SpectralConv2D(width, width, modes, modes)
for _ in range(n_layers)
])
self.bn_layers = nn.ModuleList([
nn.BatchNorm2D(width)
for _ in range(n_layers)
])
self.fc1 = nn.Linear(width, 128)
self.fc2 = nn.Linear(128, 1)
def forward(self, x):
x = self.fc0(x).permute(0, 3, 1, 2) # (B, W, H, W) -> (B, W, H, W)
for spec, bn in zip(self.spectral_layers, self.bn_layers):
x = spec(x) + x # 残差连接
x = F.gelu(bn(x))
x = x.permute(0, 2, 3, 1)
return self.fc2(F.gelu(self.fc1(x)))2.3 FNO在Navier-Stokes中的应用
Navier-Stokes方程是流体模拟的核心:
FNO可以直接学习速度场的时间演化:
训练策略:
- 短期预测: 步预测,训练多个自回归步骤
- 长期稳定性:混合损失:
- 数据增强:随机初始条件、随机粘度
def train_fno_navier_stokes(model, dataloader, n_steps=10):
"""训练FNO预测Navier-Stokes流"""
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(...)
for epoch in range(num_epochs):
for u0, u_target in dataloader:
# 短期预测
u_pred = model(u0)
loss = MSE(u_pred, u_target)
# 长期自回归预测
u_seq = [u0]
u_cur = u0
for _ in range(n_steps - 1):
u_cur = model(u_cur)
u_seq.append(u_cur)
# 长期损失
loss_long = sum(MSE(u_seq[i], u_target_seq[i])
for i in range(n_steps))
loss_total = loss + 0.1 * loss_long
loss_total.backward()
optimizer.step()3. DeepONet深度算子网络
3.1 分支-主干架构
DeepONet采用分支-主干(Branch-Trunk)架构:
- 分支网络(Branch):编码输入函数
- 主干网络(Trunk):编码空间坐标
- 输出:分支和主干输出的点积
3.2 DeepONet for Darcy Flow
Darcy方程描述多孔介质流动:
其中 是渗透率(输入函数), 是压力(输出函数)。
class DeepONet(nn.Module):
def __init__(self, branch_layers, trunk_layers, p=100):
super().__init__()
self.p = p # 分支/主干网络维度
# 分支网络:编码渗透率函数
self.branch = nn.Sequential(
nn.Linear(input_dim, 100),
nn.GELU(),
nn.Linear(100, 200),
nn.GELU(),
nn.Linear(200, p)
)
# 主干网络:编码空间坐标
self.trunk = nn.Sequential(
nn.Linear(2, 100), # (x, y) 坐标
nn.GELU(),
nn.Linear(100, 200),
nn.GELU(),
nn.Linear(200, p)
)
def forward(self, a, y):
# a: (batch, sensor_points, input_dim) - 渗透率传感器值
# y: (batch, query_points, 2) - 查询点坐标
# 聚合分支输出
b = torch.mean(self.branch(a), dim=1) # (batch, p)
# 主干网络
t = self.trunk(y) # (batch, query_points, p)
# 点积
return torch.sum(b.unsqueeze(1) * t, dim=2) # (batch, query_points)3.3 DeepONet for Navier-Stokes
对于Navier-Stokes,DeepONet可以学习流场的算子映射:
传感器点选择:选择有物理意义的点(如边界、特征位置)
def train_deeponet_navier_stokes(model, train_data, val_data):
"""DeepONet训练Navier-Stokes"""
branch_input, trunk_input, u_target = train_data
# 分支输入:初始条件和物理参数
branch_out = model.branch(branch_input)
# 主干输入:目标空间坐标
trunk_out = model.trunk(trunk_input)
# 算子输出
u_pred = torch.einsum('bp,bqp->bq', branch_out, trunk_out)
loss = MSE(u_pred, u_target)
loss.backward()4. GraphONet与图结构
4.1 非结构化网格
传统FNO/DeepONet主要处理规则网格,GraphONet处理非结构化网格:
class GraphONet(nn.Module):
"""图神经算子"""
def __init__(self, node_dim, edge_dim, hidden_dim, n_layers):
super().__init__()
self.node_encoder = nn.Linear(node_dim, hidden_dim)
self.edge_encoder = nn.Linear(edge_dim, hidden_dim)
self.message_passing = nn.ModuleList([
MessagePassingLayer(hidden_dim)
for _ in range(n_layers)
])
self.decoder = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim),
nn.GELU(),
nn.Linear(hidden_dim, 1)
)
def forward(self, graph):
x, edge_index, edge_attr = graph.x, graph.edge_index, graph.edge_attr
x = self.node_encoder(x)
for mp in self.message_passing:
x = mp(x, edge_index, edge_attr)
return self.decoder(x)4.2 在流体模拟中的应用
GraphONet在以下场景有优势:
- 复杂几何:飞机、汽车周围的流场
- 自适应网格:不同区域精度不同
- 动态域:可变形边界问题
5. 与传统CFD的对比
5.1 计算效率
| 方法 | 训练成本 | 推理成本 | 精度 |
|---|---|---|---|
| DNS | - | 基准 | |
| LES | - | 高 | |
| RANS | - | 中等 | |
| FNO | 高 | ||
| DeepONet | 高 |
5.2 泛化能力
神经算子的一个关键优势是零样本泛化:训练于有限参数范围,可以外推到未见过的参数:
- 粘度泛化:训练于 ,测试于
- 雷诺数泛化:训练于低Re,预测高Re流场
- 几何泛化:训练于简单几何,测试于复杂几何(GraphONet)
5.3 物理约束
为保证物理一致性,可加入约束:
- 无散度约束:通过投影层或分支网络编码
- 能量守恒:Hamiltonian损失
- 对称性约束:等变网络架构
6. 前沿进展
6.1 自适应神经算子
- Adaptive FNO:动态调整频域模式数
- Multi-scale DeepONet:处理多尺度问题
- Hierarchical Operators:金字塔式算子
6.2 Transformer-based Operators
- OFormer:Operator Transformer架构
- NOAH:神经算子与注意力结合
- Fourier Token Mixer:频域token混合
6.3 实际应用
- 天气预报:短临降水预测
- 工业设计:快速流体仿真
- 数字孪生:实时流场预测
参考文献
Footnotes
-
Li, Z., Kovachki, N., Azizzadenesheli, K., Liu, B., Bhattacharya, K., Stuart, A., & Anandkumar, A. (2021). Fourier neural operator for parametric partial differential equations. ICLR. ↩