我第一次真正动手写物理信息神经网络PINN的多变量回归预测项目是在一个温度场多点预测的任务里。当时手里只有少量传感器数据输出又是一个单变量换成普通BP网络或RBF网络都能把已有样本拟合得很平可一预测未采样位置的温度曲线就开始振荡。后来我把控制方程作为约束塞进损失函数结果截然不同。这篇不聊太虚的概念就围绕“多输入单输出”这个场景讲清楚PINN怎么设计损失、怎么在MATLAB里写训练循环以及我在跑通之后踩过的几个坑。1. PINN的回归预测思路数据驱动和物理约束怎么凑到一起1.1 从普通回归网络到带物理方程的损失函数传统回归网络的核心逻辑很直接给网络足够多的“输入-输出”样本让它通过梯度下降记住输入到输出的映射。这个思路在数据充足、分布均匀的时候没问题可一旦数据稀疏或者你要预测的位置超出了训练样本的覆盖范围神经网络就会暴露出一个毛病——它只懂拟合不懂物理。就像教一个孩子背乘法表却没教他乘法的含义换个数就懵。PINN的做法是在网络输出之外额外要求“输出必须满足一组物理方程”。比如你做稳态温度场预测温度分布应该满足热传导方程做流体速度场预测速度场应该满足连续性方程和动量方程。网络可以随便猜一个输出但如果这个输出不满足物理方程损失函数就会变大优化器就会把它往“物理上可解释”的方向拉。这等于给回归网络上了一道紧箍咒。正因为多了这道紧箍咒PINN在训练数据少、噪声大的场景下往往比普通回归网络更稳。它不是用样本点硬插值而是用物理方程约束网络在整体求解域内做出合理的连续预测。这也是为什么PINN明明用了和普通前馈网络几乎一样的骨架却能做出传统方法做不出的外推效果。1.2 适合用PINN的多输入单输出问题长什么样并不是所有回归问题都适合用PINN。最典型的一类问题是“场量预测”输入是空间坐标、时间、材料参数等若干变量输出是一个物理标量。举例来说二维稳态热传导问题中输入可以是横坐标x和纵坐标y输出是温度T控制方程为-∂²T/∂x² - ∂²T/∂y² f(x, y)其中f是热源项。给定边界条件和少量内部测点目标是把整个区域内的温度场T(x,y)回归出来。这就是一个非常标准的多输入单输出问题输入个数是2输出个数是1。还可以把输入维度扩展比如再加一个热源强度参数α输入变成(x, y, α)输出依然是T物理方程里出现α作为系数网络就要同时学会“空间分布”和“参数变化”两层规律。这类问题用纯数据驱动网络很难泛化因为不同α对应的温度场差异可能很大数据稍微稀疏就会学歪但PINN知道所有α都必须满足同一个控制方程所以它会在满足方程的解空间中寻找符合数据的组合。当然更广义的多输入单输出回归也能用PINN只要存在一个可微分的代数/微分关系约束输出即可。如果没有物理方程只有“输出变化比较平滑”这种抽象先验那PINN的优势就不明显。1.3 损失函数的三部分数据项、控制方程项、边界条件项PINN的损失函数比普通回归网络多两项一般写成Loss L_data λ_eq * L_eq λ_bc * L_bcL_data就是常规的回归损失比如均方误差MSE用来衡量网络输出和实测样本的差距。L_eq是控制方程残差它计算的是把网络输出代入物理方程后的“不平衡量”。如果网络输出完全满足控制方程这一项应该等于零。L_bc是边界或初始条件损失用来强制解落在物理问题对应的唯一解上。为什么要边界条件项因为很多偏微分方程的解不是唯一的同一个方程可以对应无数个温度场只有加上边界条件才能锁定唯一解。PINN在求解域内采样配置点同时也要在边界上采样让网络不仅内部满足方程边界还满足给定约束。实际操作中我会把这三项分开记录到训练日志里而不是只看总损失。如果L_eq降得很慢说明配置点采样或权重设置有问题如果L_bc降不下去多半是边界位置没采够。2. 多输入单输出的网络结构和训练策略设计2.1 网络结构宽度深度激活函数怎么选PINN的骨架通常是全连接前馈网络我常用的结构是输入层节点数等于输入变量个数中间3到5层全连接层每层20到50个神经元输出层1个节点。对于线性温度场这类较光滑的问题3个隐藏层、每层24个神经元已经够用如果输出函数有陡峭变化或间断再考虑增加深度或宽度。激活函数是最容易踩雷的地方。我在早期版本里图省事用过ReLU结果物理残差项几乎学不动。原因很简单ReLU是分段线性函数它的二阶导数在绝大部分区域等于零而很多物理方程恰好包含二阶导数项比如热传导方程里的∂²T/∂x²。网络无法从ReLU里拿到二阶导的有效梯度物理约束就形同虚设。PINN里更常用的是tanh、swish、softplus这类光滑激活函数二阶导不为零且处处可微。就我的经验tanh在小规模PINN里最稳收敛速度和精度都不错。另外可以在全连接层之间加残差连接把上一层的输出直接加到后面某一层输入上。这不是必须的但当网络加深时残差连接能明显减轻梯度消失问题。MATLAB里如果手写前向传播可以用加运算实现用dlnetwork时则需要自定义层代码会复杂一些。如果问题规模不大不加残差连接完全跑得动没必要一开始就上高阶操作。2.2 输入归一化与物理量纲处理做PINN不能只归一化数据就完事还要把物理方程也“无量纲化”一遍。很多第一次接触PINN的人会忽略这个步骤结果损失函数好几项量级天差地别梯度更新就被大数值的项带跑了。我在处理实际数据时先把每个输入特征归一化到[-1, 1]或[0, 1]区间输出Target也做类似缩放让网络输出的目标值大致在O(1)量级。接着检查控制方程如果x、y坐标被缩放了导数项的量级也会跟着变方程里的系数必须重新推导。比如坐标从物理域[0, L]缩放到[0, 1]那∂²T/∂x²前面会出现1/L²的因子写残差时不能漏掉。边界条件也要跟着缩放。如果只归一化输入却忘了改方程网络可能拼命去拟合数据点而物理残差项始终降不下来因为方程本身写错了一个尺度系数。这种错误非常隐蔽损失曲线看起来在下降实际预测结果却一塌糊涂。遇到PINN训练完但结果离谱时我第一步就会检查无量纲化后的方程系数是不是和坐标缩放完全匹配。2.3 损失权重平衡和课程式训练控制方程项和边界条件项前面的权重λ怎么定是PINN训练中最玄学的问题之一。λ_eq太小物理约束形同虚设λ_eq太大网络只顾满足方程完全不看实测数据变成纯数值模拟器。固定权重不是不行但对不同问题很难一次调好。我常用的做法是课程式训练第一阶段先只跑数据项让网络先大致拟合样本点第二阶段加入控制方程项并给一个较大的λ_eq第三阶段再加入边界项调整λ_bc。这很像人学习时先看例题、再记公式、后背边界条件。好处是前期的梯度方向主要由数据主导网络不容易在训练初期就钻进某个满足方程但不拟合数据的解。还有一种更动态的做法是根据各项损失的梯度范数去自动分配权重。损失大的项不一定需要更大的权重关键看它对网络参数的梯度量级。如果L_eq对参数的梯度一直很小说明网络对这个约束不敏感这时候光调λ没用要检查网络结构、激活函数或方程是否无量纲化。权重平衡的本质是让三股梯度方向在总损失中保持可比的量级。2.4 采样点和批大小怎么配合PINN里除了真实数据样本还有一类“配置点”。这些点没有标签不参与数据损失只在物理残差里参与计算。配置点的位置非常影响训练效果。我最早图省事把配置点全撒在定义域网格上结果网格结点过密的地方学得好网格稀疏区域完全靠猜。后来统一改用拉丁超立方采样保证配置点在各个维度上均匀分布效果明显更好。训练时不需要把所有配置点一次性加载进去每轮随机抽取几百到几千个点即可。数据点和配置点可以放进同一个batch也可以分开计算后合并损失。分开计算更清晰我会在同一个训练迭代里先用数据点算L_data再从配置点里随机抽一批算L_eq边界点算L_bc最后求加权和。批大小方面如果配置点太多每次前向计算和二阶自动微分都很吃内存如果太少物理残差的噪声又太大。我的经验是配置点每批500到2000个数据点每批几十个就够。反正每轮迭代都会重新随机采样配置点相当于给网络“换题”训练比固定一批点训练到底要稳得多。3. MATLAB里的PINN实现网络、自动微分与训练循环3.1 用深度学习工具箱把网络搭起来MATLAB里做PINN主要靠深度学习工具箱的自动微分能力对应的核心函数是dlarray、dlgradient和dlfeval。神经网络的骨架可以用dlnetwork定义也可以用自定义网络结构。下面是我常用的一个极简版本适合二维输入、单输出的问题layers [ featureInputLayer(2, Name, in) fullyConnectedLayer(24, Name, fc1) tanhLayer(Name, tanh1) fullyConnectedLayer(24, Name, fc2) tanhLayer(Name, tanh2) fullyConnectedLayer(24, Name, fc3) tanhLayer(Name, tanh3) fullyConnectedLayer(1, Name, out) ]; dlnet dlnetwork(layers);代码里第一层是2个特征输入对应(x, y)最后一层是1个输出对应T。中间全部用tanh激活就是为了保证二阶导数不为零。如果你要处理3个输入变量把featureInputLayer(2)改成featureInputLayer(3)就行后面的全连接层不用改。3.2 自动微分和物理残差的计算MATLAB里求导数的入口是dlgradient它必须在dlfeval定义的函数里调用而且参与运算的变量必须是dlarray类型。计算物理残差时我们要对网络输出T连续求两次导数比如求解∂²T/∂x²需要先求T对x的一阶导再对一阶导结果求一次梯度。由于dlgradient要求末位输出尽量是标量我可以逐样本计算物理残差。这里贴一段核心损失函数骨架代码可读性优先性能上还能继续优化function [lossData, lossPDE] computeLosses(dlnet, xData, yData, TData, xPde, yPde) % 数据点上的回归损失 uData cat(1, xData, yData); TDataPred forward(dlnet, uData); lossData mse(TDataPred, TData); % 配置点上的物理方程残差 Npde size(xPde, 2); resVec dlarray(zeros(1, Npde)); for i 1:Npde x_i xPde(:, i); y_i yPde(:, i); u_i cat(1, x_i, y_i); T_i forward(dlnet, u_i); T_i sum(T_i, all); % 转为标量 % 一阶导 dTdx dlgradient(T_i, x_i); dTdy dlgradient(T_i, y_i); % 二阶导 d2Tdx2 dlgradient(sum(dTdx, all), x_i); d2Tdy2 dlgradient(sum(dTdy, all), y_i); % 以热传导方程 -∇^2 T f 为例 fxy sourceFunction(x_i, y_i); resVec(i) (-d2Tdx2 - d2Tdy2 - fxy)^2; end lossPDE mean(resVec); end function f sourceFunction(x, y) % 这里对应解析解 T sin(pi*x) * sin(pi*y) % 此时 -∇^2 T 2 * pi^2 * T f(x,y) f 2 * pi^2 * sin(pi * x) .* sin(pi * y); end这个循环写法比较直观缺点是对每个配置点都要单独做一次前向和自动微分配置点一多训练速度就会变慢。我实际跑案例时会把配置点分组并行处理或者用向量化技巧减少循环次数但新手先从循环版改起逻辑更清楚。3.3 自定义训练循环Adam优化器和权重更新PINN没有现成的训练接口必须手写训练循环。下面是一个可以直接改的骨架核心是dlfeval计算损失和梯度再用adamupdate更新网络可学习参数。function [grads, lossTotal] modelGradients(dlnet, xData, yData, TData, xPde, yPde, lambdaPDE) [lossData, lossPDE] computeLosses(dlnet, xData, yData, TData, xPde, yPde); lossTotal lossData lambdaPDE * lossPDE; grads dlgradient(lossTotal, dlnet.Learnables); end训练主循环类似这样learningRate 1e-3; lambdaPDE 1.0; maxIters 3000; avgG []; avgS []; for iter 1:maxIters [xPdeBatch, yPdeBatch] sampleConfigurationPoints(600); [grads, lossTotal] dlfeval(modelGradients, dlnet, xData, yData, TData, xPdeBatch, yPdeBatch, lambdaPDE); [dlnet, avgG, avgS] adamupdate(dlnet, grads, avgG, avgS, iter, learningRate); if mod(iter, 200) 0 fprintf(iter %d, loss %.4e\n, iter, extractdata(lossTotal)); end end采样配置点的函数可以写成function [xPde, yPde] sampleConfigurationPoints(N) xPde dlarray(rand(1, N), CB); yPde dlarray(rand(1, N), CB); endadamupdate会自动维护一阶动量和二阶动量前两次调用时传入空的avgG和avgS即可。我一般会把lossData、lossPDE和lossBC分别打印出来观察三个损失有没有同步下降。如果某一项长期不变说明对应约束没有真正进入梯度路径。3.4 训练选项和早停判断PINN的训练比普通回归网络更需要耐心观察。学习率我通常从1e-3起步训练到中段如果损失不再下降就降到1e-4。优化器推荐Adam它对多目标损失的稳定性更好想追求精度时再切到SGDM做后期精调。早停不要只盯总损失。有时候总损失在降但物理残差还很大预测曲线也扭曲。我会额外准备一个测试集比如在区域里均匀取一些真值点每训练几百轮算一次相对L2误差等这个误差饱和再停。PINN的一个优势是可以不依赖大量标签数据所以训练集和测试集不必严格来自同分布但配置点必须覆盖你真正关心的预测区域。4. 我踩过的坑收敛慢、预测失真和边界漂移4.1 激活函数选ReLU二阶导直接归零这个坑我在前面已经提醒过但还是想单独再说一遍因为它最容易让PINN初学者浪费两三天。ReLU在x0时是y x在x0时是0二阶导几乎处处是0。热传导方程这类含二阶导的PDE残差里根本取不到有效梯度网络只能靠数据项和边界项闷头训练最终结果看起来像是一根根首尾相连的折线光滑性很差。换成tanh之后残差项才开始正常下降。如果你实在想保留ReLU的稀疏性可以在输出层之前改用swish这类有光滑导数且非饱和的激活函数。不过从省心程度上讲纯tanh网络对小规模PINN最不容易出问题。4.2 数据没有归一化物理残差尺度失衡有次我处理一个温度范围在300到500K的热传导问题坐标范围是0到0.1米结果网络训练了上千轮L_eq始终稳定在一个大数值附近。排查后发现输入坐标x本身是0.01量级输出T是几百量级一阶导量级就差了四五个数量级MSE数据的量级也完全压过方程残差。后来我把坐标乘上缩放系数归一化到0到1T也先减去均值再除以标准差重新推导了方程里的系数问题立刻解决。现在我的习惯是所有输入输出统一标定到[-1, 1]或[0, 1]然后写一个专门的无量纲化参数表每次改物理方程都要同步更新这个表。这一步看起来不起眼却能省下大量调参时间。4.3 配置点总在边界聚集内部区域学不进去另一个隐蔽问题是配置点采样偏了。如果配置点是从规则网格里取的而且网格节点在边界处更多网络就会在边界附近学到很多物理约束内部区域却因为配置点稀疏而缺乏约束。这样会导致训练损失不高但内部场预测误差很大。我现在统一用拉丁超立方采样配置点并且会额外在边界上单独采样一批点。这样控制方程残差主要约束内部区域边界条件单独由边界点去管两个任务的分工不会糊在一起。如果你发现L_bc一直很小、L_eq却下不去可以先画一下配置点分布图确认它是否覆盖了整个求解域。4.4 外推区域过拟合只在配置点范围内有效PINN的外推能力不是无限大的。很多宣传材料拿PINN的“外推”说事实际是指在配置点覆盖的求解域内网络能给出比普通插值更合理的预测一旦跑到配置点覆盖范围之外网络同样可能放飞自我。我在一次参数变化实验里只在某个参数区间内采样配置点换到区间外测试预测误差大得离谱。解决办法很简单把你想预测的区域也纳入配置点采样范围。如果想预测宽泛的参数区间就按区间均匀采样配置点如果只能提供少量离散数据那至少要让物理方程在目标区域内有约束网络才不会完全脱离物理规律瞎猜。4.5 损失降不下去先看权重和初始值如果调了学习率、换了激活函数、修正了归一化总损失还是卡在平台上我一般会检查lambda权重和网络初始化。lambdaPDE取得太小会让物理项变成噪声取太大会让网络不敢拟合数据点。我的做法是先把lambda放小优先让数据项降到接近预期水平再把lambda逐级增大。另外PINN对网络初始值比普通回归更敏感因为损失函数是多目标叠加优化风景更崎岖。同一个网络结构换一个随机种子训练结果可能差不少。遇到损失不降的时候我会连续试5个随机种子取验证误差最小的模型。不要迷信“只要调学习率就能解决”多换几个初始点成本更低。5. 一个可复现的小型验证案例二维热源场的多输入单输出回归5.1 构造一个精确解和采样方案为了从头到尾看效果我常拿一个带解析解的问题做验证。取区域[0,1]×[0,1]方程是-∂²T/∂x² - ∂²T/∂y² 2π² sin(πx) sin(πy)解析解是 T sin(πx) sin(πy)边界上T0。输入是(x,y)输出是T。这样我可以随时生成大量真值作为测试基准不会受真实测量误差干扰。训练数据从区域内部随机取40个点边界上再取100个点作为带标签样本配置点每轮随机抽600个额外在四条边界上每轮抽50个点算边界残差。网络结构按前面说的3层隐藏层、每层24个神经元lambdaPDE先从0.1开始训练到数据项稳定后提到1.0。5.2 用少量带噪数据训练看PINN和纯网络的区别我做了个对照组一个普通全连接网络只用那140个带标签样本训练一个PINN同样用这些样本但额外加入物理方程残差。在无噪声情况下普通网络在训练点附近拟合得很好可一旦取未采样点测试误差立刻放大因为网络没有能力推断边界之间“应该是什么样”。PINN因为在每个配置点都被物理方程约束学会的温度场在整体上满足热传导规律。即使训练样本很少它也能预测出中间区域的高温峰空间分布也更接近解析解。用相对L2误差来衡量普通网络在未采样点上的误差明显高于PINN尤其在训练点数量低于30的时候普通网络几乎丧失了泛化能力。5.3 误差和鲁棒性数据量从10到50的变化我统计了一组不同训练数据量下的对比结果趋势大致如下带标签数据点数普通网络相对L2误差PINN相对L2误差1023.7%3.6%2015.4%2.3%3011.2%1.9%506.8%1.4%这只是单组随机种子下的结果但规律非常稳定随着样本量增多普通网络误差在下滑PINN的误差也在下滑但PINN从很低样本量开始就保持明显优势。更值得注意的是在数据点中加入少量高斯噪声后普通网络很容易过拟合噪声误差反弹PINN因为有物理方程的约束相当于自带正则化预测曲线依然光滑误差增长幅度小很多。如果你手头数据量连20个都不到我建议优先考虑PINN只要物理方程相对可靠效果通常不会差到哪里去。反过来如果你已经有上千个高质量样本物理约束的边际收益会下降此时简单神经网络加正则化可能更省事。5.4 后续扩展把热源参数也作为输入上面这个案例的输入只有坐标(x, y)。实际工程里我们常常想知道“在不同热源强度或不同材料参数下温度场怎么变化”。这时可以把热源强度α也作为输入网络输出T(x, y, α)物理方程中对应含有α的项。训练数据来自几个不同α工况的少量测点配置点在(x, y, α)三维空间里采样PINN学到的就不再是单纯一张温度场而是一族满足方程的温度场。更进一步还可以把某些未知参数加入待优化变量用PINN做参数辨识。比如已知部分测点温度但不知道热源强度可以让网络输出T的同时把α当成额外可学习参数和网络权重一起训练。这种“回归反演”的组合是PINN最有想象力的方向也是我在后续项目里打算继续折腾的内容。最后再分享一个实操体会PINN的调试周期往往比普通神经网络长但绝大多数问题都出在“没有把物理方程和网络结构、数据尺度放在同一套体系里”。我后来养成了每次训练前先写一页纸的“问题定义”把输入变量、输出变量、控制方程、无量纲化系数、边界条件、采样区域全部列清楚。宁可花半小时做这一步也不要在训练半天后才发现是方程系数写错。如果你正准备用MATLAB去跑自己的PINN回归任务建议你也从一个小规模、有解析解的算例开始把每个损失分项都看明白再上真实数据整个过程会顺畅很多。
阅读完成 · 觉得有帮助?