主题065:物理信息神经网络(PINN)求解热方程

Physics-Informed Neural Networks for Solving Heat Conduction Equations


一、引言

1.1 背景与动机

在工程仿真领域,热传导问题的数值求解一直是一个核心课题。传统的数值方法,如有限差分法(FDM)、有限元法(FEM)和有限体积法(FVM),虽然在工程实践中取得了巨大成功,但它们也面临着一些固有的挑战:网格生成复杂、高维问题"维度灾难"、逆问题求解困难等。

近年来,深度学习技术的飞速发展为科学计算带来了新的范式。物理信息神经网络(Physics-Informed Neural Networks, PINN) 作为一种融合物理定律与数据驱动的方法,正在 revolutionize 我们求解偏微分方程(PDE)的方式。PINN 的核心思想是将物理方程作为约束嵌入神经网络的损失函数中,使得网络在拟合数据的同时,严格满足物理定律。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 什么是 PINN?

PINN 是由 Raissi 等人于 2019 年系统提出的一种深度学习方法。其基本框架包含三个关键要素:

  1. 神经网络近似:使用深度神经网络 NN(x,t;θ)NN(x, t; \theta)NN(x,t;θ) 来近似未知函数 u(x,t)u(x, t)u(x,t)
  2. 自动微分求导:利用深度学习框架(如 PyTorch、TensorFlow)的自动微分功能,计算网络输出的各阶导数
  3. 物理约束损失:将 PDE 残差、初始条件和边界条件纳入损失函数

1.3 PINN 的优势

相比传统数值方法,PINN 具有以下显著优势:

特性 传统方法 PINN
网格需求 需要离散网格 无网格,连续解
维度扩展 维度灾难 高维问题友好
逆问题 需要迭代求解 端到端求解
数据融合 难以结合实验数据 自然融合数据与物理
计算效率 单次求解快 训练慢,推理快

1.4 本教程学习目标

通过本教程的学习,读者将能够:

  1. 理解 PINN 的基本原理和数学框架
  2. 掌握使用 PyTorch 实现基础 PINN 的方法
  3. 学会处理硬约束边界条件
  4. 实现自适应权重策略平衡多任务学习
  5. 将 PINN 扩展到二维稳态问题
  6. 使用 PINN 求解逆问题(参数辨识)

二、理论基础

2.1 热传导方程回顾

一维非稳态热传导方程(扩散方程)的标准形式为:

∂T∂t=α∂2T∂x2 \frac{\partial T}{\partial t} = \alpha \frac{\partial^2 T}{\partial x^2} tT=αx22T

其中:

  • T(x,t)T(x, t)T(x,t) 是温度场
  • α\alphaα 是热扩散系数
  • x∈[0,L]x \in [0, L]x[0,L] 是空间坐标
  • t∈[0,tfinal]t \in [0, t_{final}]t[0,tfinal] 是时间

为了获得唯一解,需要指定:

初始条件(Initial Condition, IC):
T(x,0)=T0(x)T(x, 0) = T_0(x)T(x,0)=T0(x)

边界条件(Boundary Condition, BC):

  • Dirichlet 条件:T(0,t)=TLT(0, t) = T_LT(0,t)=TL, T(L,t)=TRT(L, t) = T_RT(L,t)=TR
  • Neumann 条件:∂T∂x∣x=0=qL\frac{\partial T}{\partial x}\big|_{x=0} = q_LxT x=0=qL
  • Robin 条件:−k∂T∂x∣x=0=h(T−T∞)-k\frac{\partial T}{\partial x}\big|_{x=0} = h(T - T_\infty)kxT x=0=h(TT)

2.2 PINN 的数学框架

2.2.1 神经网络近似

设神经网络 N ⁣N(x,t;θ)N\!N(x, t; \theta)NN(x,t;θ) 以空间坐标 xxx 和时间 ttt 为输入,输出温度预测值 T^\hat{T}T^。网络参数 θ\thetaθ 包括所有层的权重和偏置。

2.2.2 自动微分计算导数

利用自动微分(Automatic Differentiation, AD),我们可以精确计算网络输出的各阶导数:

T^t=∂N ⁣N∂t,T^x=∂N ⁣N∂x,T^xx=∂2N ⁣N∂x2 \hat{T}_t = \frac{\partial N\!N}{\partial t}, \quad \hat{T}_x = \frac{\partial N\!N}{\partial x}, \quad \hat{T}_{xx} = \frac{\partial^2 N\!N}{\partial x^2} T^t=tNN,T^x=xNN,T^xx=x22NN

2.2.3 损失函数构造

PINN 的损失函数由三部分组成:

L(θ)=λresLres+λicLic+λbcLbc \mathcal{L}(\theta) = \lambda_{res} \mathcal{L}_{res} + \lambda_{ic} \mathcal{L}_{ic} + \lambda_{bc} \mathcal{L}_{bc} L(θ)=λresLres+λicLic+λbcLbc

PDE 残差损失
Lres=1Nres∑i=1Nres∣T^t(xi,ti)−αT^xx(xi,ti)∣2\mathcal{L}_{res} = \frac{1}{N_{res}} \sum_{i=1}^{N_{res}} \left| \hat{T}_t(x_i, t_i) - \alpha \hat{T}_{xx}(x_i, t_i) \right|^2Lres=Nres1i=1Nres T^t(xi,ti)αT^xx(xi,ti) 2

初始条件损失
Lic=1Nic∑i=1Nic∣T^(xi,0)−T0(xi)∣2\mathcal{L}_{ic} = \frac{1}{N_{ic}} \sum_{i=1}^{N_{ic}} \left| \hat{T}(x_i, 0) - T_0(x_i) \right|^2Lic=Nic1i=1Nic T^(xi,0)T0(xi) 2

边界条件损失
Lbc=1Nbc∑i=1Nbc∣T^(xbc,ti)−Tbc(ti)∣2\mathcal{L}_{bc} = \frac{1}{N_{bc}} \sum_{i=1}^{N_{bc}} \left| \hat{T}(x_{bc}, t_i) - T_{bc}(t_i) \right|^2Lbc=Nbc1i=1Nbc T^(xbc,ti)Tbc(ti) 2

2.3 网络架构设计

对于热传导问题,常用的网络架构包括:

全连接网络(Fully Connected Network, FCN)

输入层 (x, t) → 隐藏层1 (64神经元) → 隐藏层2 (64神经元) → 隐藏层3 (64神经元) → 输出层 (T)

激活函数选择

  • Tanh:平滑可导,适合 PINN
  • Sin:周期性问题的良好选择
  • Swish:在某些情况下表现更好

网络深度与宽度

  • 深度:通常 3-8 层隐藏层
  • 宽度:每层 32-256 神经元
  • 问题越复杂,网络规模越大

2.4 训练策略

2.4.1 采样策略

残差点采样

  • 均匀网格采样:规则但可能遗漏关键区域
  • 随机采样:简单但分布不均
  • 自适应采样:根据残差大小动态调整

边界/初始点采样

  • 在边界和初始时刻密集采样
  • 通常比内部残差点更密集
2.4.2 优化算法

Adam 优化器

  • 学习率:通常 10−310^{-3}10310−410^{-4}104
  • 学习率衰减:每 1000-5000 轮衰减 0.5-0.9 倍

L-BFGS 精调

  • 在 Adam 收敛后使用
  • 二阶优化,收敛更精确
2.4.3 损失权重调优

不同损失项的量级可能差异巨大,需要合理设置权重:

λres:λic:λbc=1:10:10∼1:100:100 \lambda_{res} : \lambda_{ic} : \lambda_{bc} = 1 : 10 : 10 \sim 1 : 100 : 100 λres:λic:λbc=1:10:101:100:100


三、环境准备

3.1 依赖库安装

# 创建虚拟环境(推荐)
conda create -n pinn python=3.9
conda activate pinn

# 安装核心依赖
pip install torch numpy matplotlib scipy

# 可选:安装 Jupyter 用于交互式开发
pip install jupyter notebook

3.2 硬件要求

  • CPU:任何现代 CPU 均可运行
  • GPU:推荐 NVIDIA GPU 加速训练(CUDA 支持)
  • 内存:建议 8GB 以上

3.3 导入必要的库

import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import grad

# 设置随机种子保证可重复性
torch.manual_seed(42)
np.random.seed(42)

# 设备配置
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备: {device}")

四、案例实战

案例1:基础 PINN 求解 1D 非稳态热方程

4.1.1 问题描述

考虑一维热传导问题:

  • 域:x∈[0,1]x \in [0, 1]x[0,1], t∈[0,0.5]t \in [0, 0.5]t[0,0.5]
  • 热扩散系数:α=0.1\alpha = 0.1α=0.1
  • 初始条件:T(x,0)=sin⁡(πx)T(x, 0) = \sin(\pi x)T(x,0)=sin(πx)
  • 边界条件:T(0,t)=T(1,t)=0T(0, t) = T(1, t) = 0T(0,t)=T(1,t)=0

解析解
T(x,t)=sin⁡(πx)e−απ2tT(x, t) = \sin(\pi x) e^{-\alpha \pi^2 t}T(x,t)=sin(πx)eαπ2t

4.1.2 网络定义
class BasicPINN(nn.Module):
    """基础PINN网络结构"""
    def __init__(self, layers):
        super(BasicPINN, self).__init__()
        self.layers = nn.ModuleList()
        for i in range(len(layers) - 1):
            self.layers.append(nn.Linear(layers[i], layers[i+1]))
            if i < len(layers) - 2:
                self.layers.append(nn.Tanh())
    
    def forward(self, x, t):
        """前向传播"""
        inputs = torch.cat([x, t], dim=1)
        for layer in self.layers:
            inputs = layer(inputs)
        return inputs
4.1.3 训练过程详解
def basic_pinn_solver():
    # 问题参数
    L = 1.0
    T_final = 0.5
    alpha = 0.1
    
    # 创建网络 [2, 64, 64, 64, 1]
    layers = [2, 64, 64, 64, 1]
    model = BasicPINN(layers).to(device)
    
    # 优化器配置
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=2000, gamma=0.5)
    
    # 训练循环
    n_epochs = 10000
    for epoch in range(n_epochs):
        model.train()
        optimizer.zero_grad()
        
        # 1. 内部残差点采样
        x_res = torch.rand(5000, 1, device=device) * L
        t_res = torch.rand(5000, 1, device=device) * T_final
        x_res.requires_grad_(True)
        t_res.requires_grad_(True)
        
        # 计算网络输出和导数
        T_res = model(x_res, t_res)
        T_t = grad(T_res, t_res, grad_outputs=torch.ones_like(T_res), 
                   create_graph=True)[0]
        T_x = grad(T_res, x_res, grad_outputs=torch.ones_like(T_res), 
                   create_graph=True)[0]
        T_xx = grad(T_x, x_res, grad_outputs=torch.ones_like(T_x), 
                    create_graph=True)[0]
        
        # PDE残差损失
        residual = T_t - alpha * T_xx
        loss_res = torch.mean(residual**2)
        
        # 2. 初始条件损失
        x_ic = torch.rand(200, 1, device=device) * L
        t_ic = torch.zeros(200, 1, device=device)
        T_ic_pred = model(x_ic, t_ic)
        T_ic_true = torch.sin(np.pi * x_ic)
        loss_ic = torch.mean((T_ic_pred - T_ic_true)**2)
        
        # 3. 边界条件损失
        t_bc = torch.rand(200, 1, device=device) * T_final
        x_bc_left = torch.zeros(200, 1, device=device)
        x_bc_right = torch.ones(200, 1, device=device) * L
        T_bc_left = model(x_bc_left, t_bc)
        T_bc_right = model(x_bc_right, t_bc)
        loss_bc = torch.mean(T_bc_left**2) + torch.mean(T_bc_right**2)
        
        # 总损失
        loss = loss_res + 10.0 * loss_ic + 10.0 * loss_bc
        
        loss.backward()
        optimizer.step()
        scheduler.step()
4.1.4 代码深度解析

关键步骤1:自动微分计算导数

T_t = grad(T_res, t_res, grad_outputs=torch.ones_like(T_res), create_graph=True)[0]

这行代码使用 PyTorch 的自动微分功能计算 ∂T∂t\frac{\partial T}{\partial t}tTcreate_graph=True 允许二阶导数的计算。

关键步骤2:PDE 残差计算

residual = T_t - alpha * T_xx
loss_res = torch.mean(residual**2)

计算 PDE 的残差,理想情况下残差应为零。通过最小化残差平方和,网络学习满足物理方程。

关键步骤3:多任务损失加权

loss = loss_res + 10.0 * loss_ic + 10.0 * loss_bc

不同损失项的量级可能不同,需要通过权重平衡。通常边界和初始条件的权重更大。

4.1.5 运行结果

训练完成后,模型达到以下精度:

  • L2 相对误差8.38×10−48.38 \times 10^{-4}8.38×104
  • 训练轮数:10,000
  • 最终损失4.02×10−54.02 \times 10^{-5}4.02×105

可视化结果包括:

  1. 训练损失曲线(对数坐标)
  2. PINN 预测的温度场分布
  3. 解析解对比
  4. 绝对误差分布
  5. 不同时刻的温度剖面对比
  6. PDE 残差分布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


案例2:硬约束 PINN(精确满足边界条件)

4.2.1 问题与动机

在基础 PINN 中,边界条件是通过软约束(损失函数)实现的。这存在两个问题:

  1. 边界处可能存在误差
  2. 需要额外的损失项和权重调优

硬约束 PINN 通过数学构造,使网络输出自动满足边界条件。

4.2.2 硬约束构造方法

对于齐次 Dirichlet 边界条件 T(0,t)=T(L,t)=0T(0, t) = T(L, t) = 0T(0,t)=T(L,t)=0,可以构造:

T(x,t)=x(1−x)⋅NN(x,t)T(x, t) = x(1-x) \cdot NN(x, t)T(x,t)=x(1x)NN(x,t)

这样,无论神经网络 NNNNNN 输出什么值,边界处 x=0x=0x=0x=1x=1x=1 的温度自动为零。

4.2.3 网络实现
class HardConstrainedPINN(nn.Module):
    """硬约束PINN - 通过构造自动满足边界条件"""
    def __init__(self, layers):
        super(HardConstrainedPINN, self).__init__()
        self.net = BasicPINN(layers)
    
    def forward(self, x, t):
        """
        硬约束构造: T(x,t) = x*(1-x)*NN(x,t)
        自动满足: T(0,t)=0, T(1,t)=0
        """
        nn_output = self.net(x, t)
        T = x * (1 - x) * nn_output
        return T
4.2.4 训练简化

由于边界条件已自动满足,损失函数只需包含:

# 仅需PDE残差和初始条件
loss = loss_res + 10.0 * loss_ic
4.2.5 结果对比
指标 基础PINN 硬约束PINN
L2相对误差 8.38×10−48.38 \times 10^{-4}8.38×104 7.65×10−57.65 \times 10^{-5}7.65×105
边界误差 软约束 精确为零
损失项数 3项 2项
收敛速度 标准 更快

硬约束 PINN 的精度提高了约 10倍

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


案例3:自适应权重 PINN

4.3.1 问题背景

在多任务学习中,不同损失项的梯度量级可能差异巨大:

  • PDE 残差损失:可能很小(网络已较好满足方程)
  • 初始条件损失:可能需要更多关注
  • 边界条件损失:可能需要调整

固定权重难以适应训练过程中的动态变化。

4.3.2 自适应权重策略

核心思想:动态调整权重,使各损失项对梯度的贡献平衡

更新规则:
λi∝1∣∇θLi∣\lambda_i \propto \frac{1}{|\nabla_{\theta} \mathcal{L}_i|}λiθLi1

具体实现:

def update_weights(self, loss_res, loss_ic, loss_bc):
    # 获取各损失的当前值(近似梯度)
    grad_res = loss_res.item()
    grad_ic = loss_ic.item()
    grad_bc = loss_bc.item()
    
    # 计算自适应权重
    total = grad_res + grad_ic + grad_bc + 1e-8
    self.lambda_res = total / (grad_res + 1e-8)
    self.lambda_ic = total / (grad_ic + 1e-8)
    self.lambda_bc = total / (grad_bc + 1e-8)
    
    # 归一化
    sum_lambda = self.lambda_res + self.lambda_ic + self.lambda_bc
    self.lambda_res /= sum_lambda
    self.lambda_ic /= sum_lambda
    self.lambda_bc /= sum_lambda
4.3.3 训练过程
class AdaptiveWeightPINN:
    def __init__(self, layers, alpha=0.1):
        self.model = BasicPINN(layers).to(device)
        self.alpha = alpha
        self.optimizer = optim.Adam(self.model.parameters(), lr=0.001)
        
        # 初始化权重
        self.lambda_res = 1.0
        self.lambda_ic = 1.0
        self.lambda_bc = 1.0
    
    def train(self, n_epochs=10000):
        for epoch in range(n_epochs):
            # 计算各损失分量
            loss_res, loss_ic, loss_bc = self.compute_losses(...)
            
            # 每1000轮更新权重
            if epoch % 1000 == 0 and epoch > 0:
                self.update_weights(loss_res, loss_ic, loss_bc)
            
            # 加权总损失
            loss = (self.lambda_res * loss_res + 
                   self.lambda_ic * loss_ic + 
                   self.lambda_bc * loss_bc)
            
            loss.backward()
            self.optimizer.step()
4.3.4 权重演化分析

训练过程中,权重自适应调整:

  • 初始阶段:各权重相对均衡
  • 中期阶段:根据损失变化动态调整
  • 后期阶段:收敛到稳定比例

典型权重演化:

Epoch 2000:  λ_res=0.105, λ_ic=0.629, λ_bc=0.267
Epoch 4000:  λ_res=0.010, λ_ic=0.761, λ_bc=0.230
Epoch 6000:  λ_res=0.444, λ_ic=0.378, λ_bc=0.178
Epoch 8000:  λ_res=0.013, λ_ic=0.938, λ_bc=0.049
4.3.5 方法优势
  1. 自动平衡:无需手动调参
  2. 适应性强:适应不同训练阶段
  3. 提高稳定性:避免某一损失项主导
  4. 改善收敛:各损失项同步下降

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


案例4:二维稳态热传导 PINN

4.4.1 问题描述

考虑二维 Laplace 方程:
∇2T=∂2T∂x2+∂2T∂y2=0\nabla^2 T = \frac{\partial^2 T}{\partial x^2} + \frac{\partial^2 T}{\partial y^2} = 02T=x22T+y22T=0

在域 [0,1]×[0,1][0, 1] \times [0, 1][0,1]×[0,1] 上,边界条件:

  • T(0,y)=0T(0, y) = 0T(0,y)=0, T(1,y)=0T(1, y) = 0T(1,y)=0
  • T(x,0)=sin⁡(πx)T(x, 0) = \sin(\pi x)T(x,0)=sin(πx), T(x,1)=0T(x, 1) = 0T(x,1)=0

解析解
T(x,y)=sin⁡(πx)sinh⁡(π(1−y))sinh⁡(π)T(x, y) = \sin(\pi x) \frac{\sinh(\pi(1-y))}{\sinh(\pi)}T(x,y)=sin(πx)sinh(π)sinh(π(1y))

4.4.2 网络架构
class PINN2DSteady(nn.Module):
    """二维稳态热传导PINN"""
    def __init__(self, layers):
        super(PINN2DSteady, self).__init__()
        self.net = BasicPINN(layers)
    
    def forward(self, x, y):
        inputs = torch.cat([x, y], dim=1)
        return self.net(inputs[:, 0:1], inputs[:, 1:2])
4.4.3 损失函数构造
# 内部残差
T_res = model(x_res, y_res)
T_x = grad(T_res, x_res, grad_outputs=torch.ones_like(T_res), create_graph=True)[0]
T_y = grad(T_res, y_res, grad_outputs=torch.ones_like(T_res), create_graph=True)[0]
T_xx = grad(T_x, x_res, grad_outputs=torch.ones_like(T_x), create_graph=True)[0]
T_yy = grad(T_y, y_res, grad_outputs=torch.ones_like(T_y), create_graph=True)[0]

residual = T_xx + T_yy  # Laplace方程
loss_res = torch.mean(residual**2)

# 四条边界的条件
loss_bc_left = torch.mean(model(torch.zeros(N, 1), y_bc)**2)
loss_bc_right = torch.mean(model(torch.ones(N, 1), y_bc)**2)
loss_bc_bottom = torch.mean((model(x_bc, torch.zeros(N, 1)) - torch.sin(np.pi * x_bc))**2)
loss_bc_top = torch.mean(model(x_bc, torch.ones(N, 1))**2)

loss_bc = loss_bc_left + loss_bc_right + loss_bc_bottom + loss_bc_top
loss = loss_res + 10.0 * loss_bc
4.4.4 可视化结果

二维问题的可视化包括:

  1. 温度场等高线图
  2. 三维表面图
  3. 中心线温度分布对比
  4. 误差分布图
4.4.5 扩展到复杂几何

对于复杂几何域,可以使用:

  • 距离函数T=ϕ(x,y)⋅NN(x,y)+TbcT = \phi(x, y) \cdot NN(x, y) + T_{bc}T=ϕ(x,y)NN(x,y)+Tbc,其中 ϕ\phiϕ 是到边界的距离
  • 区域采样:仅在域内采样
  • 水平集方法:隐式表示边界

案例5:逆问题 PINN(参数辨识)

4.5.1 逆问题定义

正问题:已知参数 α\alphaα,求解温度场 T(x,t)T(x, t)T(x,t)

逆问题:从观测数据 {xi,ti,Tiobs}\{x_i, t_i, T_i^{obs}\}{xi,ti,Tiobs} 辨识参数 α\alphaα

4.5.2 逆问题 PINN 框架

将待辨识参数作为可训练变量:

class InversePINN(nn.Module):
    def __init__(self, layers):
        super(InversePINN, self).__init__()
        self.net = BasicPINN(layers)
        # 待辨识的参数
        self.alpha = nn.Parameter(torch.tensor([0.05]))
    
    def forward(self, x, t):
        return self.net(x, t)
4.5.3 损失函数设计

逆问题需要三类损失:

# 1. PDE残差(物理约束)
residual = T_t - model.alpha * T_xx
loss_res = torch.mean(residual**2)

# 2. 初始条件
loss_ic = torch.mean((T_ic_pred - T_true)**2)

# 3. 数据拟合(驱动参数更新)
T_data_pred = model(x_obs, t_obs)
loss_data = torch.mean((T_data_pred - T_obs)**2)

# 总损失
loss = loss_res + 10.0 * loss_ic + 100.0 * loss_data
4.5.4 数据生成(模拟实验)
def generate_observation_data(alpha, n_points=100, noise_level=0.02):
    """生成带噪声的合成观测数据"""
    np.random.seed(42)
    x_obs = np.random.uniform(0.1, 0.9, n_points)
    t_obs = np.random.uniform(0.05, T_final, n_points)
    
    # 解析解
    T_exact = np.sin(np.pi * x_obs) * np.exp(-alpha * np.pi**2 * t_obs)
    # 添加噪声
    noise = np.random.normal(0, noise_level * np.max(np.abs(T_exact)), n_points)
    T_obs = T_exact + noise
    
    return x_obs, t_obs, T_obs, T_exact
4.5.5 辨识结果
参数 数值
真实值 0.1000
初始猜测 0.0500
辨识结果 0.0987
相对误差 1.3%

参数收敛曲线显示,经过约 8000 轮训练,辨识值收敛到真实值附近。

4.5.6 应用价值

逆问题 PINN 在工程中具有重要价值:

  1. 材料热物性测量:从温度响应反推导热系数
  2. 无损检测:识别材料内部缺陷
  3. 数字孪生:实时校准模型参数
  4. 故障诊断:监测设备运行状态

五、高级主题

5.1 网络架构改进

5.1.1 残差连接(ResNet)
class ResidualBlock(nn.Module):
    def __init__(self, width):
        super().__init__()
        self.fc1 = nn.Linear(width, width)
        self.fc2 = nn.Linear(width, width)
        self.activation = nn.Tanh()
    
    def forward(self, x):
        residual = x
        out = self.activation(self.fc1(x))
        out = self.fc2(out)
        return self.activation(out + residual)
5.1.2 Fourier 特征嵌入

对于高频问题,使用 Fourier 特征映射:

class FourierFeature(nn.Module):
    def __init__(self, input_dim, mapping_size=256, scale=10):
        super().__init__()
        self.B = torch.randn((input_dim, mapping_size)) * scale
    
    def forward(self, x):
        x_proj = 2 * np.pi * x @ self.B
        return torch.cat([torch.sin(x_proj), torch.cos(x_proj)], dim=-1)

5.2 训练技巧

5.2.1 学习率调度
# 余弦退火
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10000, eta_min=1e-6)

# 预热 + 衰减
scheduler = optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, 
                                          total_steps=10000)
5.2.2 梯度裁剪
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
5.2.3 混合精度训练
from torch.cuda.amp import autocast, GradScaler

scaler = GradScaler()
with autocast():
    loss = compute_loss(...)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()

5.3 误差分析与验证

5.3.1 相对 L2 误差
def relative_l2_error(pred, true):
    return torch.norm(pred - true) / torch.norm(true)
5.3.2 残差可视化
# 计算残差分布
residual = T_t - alpha * T_xx
plt.contourf(X, T, np.abs(residual), levels=50, cmap='YlOrRd')
plt.colorbar(label='|Residual|')

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐