公司动态
Fourier Neural Operator实战:从解压到迁移PDE问题
简介傅里叶神经算子FNO是近年解决参数化偏微分方程PDEs的高效深度学习方法在流体、电磁、工程计算等领域表现突出。该zip压缩包提供了FNO的完整源码实现共29个文件以21个Python脚本为核心涵盖模型定义、数据预处理、快速傅里叶变换、训练与评估等模块另有6个MATLAB脚本及说明文档、许可证压缩包仅60KB轻巧便于下载。目前已有409人学习使用。代码包含FNO的一维、二维、三维实现以及低秩近似、超分辨率、图像任务等多种变体并配套Navier-Stokes、Burgers、Darcy等经典PDE场景的数据生成示例可帮助研究者完整复现论文实验、理解频域卷积与IFFT重建流程也为后续算法改进与工程落地提供了可直接扩展的基座。1. 解压 fourier_neural_operator-master.zip别急着双击先搞清这套代码到底要干嘛我收到fourier_neural_operator-master.zip这个压缩包已经不止一次了几乎每次有新同学加入都会卡在同一个地方解压、装环境、跑训练然后报错。这个 zip 是从 GitHub 仓库导出的 master 分支快照对应的是 Fourier Neural Operator傅里叶神经算子的一个经典实现通常被简称为 FNO。它解决的问题很明确用深度学习做偏微分方程PDE的神经算子学习典型用法是训练一个网络输入某个 PDE 的参数场直接输出对应的解场替换传统数值求解器。对于刚接触这个项目的人我最想说的不是算法本身而是动手流程。看似只是一个 zip 解压但里面包含环境依赖、数据集生成、训练脚本、模型定义和一堆坑如果盲目开始基本会浪费一个下午。所以这篇内容我会按照我实际操作的经验从拿到 zip 之后的第一件事讲起覆盖环境配置、代码结构、训练验证和常见报错最后再说怎么把它迁移到你自己的 PDE 问题上。1.1 先检查压缩包完整性别被半截文件坑了网络上直接下载的fourier_neural_operator-master.zip有时候会下载不完整。最典型的报错是invalid zip archive: could not find eocd。eocd 是 zip 格式结尾的 end of central directory 记录如果没找到基本可以断定文件没下完或者传输被中断。遇到这种情况第一步不是找修复工具而是重新下载或者用可以校验哈希的下载工具。GitHub 的 zip 下载页面会显示对应的 SHA256建议下载后先算一下。Linux 下快捷做法sha256sum fourier_neural_operator-master.zip unzip -t fourier_neural_operator-master.zipunzip -t是测试压缩包完整性如果全部显示 OK再解压。Windows 用户可以右键用 7-Zip 的测试功能。这一步虽然很基础但能省掉后面大量莫名其妙的问题。如果压缩包带了密码我的建议是从官方渠道重新获取不要用网上所谓的 zip 密码破解工具既浪费时间也有安全风险。开源项目的 release 包通常不会加密遇到密码保护反而要警惕来源。1.2 解压后先看目录结构再决定下一步解压后目录名字通常是fourier_neural_operator-master。我会先看顶层文件因为这一个步骤能判断你拿到的是完整仓库还是残缺包。一个完整的 FNO 项目至少包含以下内容fourier_1d.py一维 FNO 实现适合处理一维 PDE 或时序类问题。fourier_2d.py二维 FNO最常见对应 Darcy Flow 这类二维稳态问题。fourier_3d.py三维 FNO常用于 Navier-Stokes 方程这类时间二维空间的问题。generate_data.py或data_generation相关脚本生成训练数据。README.md项目说明建议先读。requirements.txt或 import 列表依赖。如果解压后发现只有空目录或者少了核心.py文件多半是解压工具处理 zip 内多级嵌套目录时出了问题。比如某些国产解压软件会把文件解压到一个嵌套子目录里导致路径不对。这时候建议用 7-Zip 或系统的unzip重新解压一遍并注意有没有__MACOSX这种隐藏目录这是 macOS 压缩产生的通常可以删掉。1.3 从 master zip 到自己的 Git 仓库这里要提一个特别容易踩的坑从 GitHub 页面直接下载的 zip 是不带.git目录的它只是一个代码快照。很多人在里面改了几行代码后想 push 到自己的远端执行git push origin master就会看到error: src refspec master does not match any error: failed to push some refs这个错误的原因很简单本地还没产生任何 commit甚至master分支根本不存在。正确做法是先接管版本管理cd fourier_neural_operator-master git init git add . git commit -m init from github zip git branch -M main git remote add origin 你的仓库地址 git push -u origin main如果项目要求主分支叫master就把-M main改成-M master。这个操作虽然跟 FNO 本身的算法无关但只要你打算基于这份代码二次开发越早纳入版本控制越好。2. 环境配置与依赖版本先让 FNO 跑起来再谈理解很多人的第一个挫败感来自装依赖。FNO 的代码不算大型项目但牵扯到 PyTorch、NumPy、SciPy还涉及数据生成脚本版本之间确实有兼容性问题。我建议严格按这两步来。2.1 Python 与 PyTorch 版本怎么搭配FNO 项目里大量使用 FFT 相关接口。旧版本的代码可能会直接调用torch.rfft但 PyTorch 从 1.8 开始把 FFT 接口搬到了torch.fft模块行为有细微差别。所以我个人的推荐组合是Python 3.8 或 3.9PyTorch 1.10 到 1.13 之间NumPy 1.21 到 1.23 之间如果你用了 Python 3.10 和最新版 PyTorch某些旧代码可能在torch.rfft上直接报AttributeError因为新版 PyTorch 删除了旧接口。解决办法有两个要么读代码把torch.rfft改成torch.fft.rfft要么装一个兼容版本的 PyTorch。我建议先根据仓库 README 里说明的版本装避免为环境问题浪费时间。创建虚拟环境是必须的别直接装在 base 环境里python3 -m venv fno_env source fno_env/bin/activate pip install --upgrade pip pip install torch1.13.0 pip install numpy scipy matplotlib2.2 requirements.txt 缺失的情况下按需补齐依赖有些版本的 FNO 仓库里没有requirements.txt。如果你碰到这种情况不要慌看import语句就能列出依赖。核心依赖其实就几个torchnumpyscipymatplotlibh5py如果数据处理用到了 HDF5生成数据的时候可能还需要pyDOE或者sobol_seq来生成采样点。如果运行generate_data.py报ModuleNotFoundError: No module named sobol_seq直接pip install sobol_seq即可。这类依赖一般不会太挑剔版本。2.3 数据集准备先看官方脚本再下载或生成FNO 经典实验是二维 Darcy Flow。训练数据是一组(输入系数场, 输出解场)的配对通常以.mat格式提供或者由generate_data.py生成。如果你下载的 zip 里带有data目录并且里面已经有.mat文件那么不需要额外生成直接训练即可。如果没有就运行python generate_data.py这个脚本会生成一个大的.mat文件可能包含 1000 组数据。生成速度取决于机器配置CPU 跑的话可能要几分钟到十几分钟。生成过程中不要关终端不然文件写到一半会损坏后面训练读数据时只会读到一堆 NaN。数据准备好后检查一下训练脚本里的DATAPATH或TRAIN_PATH变量不同版本的 FNO 命名不一样。常见的是TRAIN_PATH data/piececonst_r421_N1024_smooth1.mat TEST_PATH data/piececonst_r421_N1024_smooth2.mat如果你把.mat文件放在别的位置记得改路径否则会报FileNotFoundError或者更隐蔽地直接加载到错误文件。3. 核心代码拆解FourierLayer 到底做了什么训练流程怎么走环境配置好了数据也准备好了第一次训练可能会运行成功但很多人并不清楚模型内部是怎么设计的。我建议在跑训练之前先把fourier_2d.py打开读一遍因为这是整个 FNO 的核心。3.1 从 fourier_2d.py 看傅里叶层的本质Fourier Neural Operator 的核心思想是把神经网络的卷积过程放到傅里叶空间里做。卷积定理告诉我们空间域的卷积等价于频率域的逐点乘积。传统卷积在图像这类均匀网格上很自然但是面对 PDE 求解域的任意分辨率固定卷积核就不太好迁移。FNO 的做法是对输入特征图做快速傅里叶变换FFT在频域保留一组低阶傅里叶模式与一组可学习的复数权重相乘再反变换回空间域。代码中通常表现为一个自定义的FourierLayer类关键步骤大概是x_ft torch.fft.rfft2(x) # 二维 FFT out_ft self.complex_weight * x_ft # 频域加权 out torch.fft.irfft2(out_ft, s(x.size(-2), x.size(-1)))这里的complex_weight是模型的可学习参数形状一般是(in_channels, out_channels, height, width, 2)其中最后一维2表示复数的实部和虚部。你不需要手写复数运算PyTorch 会把最后一维为 2 的张量当作复数处理。理解这一步以后调模型的自由度就打开了傅里叶层保留多少频率可以用modes参数控制堆叠多少个傅里叶层可以用num_layers控制。modes越小相当于只保留低频信息模型更容易收敛但也可能丢掉高频细节modes越大参数越多训练越慢且更容易过拟合。3.2 训练脚本的数据流向以常见的train.py或train_2d.py为例训练流程大概是用scipy.io.loadmat加载.mat数据。把数据转换成 PyTorch 张量permute维度成(batch, channels, height, width)。构造DataLoader按batch_size迭代。定义模型、损失函数一般是相对 L2 损失和优化器通常用 Adam。每个 epoch 里做前向传播、计算损失、反向传播、更新参数定期在测试集上评估并保存模型。数据维度是新手最容易弄混的地方。Darcy Flow 的输入是(N, H, W)代表 N 个网格场但神经网络需要通道维所以要unsqueeze(1)变成(N, 1, H, W)。如果你错误地把数据维度传给模型经常会看到类似Expected 4D input的报错。这个时候不是改模型而是检查数据shape。3.3 快速实验时可以改哪些参数跑通默认训练之后你可以改这些参数来理解模型。我给一个我自己常用的调整方向表参数默认值调整建议batch_size16 或 32显存不够就减半收敛不稳也先减半learning_rate0.001误差震荡可以降为 0.0005modes12 或 16误差集中在该频率附近时增加一般不超过 20width64表达力不足时增加到 128同时注意显存epochs500不必等满观察验证误差提前停止每修改一个参数建议记录一组测试相对误差。FNO 在 Darcy Flow 上通常能到 0.01 以下的相对误差如果训练几百个 epoch 误差还下不来先别急着调参检查数据归一化和损失函数。4. 复现过程中的高频踩坑与排查思路这一节是我最想写的。从我自己的经验以及跟同行交流的情况来看FNO 项目卡住人的地方往往不是数学而是一些操作层面的问题。下面按出现频率排个序。4.1 invalid zip archive: could not find eocd 和下载半截文件这个问题我在第 1.1 节提过为什么还要单独拎出来因为很多人压缩包下载完成后解压到一半报错然后本能地去找修复工具。但could not find eocd几乎都是压缩包本身不完整修复工具能救回来的情况非常少见。如果你在公司内部网络下载可能是网络代理缓存了错误内容这时候删除本地文件换一个网络或者用浏览器的下载工具重新下载。另外一个类似的问题是解压时提示zip warning: not all files were readable通常是因为 zip 里有单个文件损坏或者是磁盘空间不足。先清理磁盘再重新解压到本地 SSD 上别直接在网络盘里解压大压缩包。4.2 CUDA out of memory 和 3D FNO二维 FNO 在普通显卡上问题不大但fourier_3d.py的显存消耗会突然上升一个级别。因为它把三维网格变换到频域后还要保留复数权重中间激活值非常多。报错通常是RuntimeError: CUDA out of memory. Tried to allocate ... MiB解决思路由轻到重减小batch_size例如从 8 减到 2。减小空间分辨率把数据下采样到64x64或32x32。减小modes和width。如果显存还是不够可以考虑混合精度。但要注意 FNO 的复数权重和 FFT 在 amp 模式下有兼容性问题实测在 PyTorch 1.13 上可以工作更老版本建议先别开。4.3 数据归一化误差一直不掉的真凶很多新手训练 FNO发现 loss 降得很快但测试误差很高或者误差曲线忽高忽低这通常跟数据归一化有关。原始 PDE 数据的量纲差异可能很大比如 Darcy 流里的渗透率场取值跨了几个数量级。如果不归一化模型在初始阶段会偏向数值大的特征导致训练不稳定。我在复现的时候习惯对输入和输出分别做 min-max 归一化并保存归一化的极值这样最终预测结果可以反归一化回物理单位。如果使用官方数据生成脚本通常数据已经是归一化过的但当你替换成自己的数据时必须自己处理。4.4 从 zip 快照开始的 Git 版本管理前面提过src refspec master does not match any error这里再补充一个场景你从 zip 解压后用git init和git commit建立了本地仓库但之后又直接从 GitHub 下载了新版 zip 覆盖了文件git 可能会显示很多deleted和modified。这不是代码坏了而是 zip 里的文件属性和时间戳变了。建议不要用 zip 覆盖的方式更新代码而是把新 zip 解压到临时目录对比差异后手动替换。更推荐的做法是先从 GitHub 用git clone拉仓库不仅后续git pull方便也可以保留原始提交历史对排查问题很有帮助。5. 把 FNO 迁移到自己的偏微分方程问题最后聊一聊怎么把这份项目迁移到自己的问题上。很多读者拿到 zip 并不是为了复现 Darcy Flow而是想做自己的研究或工程落地比如使用 FNO 做某些领域的参数估计、快速代理模型等。这部分我会给出一个相对通用化的流程。5.1 准备自建数据集的四个要点要让 FNO 解决你自己的 PDE 问题你至少需要准备一组有标签的数据输入是某个方程参数场输出是目标物理量解。处理成网络能吃的格式时注意四点数据格式统一为 NumPy 数组或.mat形状尽量对齐(N, H, W)。采样分辨率固定在一个分辨率训练否则 FNO 的网格相关操作会不匹配。数据切分训练集、验证集、测试集的划分要按物理工况分不能随机打乱混在一起否则会高估泛化能力。归一化记录训练集的统计量测试时用同一组统计量归一化。如果只有静态数据没有解析解可以用传统数值方法离线算一批数据。比如经典的应用是用 FNO 预测达西流场的解而数据来自有限差分求解器。做好离线数据管线比调模型参数更重要。5.2 监控哪些指标判断模型真的学对了训练时 loss 下降不代表模型学对了物理规律。我建议除了看相对 L2 损失还要看预测场的可视化。每训练一定轮次选几个测试样本把预测解、真实解和误差场画成三张子图。如果误差集中在边界或高频位置说明模型可能只学到了低频成分这时候增加modes或提高width可能更有用如果误差均匀分布但整体偏高大概率是数据量不够或者训练轮次不足。对于 PDE 问题还要注意守恒量。比如流动问题里的质量守恒如果模型预测的数值分布整体偏移即使相对误差不高物理上也是不可用的。这一点是纯图像领域训练经验很难覆盖的。5.3 后续可以扩展的方向FNO 是个起点很多人会在它的基础上加改进模块比如把傅里叶层和普通卷积层结合或者引入注意力机制。也有朋友把它跟强化学习、优化算法结合做快速 PDE 反演。扩展时不需要从零开发直接在这份 zip 代码上修改模型类就行这也是为什么我首先要强调把 Git 仓库建立起来因为每一次改动都能追踪。另外一个省钱小技巧如果暂时没有 GPU可以用 Google Colab 或 Kaggle Notebook 跑fourier_2d.py二维小规模数据用 CPU 也能跑只是慢很多。我自己最开始是在 MacBook 的 CPU 上跑通的花了几个小时但体验一遍完整流程后对模型的理解会深很多。这个 zip 只是入口真正值钱的是里面那几十个层的定义方式。先跑通再改最后移植到自己的问题上每一步的坑我都踩过希望这篇内容能让你少走一点弯路。如果你手头有一个具体的问题想用 FNO 试一试不妨先把默认的 Darcy Flow 跑通一次再替换成自己的数据这个顺序最稳。本文还有配套的精品资源点击获取