尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从RC电路到芯片热分析:用PyTorch理解物理信息神经网络PINN

从RC电路到芯片热分析:用PyTorch理解物理信息神经网络PINN 1. 为什么 RC 电路是理解 PINN 的最短路径去年我接到一个芯片热分析需求对方希望我不依赖商业热仿真软件也能快速给出芯片表面的温度分布趋势。我当时第一个想到的不是 Ansys、不是 Fluent而是一个早就听过但一直没真正动手跑过的词PINN。PINN 全称 Physics-Informed Neural Network中文常叫物理信息神经网络。说白了它不是在用一堆标签数据做拟合而是把微分方程本身当作训练信号让神经网络去逼近那个“看不见的解析解”。对我来说PINN 最大的问题是概念太多残差网络、自动微分、损失函数加权、边界条件硬约束……如果不写代码光看公式很容易产生一种“懂了但又没懂”的错觉。所以我的建议很直接从 RC 电路开始。RC 串联电路是电路分析里最基础的一阶动态电路电容电压随时间的暂态过程有解析解你随时可以拿 PINN 的结果和理论值对比。更重要的是RC 电路的数学形式极简单只有一阶常微分方程适合把 PINN 的完整套路讲清楚。这篇文章适合三类人第一听过 PINN 但不知道代码怎么落地的工程师第二想从电路或传热角度理解 PINN 的算法工程师第三准备做芯片热分析、想知道这套方法能不能上手的硬件从业者。我会用 Python 和 PyTorch 手写一个最小可用的 PINN再把同样思路扩展到二维热传导方程最后聊一聊我在实际项目中反复踩过的坑。这段代码不追求炫技每个环节你都能看清它在干什么。2. 先把 RC 电路方程翻译成神经网络损失2.1 控制方程和初始条件一个最简单的 RC 充电电路电阻 R 和电容 C 串联直流电源电压 V电容电压记为 u(t)。根据基尔霍夫电压定律回路方程是V R * i(t) u(t)而电容电流 i(t) C * du/dt代入后整理得到du/dt (V - u) / (R*C)R*C 就是时间常数 τ。假设电容初始电压为 0初始条件就是 u(0)0。这个方程有解析解u(t) V * (1 - exp(-t/τ))你要是只为了算这个电路用欧拉法、四阶龙格库塔法甚至直接套公式都行完全轮不到神经网络。但 PINN 的价值恰恰在于它把“解方程”这件事变成“最小化损失函数”这件事。一旦你会解这个方程后面换成非线性电阻、随温度变化的电容、甚至热传导偏微分方程套路都一样。2.2 PINN 的损失函数到底在算什么神经网络在这里的角色不是分类器也不是回归器而是一个“坐标到解的映射”。对于 RC 电路网络输入是时间 t输出是电压 u(t)。训练时没有现成的“输入-输出标签”真正的监督信号来自物理方程本身。第一项是微分方程残差loss_ode mean( (du/dt - (V - u)/τ)^2 )如果网络输出的 u(t) 是真实解那么 du/dt 和 (V-u)/τ 应该完全相等这一项应该为 0。第二项是初始条件残差loss_ic mean( (u(0) - 0)^2 )总损失就是两项的加权和loss loss_ode λ_ic * loss_ic训练的过程就是不断调整网络参数让这个损失降到最低。这里有个关键点du/dt 不是我手算的而是通过 PyTorch 的自动微分得到的。神经网络本身是参数化的函数对输入 t 求导完全可行。这也是 PINN 和普通监督学习最大的不同普通神经网络只要求输出接近标签而 PINN 还要求输出的一阶导数、二阶导数甚至偏导数满足物理方程。2.3 为什么我强烈建议先做无量纲化RC 电路的时间常数 τ R*C如果 R 取 1kΩC 取 1μFτ 就是 1ms。你如果直接把采样时间范围设在 0 到 5ms网络输入的数量级在 10⁻³ 左右。这种“小数值”会让第一层线性变换的输出很小梯度更新极不稳定训练半天 loss 纹丝不动。我的做法是先把时间轴做归一化。令 t* t/τ方程变成du/dt* 1 - u这样输入 t* 在 0 到 5 之间输出 u 在 0 到 1 之间网络需要处理的全是 O(1) 量级的数。这个习惯看起来不起眼但几乎所有 PINN 实战翻车案例都和量纲、单位、归一化有关。后面做芯片热分析时x、y 坐标、温度、热流密度各有各的量纲如果不先统一归一化损失的数值会被某一项主导另一个物理约束就等于白设。3. 30 行 PyTorch 代码跑通 RC 暂态3.1 先定义基础网络结构我习惯用最普通的全连接网络激活函数选 tanh。为什么是 tanh 而不是 ReLU因为 PINN 需要对输入求二阶甚至更高阶导数ReLU 在转折点处导数不连续二阶导基本为零会让网络很难表达光滑的物理场。tanh 处处光滑做微分方程残差更稳。import torch import torch.nn as nn class FCN(nn.Module): def __init__(self, n_input1, n_output1, n_hidden4, n_neurons64): super().__init__() layers [nn.Linear(n_input, n_neurons), nn.Tanh()] for _ in range(n_hidden - 1): layers [nn.Linear(n_neurons, n_neurons), nn.Tanh()] layers [nn.Linear(n_neurons, n_output)] self.net nn.Sequential(*layers) def forward(self, x): return self.net(x)这个网络没有引入任何电路信息。R、C、V 参数不会写进网络结构它们只出现在损失函数里。这意味着同一个网络结构可以解完全不同的方程你只需要更换损失函数。3.2 训练循环接下来写训练主循环。这里我使用随机采样的配点法每个 batch 在时间区间 [0, 5τ] 内重新采样一批时间点而不是提前固定一份训练集。这样做的好处是网络每轮看到的点都在变化不容易在一个固定网格上过拟合。R 1e3 C 1e-6 V 1.0 tau R * C model FCN(1, 1, n_hidden4, n_neurons64) optimizer torch.optim.Adam(model.parameters(), lr1e-3) t0 torch.zeros((1, 1)) u0 torch.zeros((1, 1)) for step in range(30000): optimizer.zero_grad() # 在无量纲时间 [0, 5] 内随机采样 t_star torch.rand(256, 1) * 5.0 t_star.requires_grad_(True) # t t_star * tau实际物理时间 u_pred model(t_star) # 自动求 du/dt_star u_t torch.autograd.grad( u_pred, t_star, grad_outputstorch.ones_like(u_pred), create_graphTrue )[0] # 方程残差du/dt* V - u 这里 V1无量纲化后是 1 - u ode_residual u_t - (V - u_pred) # 初始条件 u0_pred model(torch.zeros((1, 1))) ic_residual u0_pred - 0.0 loss_ode ode_residual.square().mean() loss_ic ic_residual.square().mean() loss loss_ode 500 * loss_ic loss.backward() optimizer.step() if step % 5000 0: print(fstep {step}, loss {loss.item():.3e})我在这里给初始条件损失加了 500 的权重。为什么因为配点法随机采的时间点绝大多数在区间中部初始点只占极小比例如果不放大权重网络很容易牺牲 t0 附近的精度。你可以把 500 换成 1 试试会看到早期 loss 下降很快但最终电压曲线在起点附近会出现明显的偏置。3.3 结果验证和 MATLAB 的对应做法训练结束后在 [0, 5τ] 上密集采样把网络预测值和解析解画在一起最大相对误差通常在 1% 以内。如果你想把这段逻辑搬到 MATLAB思路完全一样用dlarray包装输入用dlgradient对网络输出求导再和你手写的方程残差一起放入dlfeval。MATLAB 的深度学习工具箱虽然不像 PyTorch 那么自由但 PINN 的骨架就是“前向计算 自动微分 损失下降”语言差异不会改变核心机制。有一点我要提醒你RC 电路在频域里对应一阶低通滤波器幅频特性是 1/sqrt(1(ωRC)²)。如果你要算正弦稳态响应直接用相量法比 PINN 快得多。PINN 真正有价值的地方不是替代这些成熟方法而是处理那些“边界条件复杂、方程非线性、甚至参数未知”的问题。4. 从一阶 ODE 到热传导 PDE难度不在维度在约束4.1 方程形式的变化RC 电路只有一个自变量 t输出是 u(t)这是一阶常微分方程。芯片热分析的核心方程则是热传导方程。以二维非稳态为例ρ * c * ∂T/∂t k * (∂²T/∂x² ∂²T/∂y²) Q其中 T 是温度ρ 是密度c 是比热容k 是导热系数Q 是单位体积的发热率。如果只看稳态也就是温度不再随时间变化方程退化为k * (∂²T/∂x² ∂²T/∂y²) Q 0这就是泊松方程。在 PINN 里你只需要把网络输入从一维的 t 改成二维的 (x, y)输出从电压 u 改成温度 T再把损失函数从 ODE 残差换成 PDE 残差。这里有个新手特别容易误判的地方从一维到二维网络结构本身几乎不用改真正难的是约束条件。RC 电路只需要一个初始条件而热传导问题必须有完整的边界条件。边界条件少一条方程的解就可能不唯一网络就会在无数个“看起来合理”的温度场里随机游走。4.2 三类边界条件先分清热分析中常见的边界条件大致分三类第一类叫 Dirichlet 条件直接给定边界温度比如芯片底部固定 350K。第二类叫 Neumann 条件给定边界热流密度比如某个面有恒定热流 q写成 k * ∂T/∂n q。第三类叫 Robin 条件也是最常见的对流换热条件高温表面向环境散热的边界写成 k * ∂T/∂n h * (T - T_amb) 0h 是对流换热系数。PINN 处理边界约束有两种思路。一种是软约束把边界残差像初始条件一样作为损失项加进去实现简单但要调权重。另一种是硬约束通过修改网络输出结构让边界条件自动满足比如 RC 电路可以令 u(t) t * f(t) 来保证 u(0)0。实际工程中我大部分情况先用软约束跑通再去优化硬约束因为复杂几何边界下构造硬约束本身就很费劲。4.3 RC 电路和芯片传热有什么对应关系我把两者的要素列一个表方便你建立直觉维度RC 暂态芯片热传导控制方程一阶 ODE热传导 PDE自变量时间 t空间 x,y瞬态再加时间 t未知量电容电压 u(t)温度场 T(x,y)约束类型初始条件边界条件瞬态再加初始条件典型材料参数R, C, τk, ρc, hPINN 输入一个坐标两个或三个坐标这张表也说明一个问题PINN 不是“一种算法对应一个领域”而是“一套物理约束框架适配不同方程”。你只要能把物理规律写成残差不管是电路、流体还是热传导训练逻辑都是一样的。5. 芯片热分析实战二维稳态热传导 PINN5.1 问题设定和归一化我们把问题简化成一个 10mm × 10mm 的芯片平面内部均匀发热底部边界固定温度 350K其余边界绝热。这个设定虽然离真实芯片封装还有距离但足够展示 PINN 的完整流程。几何尺寸、导热系数、发热率都有量纲直接代入会引发上一节说的数值问题。所以我的习惯是先做一次彻底的无量纲化。令 x* x/Ly* y/L其中 L 是芯片边长令 T_norm (T - T_ref) / T_scale其中 T_ref 取边界温度T_scale 取一个预估温差。方程就变成∂²u/∂x*² ∂²u/∂y*² Q_norm 0Q_norm 是折算后的无量纲热源。这样网络输入输出都在 0 附近波动训练稳定很多。5.2 二维热传导 PINN 代码骨架class HeatPINN(nn.Module): def __init__(self): super().__init__() self.net nn.Sequential( nn.Linear(2, 64), nn.Tanh(), nn.Linear(64, 64), nn.Tanh(), nn.Linear(64, 64), nn.Tanh(), nn.Linear(64, 1) ) def forward(self, x): return self.net(x) def pde_residual(model, x, y, Q_norm): x.requires_grad_(True) y.requires_grad_(True) T model(torch.cat([x, y], dim1)) T_x torch.autograd.grad( T, x, grad_outputstorch.ones_like(T), create_graphTrue )[0] T_y torch.autograd.grad( T, y, grad_outputstorch.ones_like(T), create_graphTrue )[0] T_xx torch.autograd.grad( T_x, x, grad_outputstorch.ones_like(T_x), create_graphTrue )[0] T_yy torch.autograd.grad( T_y, y, grad_outputstorch.ones_like(T_y), create_graphTrue )[0] residual T_xx T_yy Q_norm return residual边界损失按四条边分别采样# 四条边各采 64 个点温度设为 0归一化后 n_b 64 left_x torch.zeros(n_b, 1) left_y torch.rand(n_b, 1) right_x torch.ones(n_b, 1) right_y torch.rand(n_b, 1) bottom_x torch.rand(n_b, 1) bottom_y torch.zeros(n_b, 1) top_x torch.rand(n_b, 1) top_y torch.ones(n_b, 1) b_x torch.cat([left_x, right_x, bottom_x, top_x]) b_y torch.cat([left_y, right_y, bottom_y, top_y]) T_boundary model(torch.cat([b_x, b_y], dim1)) bc_loss T_boundary.square().mean()内部残差点在单位正方形里随机采样数量可以比边界点多一些比如 1024 个点一个 batch。每一轮迭代都重新采样避免网络只在固定网格上记住解。5.3 训练结果里应该看到什么如果设置 Q_norm 为一个正值温度场应该在芯片中心区域偏高边界附近被拉回 0因为底部和四周都有固定温度约束。训练几万步后你可以把温度场画成等高线或热力图中心热点位置和半解析解对得上就说明 PINN 基本学对了。这里有一个很常见的训练现象PDE 残差继续下降但边界损失卡在一个平台期。原因往往是边界点在总损失中的占比太低网络宁可牺牲边界精度也要满足大量内部配点的方程残差。我的对策是给边界损失设置一个 50 到 200 的权重并且每 5000 步检查一次边界上的最大误差而不是只看总 loss。6. 我在 PINN 实战里反复踩的五个坑6.1 单位没有归一化损失像过山车这是我最常犯的错误。RC 电路里时间单位是毫秒芯片热分析里长度单位是毫米、温度单位是开尔文、热导率单位是 W/(m·K)把这些原始数值直接喂给神经网络各项损失的尺度能差好几个数量级。大的项把梯度方向带偏小的项彻底失去存在感。解决方式只有一个在进入网络之前做坐标缩放在输出之后做反缩放。不要相信网络“自己能适应”它没有量纲概念它只知道数字大就是大。6.2 激活函数选 ReLU二阶导直接报废如果你用 ReLU 做热传导 PINN会发现 loss 能降但温度场非常粗糙甚至出现直线段。原因很简单ReLU 的非线性集中在转折点其导数在大部分区域是常数二阶导几乎处处为 0。热传导方程需要二阶导等于让一个“不懂曲率”的函数去拟合物理场自然不对。我推荐的激活函数首先是 tanh其次是 sin 或 Swish 这类光滑激活函数。sin 在周期性问题上表现好但工程问题里预热不稳定tanh 最稳适用范围最广。6.3 初始条件和边界条件的权重不是随便定的PINN 的损失是多个物理约束的加权和权重很影响最终解的平衡。举个例子在 RC 电路里如果你只采一个 t0 作为初始条件而内部配点有上千个初始条件在总损失里的贡献微乎其微最终曲线可能整体平移完全不满足初始电压。我的经验是先用一个量级判断分别单独输出 ode_loss 和 ic_loss看哪一项数量级大再把权重调到让它们对梯度更新的贡献接近。不要盯着总 loss要看每一项的分量。6.4 配点总是一堆随机数热点区域永远采不到随机采样的配点法简单但有个问题方程解在局部变化剧烈的地方需要更多采样点。比如芯片热点区域温度梯度很大随机采样点落在里面的概率可能只有百分之几网络就会把热点细节抹平。进阶做法是自适应采样每训练一定步数用当前网络计算各点的 PDE 残差残差大的区域多放点。这个逻辑很像有限元里的网格加密只是换成在配点密度上做文章。小规模问题先不加但如果你的热源很集中建议尽早用。6.5 不要拿 PINN 硬刚商业求解器说实话纯正向求解、几何规则、网格易生成的芯片热问题用传统有限元或有限差分又快又准PINN 未必有优势。PINN 真正能打的地方是反问题你只有少数几个温度测点想反推热导率、接触热阻或芯片内部热源位置或者你做参数化设计需要快速评估大量不同工况而不是每个工况都重新建模。所以我在项目里的定位是把 PINN 当做一个“可微分的求解器”和“可逆向的仿真代理”而不是替代 Ansys/Fluent 的通用工具。这句话听起来不酷但能帮你少走很多弯路。7. 从 RC 到芯片这套代码还能一路走到哪7.1 瞬态热分析和反问题如果你把时间也当成网络的一个输入输出变成 T(x, y, t)损失函数里再加上时间偏导项就能做瞬态热分析。芯片在动态负载下的温度波动、开关瞬间的热冲击、脉冲功率下的温升曲线都能套进这个框架。更值钱的是反问题。假设芯片内部热源分布未知但你用红外热像仪或热电偶测到了表面温度你可以把这些测量值作为额外的数据损失同时保留热传导方程残差训练出的网络就能反推未知热源强度。这个能力是传统求解器很难做到的因为传统方法通常只能“给定参数算出温度”很难反过来把参数当未知数一起迭代。7.2 实际项目里我会不会手写这套代码不会每次都手写。手写代码的意义是搞懂机制让你在调参时不至于两眼一抹黑。一旦问题规模变大几何变得复杂我会直接用 DeepXDE 这类成熟 PINN 框架。DeepXDE 已经把配点生成、边界条件、损失函数组装都封装好了你只要告诉它几何区域、方程表达式和边界类型就能快速搭建模型。但我仍然建议你先亲手跑一遍 RC 电路的 PINN原因很朴素只有亲手写出从“方程”到“损失”到“训练”的转换过程你才知道框架里那些 API 背后发生了什么。芯片热分析涉及多材料、非线性边界、复杂几何这些问题任何一个都会把 PINN 的调试周期拉得很长没有基本功会很痛苦。7.3 我在实际使用里的最终建议以我现在做项目的习惯我会先用本文这种最小化 PINN 验证物理模型再逐步往里面加材料参数、加边界条件。每加一项我都会和解析解或传统仿真结果对一次确保新引入的物理项没有把前面的解带偏。从 RC 电路到芯片热分析不是一个“替代关系”而是一条从简到繁、从能跑到能用的路。这条路的起点很小但练熟了之后你会发现“用方程约束神经网络”这个思路远比某个具体算例本身值钱。
返回列表