2025.2.9机器学习笔记:PINN文献阅读

news2025/2/11 19:02:47

2025.2.9周报

  • 文献阅读
    • 题目信息
    • 摘要
    • Abstract
    • 创新点
    • 网络架构
    • 实验
    • 结论
    • 缺点以及后续展望

文献阅读

题目信息

  • 题目: GPT-PINN:Generative Pre-Trained Physics-Informed Neural Networks toward non-intrusive Meta-learning of parametric PDEs
  • 期刊: Finite Elements in Analysis and Design
  • 作者: Yanlai Chen, Shawn Koohy
  • 发表时间: 2024
  • 文章链接: https://arxiv.org/pdf/2303.14878

摘要

PINN是一种结合了深度神经网络和现代高性能计算技术的方法,其可以用来求解复杂的非线性偏微分方程。虽然PINN能够处理复杂的方程,但在需要多次计算或实时模拟的情况下它的训练过程很慢。此外,PINN的结构通常比较复杂,参数太多,导致计算效率不高。传统的数值方法虽然也能解决这些问题,但计算量非常大。为了解决PINN的这些缺点,这篇论文提出了一种新的方法,叫做生成式预训练PINN(GPT-PINN)。GPT-PINN的核心思想是简化网络结构,减少计算量。此外,GPT-PINN的外部结构非常简单,只有一个隐藏层,而且隐藏层中的神经元数量也大大减少。其每个神经元的激活函数是通过预先训练好的完整PINN来确定的,这些预训练是在一些特定选择的系统配置下完成的。GPT-PINN还引入了一个“元网络”,这个元网络能够自适应地学习系统的参数变化,并且每次只增加一个神经元。通过这种方式,GPT-PINN只需要训练少量的网络,就能在整个参数范围内快速生成准确的解。这种方法不仅提高了计算效率,还能更好地理解系统在不同参数下的行为。

Abstract

Physics-Informed Neural Networks (PINNs) combine deep learning with high-performance computing to solve nonlinear PDEs but face challenges like slow training and excessive parameterization. This paper introduces Generative Pre-trained PINN (GPT-PINN), which simplifies the network to a single hidden layer with fewer neurons. Each neuron’s activation function is pre-trained under specific configurations, and a meta-network adaptively learns parameter dependencies, adding neurons incrementally. GPT-PINN efficiently generates accurate solutions across the parameter domain with minimal training, improving computational efficiency and system understanding. This approach is particularly useful for multi-query applications like uncertainty quantification and optimal control.

创新点

1.网络架构设计,将预训练的完整网络作为神经元的激活函数;
2.采用元网络的训练损失作为误差指标,灵感源于传统数值求解器基于残差的误差估计。

网络架构

这幅图展示了GPT-PINN的架构,该架构受到降阶基方法(RBM) 的启发,主要用于求解参数化偏微分方程
RBM
RBM的关键在于假设所有参数值对应的解 u ( ⋅ ; μ ) u(⋅;μ) u(;μ) 可以在一个较小的子空间 X N X_N XN​ 中很好地近似。这个子空间的大小由Kolmogorov N-width决定,它衡量了解集在最佳N维子空间中的最大误差。
算法流程如下:
1.从一组参数值 μ 1 μ_1 μ1​ 开始,求解全阶模型(FOM),并将第一个解 u ( ⋅ ; μ 1 ​ ) u(⋅;μ1​) u(;μ1​) 作为初始降阶基 X 1 X_1 X1​。
2.使用贪心算法逐步增加降阶基 X n X_n Xn​。对于每个参数值 μ μ μ,求解降阶模型(ROM),计算误差估计 Δ n − 1 ​ ( μ ) Δ_{n−1​}(μ) Δn1​(μ),选择使误差最大的参数值 μ n μ_n μn​,求解FOM,更新降阶基 X n X_n Xn​。
3.当满足某个条件,比如误差低于某个阈值或达到最大基函数数量时,停止算法。
Kolmogorov N-width
Kolmogorov N-width d N d_N dN​ 衡量了解集在最佳N维子空间中的最差近似误差。
公式如下:
d N [ u ( ⋅ ; D ) ] = inf ⁡ X N ⊂ X h , dim ⁡ X N = N sup ⁡ μ ∈ D inf ⁡ v ∈ X N ∥ u ( ⋅ , μ ) − v ∥ X d_{N}[u(\cdot ; D)]=\inf _{X_{N} \subset X_{h}, \operatorname{dim} X_{N}=N} \sup _{\mu \in D} \inf _{v \in X_{N}}\|u(\cdot, \mu)-v\|_{X} dN[u(;D)]=XNXh,dimXN=NinfμDsupvXNinfu(,μ)vX

第一个 i n f inf inf表示在所有可能的N维子空间 X N X_N XN​ 中寻找最佳的一个。
s u p sup sup表示考虑所有参数 μ μ μ,找到最差情况下的误差。
最后一个 i n f inf inf表示在选定的子空间 X N X_N XN​ 中找到每个 u ( ⋅ , μ ) u(⋅,μ) u(,μ) 的最佳近似 v。

降阶基
降阶基是一组能够代表高维解空间的基函数。通过这些基函数的线性组合,我们可以近似解 u ( ⋅ ; μ ) u(⋅;μ) u(;μ)

以下是对该架构的详细说明:

  1. 超降阶神经网络:图中的神经网络被称为超降阶网络(hyper-reduced),其通过大幅简化传统神经网络结构,从而降低计算量并加快学习速度。该网络用 N N ( 2 , n , 1 ) NN(2,n,1) NN(2,n,1)表示,其中2表示输入层节点数(空间位置x和时间t),n为隐藏层节点数,1为输出层节点数(温度u)。

     其中“超降阶”则是模型降阶中的一种技术,可能进一步简化计算步骤,比如减少参数空间或优化计算过程。
     在GPT-PINN的上下文中,元网络(meta-network)被设计为超降阶的,意味着它的结构比传统的PINN更简单
     例如只有一个隐藏层,神经元数量减少,并且每个神经元使用预训练的完整PINN作为激活函数。
     “超降阶”中的“超”不是指超越,而是指进一步的降阶或优化。
     比如,传统的降阶方法可能减少变量数目,而超降阶可能在降阶的基础上进一步优化计算流程或网络结构,使其更加高效。
    
  2. 隐藏层激活函数:隐藏层的每个节点都配备了一个特定的激活函数,这些函数实际上是针对特定参数值 μ n μ^n μn预训练的PINN。即每个隐藏层节点并非简单的权重和偏置组合,而是一个完整的预训练网络,能够根据物理定律和已知的PDEs对输入做出响应。

  3. 贪婪算法选择的参数:参数值{ μ 1 , μ 2 , . . . , μ n μ^1,μ^2,...,μ^n μ1,μ2,...,μn}是通过专门针对PINNs设计的贪婪算法选取的,以确保所选参数能够有效捕捉解的整体特征。

     贪婪算法是一种“每一步都选当前最优解”的策略,不求全局最优,但求快速逼近。
    

贪婪算法在GPT-PINN的运作过程如下图所示:
1.从一个随机选择的 μ^1开始,设置一个空的 GPT-PINN,n=1。
2.在 μn处训练 GPT-PINN 并求解完整的 PINN。
3.将新的神经元添加到 GPT-PINN 中。
4.检查所有训练参数的最大终端损失是否低于容差 ε t o l ε_{tol} εtol
5.若满足条件,则训练过程结束;如果未收敛,选择下一个最差的 μn+1,将 n 增加 1,然后重复。
其核心思想就是通过逐步添加神经元来训练GPT-PINN,每次选择使当前模型损失最大的参数进行训练。目标是确保所有训练参数的损失都低于某个容差,从而确保模型的泛化能力。
在这里插入图片描述

  1. 输出:输出层将所有隐藏层节点的输出进行整合,从而生成给定参数值下空间位置x和时间t处的温度u的近似解。
    GPT-PINN的解是多个预训练PINN的线性组合,其公式表达如下:
    u G P T ( x , t ; μ ) = ∑ i = 1 n c i ( μ ) ⋅ Ψ N N θ i ( x , t ) u_{\mathrm{GPT}}(\mathbf{x}, t ; \boldsymbol{\mu})=\sum_{i=1}^{n} c_{i}(\boldsymbol{\mu}) \cdot \Psi_{\mathrm{NN}}^{\theta^{i}}(\mathbf{x}, t) uGPT(x,t;μ)=i=1nci(μ)ΨNNθi(x,t)
    参数的含义如下:
    x为空间坐标;t为时间变量;μ为参数向量(如材料属性、边界条件等);
    ∑ i = 1 n \sum_{i=1}^{n} i=1n表示对n个预训练的PINN模型进行线性组合;
    c i ( μ ) c_{i}(\boldsymbol{\mu}) ci(μ)表示第i个预训练PINN的权重系数,依赖参数 μ;
    Ψ N N θ i ( x , t ) \Psi_{\mathrm{NN}}^{\theta^{i}}(\mathbf{x}, t) ΨNNθi(x,t)表示第 i个预训练的PINN,参数 θi 在特定参数 μi下训练完成。

在这里插入图片描述

实验

这篇论文将生成式预训练物理信息神经网络(GPT - PINN)应用于三个方程族(Klein - Gordon方程、Burgers方程和Allen - Cahn方程)进行数值实验。
对于这些方程的具体表达,可以查看我之前的文章:第二十六周机器学习笔记:PINN求正反解求PDE文献阅读

实验结果如下:

1. 对Klein - Gordon方程的实验结果
训练过程:
全连接网络结构的全PINN采用特定激活函数、学习率、优化器、轮数等进行训练。参数训练集有1000个值,贪心算法生成最多15个神经元的GPT - PINN,其在与全PINN相同的配点集上用不同学习率和轮数训练。 GPT - PINN生成的15个神经元对应的参数值及离线训练损失显示,采样参数值靠近域边界,训练损失呈指数下降。与均匀采样对比,自适应“学习神经元”性能更好,且达到一定精度只需训练全PINN 15次。
在这里插入图片描述
测试过程:
在200个随机选择的参数值上测试GPT - PINN,不同大小的GPT - PINN最大误差呈指数趋势。对比全PINN和GPT - PINN的累积运行时间,GPT - PINN边际成本低,增长缓慢,约为全PINN的0.0022倍。全PINN和GPT - PINN的训练损失随轮数变化,GPT - PINN损失下降更平滑,还给出了GPT - PINN解的逐点误差。
在这里插入图片描述

2. 对Burgers方程的实验结果
训练过程:
全PINN为特定结构的全连接网络参数训练集在粘度域内均匀分布,贪心算法生成最多9个神经元的GPT - PINN,其在排除部分配点(靠近大梯度处)的相同配点集上用不同学习率和轮数训练。GPT - PINN生成的9个神经元对应的参数值及离线训练损失显示出与Klein - Gordon方程类似的结果,自适应“学习神经元”比非自适应“均匀神经元”性能好很多。
在这里插入图片描述
测试过程:
在25个参数值上测试GPT - PINN,不同大小的GPT - PINN最大误差呈指数趋势。对比全PINN和GPT - PINN的累积运行时间,GPT - PINN增长缓慢(相对速度为0.009),少量查询(12次)时投资GPT - PINN就很值得。全PINN和GPT - PINN的训练损失随轮数变化,GPT - PINN损失下降更平滑,验证了初始化策略的有效性。
在这里插入图片描述
3. 对Allen - Cahn方程的实验结果
训练过程:
采用自适应性的SA - PINN作为全PINN,设定网络结构、激活函数、学习率、优化器、轮数等进行训练。参数训练集为均匀分布的121个值,贪心算法生成最多9个神经元的GPT - PINN,其在与SA - PINN相同的配点集上用不同学习率和轮数训练。
GPT - PINN生成的9个神经元对应的参数值及离线训练损失显示出与前两个方程类似的结果。
在这里插入图片描述
测试过程:
在25个参数值上测试GPT - PINN,不同大小的GPT - PINN最大误差及累积运行时间表明,GPT - PINN增长缓慢(相对速度为0.0006),少量查询(9 - 10次)时训练GPT - PINN就很值得。
在这里插入图片描述
SA - PINN和GPT - PINN的训练损失随轮数变化,GPT - PINN损失下降更平滑。
在这里插入图片描述
代码链接:https://github.com/idrl-lab/PINNpapers

代码如下:

# Import and GPU Support
import matplotlib.pyplot as plt
import numpy as np
import torch
import os
import tensorflow as tf
 
physical_devices = tf.config.list_physical_devices('GPU') 
tf.config.experimental.set_memory_growth(physical_devices[0], True)
 
import time
import scipy.io
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Input
from tensorflow.keras import layers, activations
from eager_lbfgs import lbfgs, Struct
from pyDOE import lhs
np.random.seed(1234) # lhs
 
# GPT-PINN
from AC_Plotting import AC_plot, loss_plot 
 
from AC_GPT_activation import P
from AC_GPT_precomp import autograd_calculations, Pt_lPxx_eP
from AC_GPT_PINN import GPT
from AC_GPT_train import gpt_train
 
# SA-PINN is implemented explicitly in the code
 
torch.set_default_dtype(torch.float)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Current Device (PyTorch): {device}")
if torch.cuda.is_available():
    print(f"Current Device Name (PyTorch): {torch.cuda.get_device_name()}")
 
# Domain and Data
data_path = r".\data"
xt_test = torch.from_numpy(np.loadtxt(fr"{data_path}\xt_test.txt",dtype=np.float32)).to(device)
 
# Initial Condition
IC_x = torch.from_numpy(np.loadtxt(fr"{data_path}\initial\x0.txt",dtype=np.float32))
IC_t = torch.zeros(IC_x.shape[0])[:,None]
val, idx = torch.sort(IC_x)
IC_u = torch.from_numpy(np.loadtxt(fr"{data_path}\initial\u0.txt",dtype=np.float32))
IC_u = IC_u[idx][:,None].to(device)
IC_xt = torch.hstack((IC_x[idx][:,None],IC_t)).to(device)
 
# Boundary Condition
BC_x_ub = torch.from_numpy(np.loadtxt(fr"{data_path}\boundary\x_ub.txt",dtype=np.float32))[:,None]
BC_t_ub = torch.from_numpy(np.loadtxt(fr"{data_path}\boundary\t_ub.txt",dtype=np.float32))[:,None]
BC_xt_ub = torch.hstack((BC_x_ub,BC_t_ub))
 
BC_x_lb = torch.from_numpy(np.loadtxt(fr"{data_path}\boundary\x_lb.txt",dtype=np.float32))[:,None]
BC_t_lb = torch.from_numpy(np.loadtxt(fr"{data_path}\boundary\t_lb.txt",dtype=np.float32))[:,None]
BC_xt_lb = torch.hstack((BC_x_lb,BC_t_lb))
 
BC_xt = torch.vstack((BC_xt_ub,BC_xt_lb)).to(device) 
BC_u = torch.full((200,1), -1.0).to(device)  
 
# Residual 
x_resid = torch.from_numpy(np.loadtxt(fr"{data_path}\f\xf_train.txt",dtype=np.float32))[:,None]
t_resid = torch.from_numpy(np.loadtxt(fr"{data_path}\f\tf_train.txt",dtype=np.float32))[:,None]
 
xt_resid = torch.hstack((x_resid,t_resid)).to(device) 
f_hat = torch.full((20000,1), 0.0).to(device)   
 
# Training Parameter Set
ac_training = np.loadtxt("ac_param_training.txt")
 
train_final_gpt   = True
number_of_neurons = 9
loss_list         = np.ones(number_of_neurons)
print(f"Expected Final GPT-PINN Depth: {[2,number_of_neurons,1]}\n")
 
###############################################################################
#################################### GPT Setup ####################################
###############################################################################
P_resid_values    = torch.ones((xt_resid.shape[0],  number_of_neurons)).to(device)
P_IC_values       = torch.ones((   IC_xt.shape[0],  number_of_neurons)).to(device)
P_BC_values       = torch.ones((   BC_xt.shape[0],  number_of_neurons)).to(device)
 
P_t_term  = torch.ones((xt_resid.shape[0], number_of_neurons)).to(device)
P_xx_term = torch.ones((xt_resid.shape[0], number_of_neurons)).to(device)
 
ac_neurons    = [1 for i in range(number_of_neurons)]
ac_neurons[0] = [0.00055, 3.0]
 
P_list = np.ones(number_of_neurons, dtype=object)
 
lr_gpt          = 0.0025
epochs_gpt      = 2000
epochs_gpt_test = 5000
test_cases      = 25
 
# Save Data/Plot Options
save_data         = False
plot_pinn_loss    = True
plot_pinn_sol     = True
plot_largest_loss = True
 
pinn_train_times = np.ones(number_of_neurons)
gpt_train_times  = np.ones(number_of_neurons)
 
total_train_time_1 = time.perf_counter()
###############################################################################
#################################### SA Setup #################################
###############################################################################
# SA-PINN from https://github.com/levimcclenny/SA-PINNs
 
lr_adam_sa  = 0.005
lr_lbfgs_sa = 0.8
 
epochs_adam_sa  = 10000
epochs_lbfgs_sa = 10000
 
layers_sa = [2, 128, 128, 128, 128, 1]
 
lb = np.array([-1.0])
ub = np.array([1.0])
 
N0 = 512
N_b = 100
N_f = 20000
 
data = scipy.io.loadmat('AC.mat')
t = data['tt'].flatten()[:,None]
x = data['x'].flatten()[:,None]
Exact = data['uu']
Exact_u = np.real(Exact)
 
#grab training points from domain
idx_x = np.random.choice(x.shape[0], N0, replace=False)
x0 = x[idx_x,:]
u0 = tf.cast(Exact_u[idx_x,0:1], dtype = tf.float32)
 
idx_t = np.random.choice(t.shape[0], N_b, replace=False)
tb = t[idx_t,:]
# Grab collocation points using latin hypercube sampling
X_f = lb + (ub-lb)*lhs(2, N_f)
x_f = tf.convert_to_tensor(X_f[:,0:1], dtype=tf.float32)
t_f = tf.convert_to_tensor(np.abs(X_f[:,1:2]), dtype=tf.float32)
 
# IC/BC data 
X0 = np.concatenate((x0, 0*x0), 1) # (x0, 0)
X_lb = np.concatenate((0*tb + lb[0], tb), 1) # (lb[0], tb)
X_ub = np.concatenate((0*tb + ub[0], tb), 1) # (ub[0], tb)
x0 = tf.cast(X0[:,0:1], dtype = tf.float32)
t0 = tf.cast(X0[:,1:2], dtype = tf.float32)
x_lb = tf.convert_to_tensor(X_lb[:,0:1], dtype=tf.float32)
t_lb = tf.convert_to_tensor(X_lb[:,1:2], dtype=tf.float32)
x_ub = tf.convert_to_tensor(X_ub[:,0:1], dtype=tf.float32)
t_ub = tf.convert_to_tensor(X_ub[:,1:2], dtype=tf.float32)
 
#L-BFGS weight getting and setting from https://github.com/pierremtb/PINNs-TF2.0
def set_weights(model, w, sizes_w, sizes_b):
    with tf.device('/GPU:0'):
        for i, layer in enumerate(model.layers[0:]):
            start_weights = sum(sizes_w[:i]) + sum(sizes_b[:i])
            end_weights = sum(sizes_w[:i+1]) + sum(sizes_b[:i])
            weights = w[start_weights:end_weights]
            w_div = int(sizes_w[i] / sizes_b[i])
            weights = tf.reshape(weights, [w_div, sizes_b[i]])
            biases = w[end_weights:end_weights + sizes_b[i]]
            weights_biases = [weights, biases]
            layer.set_weights(weights_biases)
 
def get_weights(model):
    with tf.device('/GPU:0'):
        w = []
        for layer in model.layers[0:]:
            weights_biases = layer.get_weights()
            weights = weights_biases[0].flatten()
            biases = weights_biases[1]
            w.extend(weights)
            w.extend(biases)
 
        w = tf.convert_to_tensor(w)
        return w
 
#define the neural network model
def neural_net(layer_sizes):
    with tf.device('/GPU:0'):
        model = Sequential()
        model.add(layers.InputLayer(input_shape=(layer_sizes[0],)))
        for width in layer_sizes[1:-1]:
            model.add(layers.Dense(
                width, activation=tf.nn.tanh,
                kernel_initializer="glorot_normal"))
        model.add(layers.Dense(
                layer_sizes[-1], activation=None,
                kernel_initializer="glorot_normal"))
    return model
 
#define the loss
def loss(x_f_batch, t_f_batch,
         x0, t0, u0, x_lb,
         t_lb, x_ub, t_ub,
         col_weights, u_weights, lmbda, eps):
    with tf.device('/GPU:0'):
        f_u_pred = f_model(x_f_batch, t_f_batch, lmbda, eps)
        u0_pred = u_model(tf.concat([x0, t0], 1))
 
        u_lb_pred, u_x_lb_pred, = u_x_model(u_model, x_lb, t_lb)
        u_ub_pred, u_x_ub_pred, = u_x_model(u_model, x_ub, t_ub)
 
        mse_0_u = tf.reduce_mean(tf.square(u_weights*(u0 - u0_pred)))
        mse_b_u = tf.reduce_mean(tf.square(tf.math.subtract(u_lb_pred, u_ub_pred))) + \
                  tf.reduce_mean(tf.square(tf.math.subtract(u_x_lb_pred, u_x_ub_pred)))
 
        mse_f_u = tf.reduce_mean(tf.square(col_weights * f_u_pred[0]))
 
    return  mse_0_u + mse_b_u + mse_f_u , tf.reduce_mean(tf.square((u0 - u0_pred))), mse_b_u, tf.reduce_mean(tf.square(f_u_pred))
 
@tf.function
def f_model(x,t,lmbda,eps):
    with tf.device('/GPU:0'):
        u = u_model(tf.concat([x, t],1))
        u_x = tf.gradients(u, x)
        u_xx = tf.gradients(u_x, x)
        u_t = tf.gradients(u,t)
        c1 = tf.constant(lmbda, dtype = tf.float32)
        c2 = tf.constant(eps, dtype = tf.float32)
        f_u = u_t - c1*u_xx + c2*u*u*u - c2*u
    return f_u
 
@tf.function
def u_x_model(u_model, x, t):
    with tf.device('/GPU:0'):
        u = u_model(tf.concat([x, t],1))
        u_x = tf.gradients(u, x)
    return u, u_x
 
@tf.function
def grad(model, x_f_batch, t_f_batch, x0_batch, t0_batch, u0_batch, x_lb, t_lb, x_ub, t_ub, col_weights, u_weights, lmbda, eps):
    with tf.device('/GPU:0'):
        with tf.GradientTape(persistent=True) as tape:
            loss_value, mse_0, mse_b, mse_f = loss(x_f_batch, t_f_batch, x0_batch, t0_batch, u0_batch, 
                                                   x_lb, t_lb, x_ub, t_ub, col_weights, u_weights, lmbda, eps)
            grads = tape.gradient(loss_value, u_model.trainable_variables)
            grads_col = tape.gradient(loss_value, col_weights)
            grads_u = tape.gradient(loss_value, u_weights)
            gradients_u = tape.gradient(mse_0, u_model.trainable_variables)
            gradients_f = tape.gradient(mse_f, u_model.trainable_variables)
 
    return loss_value, mse_0, mse_b, mse_f, grads, grads_col, grads_u, gradients_u, gradients_f
 
def fit(x_f, t_f, x0, t0, u0, x_lb, t_lb, x_ub, t_ub, col_weights, u_weights, tf_iter, newton_iter, lmbda, eps):
    with tf.device('/GPU:0'):
        batch_sz = N_f # Can adjust batch size for collocation points, here we set it to N_f
        n_batches =  N_f // batch_sz
        adam_losses = []
        #create optimizer s for the network weights, collocation point mask, and initial boundary mask
        tf_optimizer = tf.keras.optimizers.Adam(learning_rate = lr_adam_sa, beta_1=.99)
        tf_optimizer_weights = tf.keras.optimizers.Adam(learning_rate = lr_adam_sa, beta_1=.99)
        tf_optimizer_u = tf.keras.optimizers.Adam(learning_rate = lr_adam_sa, beta_1=.99)
 
        print("Starting ADAM training")
        # For mini-batch (if used)
        for epoch in range(tf_iter):
            for i in range(n_batches):
 
                x0_batch = x0
                t0_batch = t0
                u0_batch = u0
 
                x_f_batch = x_f[i*batch_sz:(i*batch_sz + batch_sz),]
                t_f_batch = t_f[i*batch_sz:(i*batch_sz + batch_sz),]
 
                loss_value, mse_0, mse_b, mse_f, grads, grads_col, grads_u, g_u, g_f = grad(u_model, x_f_batch, t_f_batch, x0_batch, 
                                                                                            t0_batch,  u0_batch, x_lb, t_lb, x_ub, t_ub, 
                                                                                            col_weights, u_weights, lmbda, eps)
 
                tf_optimizer.apply_gradients(zip(grads, u_model.trainable_variables))
                tf_optimizer_weights.apply_gradients(zip([-grads_col, -grads_u], [col_weights, u_weights]))
 
            if (epoch % 250 == 0) or (epoch == (tf_iter-1)):
                adam_losses.append(loss_value)
                if (epoch % 1000 == 0) or (epoch == (tf_iter-1)):
                     print("Epoch: %d | " % (epoch), end='')
                     tf.print(f"mse_0: {mse_0} | mse_b: {mse_b} | mse_f: {mse_f} | Total Loss: {loss_value}\n")
 
        print("Starting L-BFGS training")
        loss_and_flat_grad = get_loss_and_flat_grad(x_f_batch, t_f_batch, x0_batch, t0_batch, u0_batch, 
                                                    x_lb, t_lb, x_ub, t_ub, col_weights, u_weights, lmbda, eps)
 
        lbfgs_losses = lbfgs(loss_and_flat_grad,
          get_weights(u_model),
          Struct(), maxIter=newton_iter, learningRate=lr_lbfgs_sa)[3]
    return adam_losses, lbfgs_losses
 
#L-BFGS implementation from https://github.com/pierremtb/PINNs-TF2.0
def get_loss_and_flat_grad(x_f_batch, t_f_batch, x0_batch, t0_batch, u0_batch, x_lb, t_lb, x_ub, t_ub, col_weights, 
                           u_weights, lmbda, eps):
    def loss_and_flat_grad(w):
        with tf.device('/GPU:0'):
            with tf.GradientTape() as tape:
                set_weights(u_model, w, sizes_w, sizes_b)
                loss_value, _, _, _ = loss(x_f_batch, t_f_batch, x0_batch, t0_batch, u0_batch, x_lb, t_lb, x_ub, 
                                           t_ub, col_weights, u_weights, lmbda, eps)
            grad = tape.gradient(loss_value, u_model.trainable_variables)
            grad_flat = []
            for g in grad:
                grad_flat.append(tf.reshape(g, [-1]))
            grad_flat = tf.concat(grad_flat, 0)
            return loss_value, grad_flat
 
    return loss_and_flat_grad
 
def predict(X_star):
    with tf.device('/GPU:0'):
        X_star = tf.convert_to_tensor(X_star, dtype=tf.float32)
        u_star, _ = u_x_model(u_model, X_star[:,0:1], X_star[:,1:2])
    return u_star.numpy()
 
sizes_w = []
sizes_b = []
with tf.device('/GPU:0'):
    for q, width in enumerate(layers_sa):
        if q != 1:
            sizes_w.append(int(width * layers_sa[1]))
            sizes_b.append(int(width if q != 0 else layers_sa[1]))
 
###############################################################################
################################ Training Loop ################################
###############################################################################
for i in range(0, number_of_neurons):
    print("******************************************************************")
    ########################### SA PINN Training ############################
 
    ac_sa_train = ac_neurons[i]
    lmbda, eps  = float(ac_sa_train[0]), float(ac_sa_train[1])
 
    col_weights = tf.Variable(tf.random.uniform([N_f, 1]))
    u_weights   = tf.Variable(100*tf.random.uniform([N0, 1]))
 
    #initialize the NN
    u_model = neural_net(layers_sa)
 
    if (i+1 == number_of_neurons):
        print(f"Begin Final SA-PINN Training: lambda={lmbda}, eps={eps} (Obtaining Neuron {i+1})")
    else:
        print(f"Begin SA-PINN Training: lambda={lmbda}, eps={eps} (Obtaining Neuron {i+1})")
    
    pinn_train_time_1 = time.perf_counter()
    
    sa_losses = fit(x_f, t_f, x0, t0, u0, x_lb, t_lb, x_ub, t_ub, col_weights, u_weights, 
        tf_iter = epochs_adam_sa, newton_iter = epochs_lbfgs_sa, lmbda=lmbda, eps=eps)
    
    pinn_train_time_2 = time.perf_counter()
    
    print("\nSA-PINN Training Completed")
    print(f"SA-PINN Training Time: {(pinn_train_time_2-pinn_train_time_1)/3600} Hours")
    
    w1 = u_model.layers[0].get_weights()[0].T
    w2 = u_model.layers[1].get_weights()[0].T
    w3 = u_model.layers[2].get_weights()[0].T
    w4 = u_model.layers[3].get_weights()[0].T
    w5 = u_model.layers[4].get_weights()[0].T
    
    b1 = u_model.layers[0].get_weights()[1]
    b2 = u_model.layers[1].get_weights()[1]
    b3 = u_model.layers[2].get_weights()[1]
    b4 = u_model.layers[3].get_weights()[1]
    b5 = u_model.layers[4].get_weights()[1]
 
    P_list[i] = P(w1, w2, w3, w4, w5, b1, b2, b3, b4, b5).to(device)
 
    print(f"\nCurrent GPT-PINN Depth: [2,{i+1},1]")
 
    if (save_data):        
        path = fr".\Full-PINN-Data (AC)\({ac_sa_train})"
        
        if not os.path.exists(path):
            os.makedirs(path)
    
        np.savetxt(fr"{path}\saved_w1.txt", w1.numpy())
        np.savetxt(fr"{path}\saved_w2.txt", w2.numpy())
        np.savetxt(fr"{path}\saved_w3.txt", w3.numpy())
        np.savetxt(fr"{path}\saved_w4.txt", w3.numpy())
        np.savetxt(fr"{path}\saved_w5.txt", w3.numpy())
 
        np.savetxt(fr"{path}\saved_b1.txt", b1.numpy())
        np.savetxt(fr"{path}\saved_b2.txt", b2.numpy())
        np.savetxt(fr"{path}\saved_b3.txt", b3.numpy())
        np.savetxt(fr"{path}\saved_b4.txt", b3.numpy())
        np.savetxt(fr"{path}\saved_b5.txt", b3.numpy())
        
        x_test = xt_test[:,0].view(-1).cpu().detach().numpy()
        t_test = xt_test[:,1].view(-1).cpu().detach().numpy()
        X_star = np.hstack((x_test[:,None], t_test[:,None]))
        u = predict(X_star)
        
        np.savetxt(fr"{path}\u_test.txt", u)
        np.savetxt(fr"{path}\adam_losses.txt",  sa_losses[0])
        np.savetxt(fr"{path}\lbfgs_losses.txt", sa_losses[1])
        
    if (plot_pinn_sol):
        x_test = xt_test[:,0].view(-1).cpu().detach().numpy()
        t_test = xt_test[:,1].view(-1).cpu().detach().numpy()
        X_star = np.hstack((x_test[:,None], t_test[:,None]))
        u = predict(X_star)
    
        AC_plot(t_test, x_test, u, title=fr"SA-PINN Solution $\lambda={lmbda}, \epsilon={eps}$")
    
    if (plot_pinn_loss):
        adam_loss  = sa_losses[0]
        lbfgs_loss = sa_losses[1]
        loss_plot(epochs_adam_sa, epochs_lbfgs_sa, adam_loss, lbfgs_loss,
                  title=fr"SA-PINN Losses $\lambda={lmbda}, \epsilon={eps}$")
 
    if (i == number_of_neurons-1) and (train_final_gpt == False):
        break
        
    ############################ GPT-PINN Training ############################
    layers_gpt = np.array([2, i+1, 1])
    P_t, P_xx = autograd_calculations(xt_resid, P_list[i])
 
    P_t_term[:,i][:,None]  = P_t
    P_xx_term[:,i][:,None] = P_xx
 
    P_IC_values[:,i][:,None]    = P_list[i](IC_xt)
    P_BC_values[:,i][:,None]    = P_list[i](BC_xt)
    P_resid_values[:,i][:,None] = P_list[i](xt_resid)
    
    largest_case = 0
    largest_loss = 0
    
    if (i+1 == number_of_neurons):
        print("\nBegin Final GPT-PINN Training (Largest Loss Training)")
    else:
        print(f"\nBegin GPT-PINN Training (Finding Neuron {i+2} / Largest Loss Training)")
        
    gpt_train_time_1 = time.perf_counter()
    for ac_param in ac_training:
        lmbda, eps = ac_param[0], ac_param[1]
        
        if ([lmbda, eps] in ac_neurons):
            idx = ac_neurons.index([lmbda, eps])
                
            c_initial = torch.full((1,i+1), 0.)
            c_initial[0][idx] = 1.
        else:
            c_initial = torch.full((1,i+1), 1/(i+1))
                
        Pt_lPxx_eP_term = Pt_lPxx_eP(P_t_term[:,0:i+1], P_xx_term[:,0:i+1], P_resid_values[:,0:i+1], lmbda, eps) 
    
        GPT_NN = GPT(layers_gpt, lmbda, eps, P_list[0:i+1], c_initial, xt_resid, IC_xt, 
                     BC_xt, IC_u, BC_u, f_hat, P_resid_values[:,0:i+1], P_IC_values[:,0:i+1],
                     P_BC_values[:,0:i+1], Pt_lPxx_eP_term[:,0:i+1]).to(device)
 
        gpt_losses = gpt_train(GPT_NN, lmbda, eps, xt_resid, IC_xt, BC_xt, IC_u, BC_u,
                               P_resid_values[:,0:i+1], P_IC_values[:,0:i+1], 
                               P_BC_values[:,0:i+1], Pt_lPxx_eP_term[:,0:i+1],
                               lr_gpt, epochs_gpt, largest_loss, largest_case)
        
        largest_loss = gpt_losses[0]
        largest_case = gpt_losses[1]
        
        
    gpt_train_time_2 = time.perf_counter()
    loss_list[i] = largest_loss
    
    print("GPT-PINN Training Completed")
    print(f"GPT Training Time ({i+1} Neurons): {(gpt_train_time_2-gpt_train_time_1)/3600} Hours")
 
    if (i+1 < number_of_neurons):
        ac_neurons[i+1] = largest_case
        
    print(f"\nLargest Loss (Using {i+1} Neurons): {largest_loss}")
    print(f"Parameter Case: {largest_case}")
total_train_time_2 = time.perf_counter()
 
###############################################################################
# Results of largest loss, parameters chosen, and times may vary based on
# the initialization of full PINN and the final loss of the full PINN
print("******************************************************************")
print("*** Full PINN and GPT-PINN Training Complete ***")
print(f"Total Training Time: {(total_train_time_2-total_train_time_1)/3600} Hours\n")
print(f"Final GPT-PINN Depth: {[2,len(P_list),1]}")
print(f"\nActivation Function Parameters: \n{ac_neurons}\n")
 
for j in range(number_of_neurons-1):
    print(f"Largest Loss of GPT-PINN Depth {[2,j+1,2]}: {loss_list[j]}")
if (train_final_gpt):
    print(f"Largest Loss of GPT-PINN Depth {[2,j+2,2]}: {loss_list[-1]}")
        
if (plot_largest_loss):
    plt.figure(dpi=150, figsize=(10,8))
    
    if (train_final_gpt):
        range_end = number_of_neurons + 1
        list_end  = number_of_neurons
    else:
        range_end = number_of_neurons 
        list_end  = number_of_neurons - 1
        
    plt.plot(range(1,range_end), loss_list[:list_end], marker='o', markersize=7, 
             c="k", linewidth=3)
    
    plt.grid(True)
    plt.xlim(1,max(range(1,range_end)))
    plt.xticks(range(1,range_end))
    
    plt.yscale("log") 
    plt.xlabel("Number of Neurons",      fontsize=17.5)
    plt.ylabel("Largest Loss",           fontsize=17.5)
    plt.title("GPT-PINN Largest Losses", fontsize=17.5)
    plt.show()
    
############################### GPT-PINN Testing ############################## 
ac_test = ac_training.tolist()
for i in ac_neurons: 
    if (i in ac_test):
        ac_test.remove(i)    
    
idx = np.random.choice(len(ac_test), test_cases, replace=False)
ac_test = np.array(ac_test)[idx]
    
print(f"\nBegin GPT-PINN Testing ({len(set(idx.flatten()))} Cases)")
 
I = len(P_list)   
layers_gpt = np.array([2, I, 1])
c_initial  = torch.full((1,I), 1/(I))    
 
total_test_time_1 = time.perf_counter()
incremental_test_times = np.ones(len(ac_test))
cnt = 0
 
for ac_test_param in ac_test:
    lmbda, eps = ac_test_param[0], ac_test_param[1]
    
    Pt_lPxx_eP_term = Pt_lPxx_eP(P_t_term, P_xx_term, P_resid_values, lmbda, eps) 
 
    GPT_NN = GPT(layers_gpt, lmbda, eps, P_list, c_initial, xt_resid, IC_xt, 
                 BC_xt, IC_u, BC_u, f_hat, P_resid_values, P_IC_values,
                 P_BC_values, Pt_lPxx_eP_term).to(device)
 
    gpt_losses = gpt_train(GPT_NN, lmbda, eps, xt_resid, IC_xt, BC_xt, IC_u, BC_u,
                           P_resid_values, P_IC_values, P_BC_values, Pt_lPxx_eP_term, 
                           lr_gpt, epochs_gpt, testing=True)
    
    incremental_test_times[cnt] = (time.perf_counter()-total_test_time_1)/3600
    cnt += 1
 
#np.savetxt(".\incremental_test_times.txt", incremental_test_times)
 
total_test_time_2 = time.perf_counter()
print("\nGPT-PINN Testing Completed")
print(f"\nTotal Testing Time: {(total_test_time_2-total_test_time_1)/3600} Hours")
    
init_time = (total_train_time_2-total_train_time_1)/3600
test_time = incremental_test_times
line = test_time + init_time
x = range(1,test_time.shape[0]+1)
plt.figure(dpi=150, figsize=(10,8))
plt.plot(x, line, c="k", lw=3.5)
plt.xlabel("Test Case Number", fontsize=22.5)
plt.ylabel("Time (Hours)", fontsize=22.5)
plt.xlim(min(x),max(x))
plt.ylim(min(line),max(line))
xtick = list(range(0,test_cases+1,5))
xtick[0] = 1
plt.xticks(xtick)
plt.grid(True)
plt.show()

结论

本论文中作者提出的GPT - PINN可解决PINN在参数化偏微分方程环境下面临的训练成本高和过度参数化两大难题。GPT - PINN是一种超精简网络,其激活函数为预训练的完整PINN,通过对三个不同的参数方程族进行测试,实验结果表明选择少量精心挑选的网络能在整个参数域准确高效地生成替代PINN。

缺点以及后续展望

GPT - PINN对参数维度敏感(高维参数仍需更多预训练模型)且对解空间快速变化(如移动激波)的适应性有限。
最后,作者提出后续可进一步探索处理参数移动时产生的不连续性,如采用非线性模型降阶策略或整合转换策略。此外,还可继续优化GPT - PINN,降低全PINN模拟次数,提高效率。最后也可尝试将该方法应用于更多类型的PDEs或其他相关领域。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2296468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM(Java 虚拟机)

Java语言的解释性和编译性&#xff08;通过JVM 的执行引擎&#xff09; Java 代码&#xff08;.java 文件&#xff09;要先使用 javac 编译器编译为 .class 文件&#xff08;字节码&#xff09;&#xff0c;紧接着再通过JVM 的执行引擎&#xff08;Execution Engine&#xff09…

利用二分法进行 SQL 盲注

什么是sql注入&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是一种常见的 Web 安全漏洞&#xff0c;攻击者可以通过构造恶意 SQL 语句来访问数据库中的敏感信息。在某些情况下&#xff0c;服务器不会直接返回查询结果&#xff0c;而是通过布尔值&#xff08;Tr…

大模型数据集全面整理:444个数据集下载地址

本文针对Datasets for Large Language Models: A Comprehensive Survey 中的 444 个数据集&#xff08;涵盖8种语言类别和32个领域&#xff09;进行完整下载地址整理收集。 2024-02-28&#xff0c;由杨刘、曹家欢、刘崇宇、丁凯、金连文等作者编写&#xff0c;深入探讨了大型语…

Linux 创建进程 fork()、vfork() 与进程管理

Linux 创建进程 fork、vfork、进程管理 一、Linux的0号、1号、2号进程二、Linux的进程标识三、fork() 函数1、基本概念2、函数特点3、用法以及应用场景&#xff08;1&#xff09;父子进程执行不同的代码&#xff08;2&#xff09;进程执行另一个程序 4、工作原理 四、vfork() 函…

2025web寒假作业二

一、整体功能概述 该代码构建了一个简单的后台管理系统界面&#xff0c;主要包含左侧导航栏和右侧内容区域。左侧导航栏有 logo、管理员头像、导航菜单和安全退出按钮&#xff1b;右侧内容区域包括页头、用户信息管理内容&#xff08;含搜索框和用户数据表格&#xff09;以及页…

鸿蒙NEXT API使用指导之文件压缩和邮件创建

鸿蒙NEXT API 使用指导 一、前言二、邮件创建1、拉起垂类应用2、 UIAbilityContext.startAbilityByType 原型2.1、wantParam2.2、abilityStartCallback 与 callback 3、拉起邮箱类应用3.1、单纯拉起邮箱应用3.2、传入带附件的邮件 三、压缩文件1、认识 zlib2、压缩处理2.1、单文…

javaEE-10.CSS入门

目录 一.什么是CSS ​编辑二.语法规则: 三.使用方式 1.行内样式: 2.内部样式: 3.外部样式: 空格规范 : 四.CSS选择器类型 1.标签选择器 2.类选择器 3.ID选择器 4.通配符选择器 5.复合选择器 五.常用的CSS样式 1.color:设置字体颜色 2.font-size:设置字体大小 3…

Spring Boot牵手Redisson:分布式锁实战秘籍

一、引言 在当今的分布式系统架构中,随着业务规模的不断扩大和系统复杂度的日益增加,如何确保多个服务节点之间的数据一致性和操作的原子性成为了一个至关重要的问题。在单机环境下,我们可以轻松地使用线程锁或进程锁来控制对共享资源的访问,但在分布式系统中,由于各个服务…

制药行业 BI 可视化数据分析方案

一、行业背景 随着医药行业数字化转型的深入&#xff0c;企业积累了海量的数据&#xff0c;包括销售数据、生产数据、研发数据、市场数据等。如何利用这些数据&#xff0c;挖掘其价值&#xff0c;为企业决策提供支持&#xff0c;成为医药企业面临的重大挑战。在当今竞争激烈的…

[学习笔记] Kotlin Compose-Multiplatform

Compose-Multiplatform 原文&#xff1a;https://github.com/zimoyin/StudyNotes-master/blob/master/compose-multiplatform/compose.md Compose Multiplatform 是 JetBrains 为桌面平台&#xff08;macOS&#xff0c;Linux&#xff0c;Windows&#xff09;和Web编写Kotlin UI…

Golang 并发机制-7:sync.Once实战应用指南

Go的并发模型是其突出的特性之一&#xff0c;但强大的功能也带来了巨大的责任。sync.Once是由Go的sync包提供的同步原语。它的目的是确保一段代码只执行一次&#xff0c;而不管有多少协程试图执行它。这听起来可能很简单&#xff0c;但它改变了并发环境中管理一次性操作的规则。…

【AI实践】Cursor上手-跑通Hello World和时间管理功能

背景 学习目的&#xff1a;熟悉Cursor使用环境&#xff0c;跑通基本开发链路。 本人背景&#xff1a;安卓开发不熟悉&#xff0c;了解科技软硬件常识 实践 基础操作 1&#xff0c;下载安装安卓Android Studio 创建一个empty project 工程&#xff0c;名称为helloworld 2&am…

【多模态大模型】系列4:目标检测(ViLD、GLIP)

目录 1 ViLD2 GLIP 1 ViLD OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION 从标题就能看出来&#xff0c;作者是把CLIP模型当成一个Teacher&#xff0c;去蒸馏他自己的网络&#xff0c;从而能Zero Shot去做目标检测。 现在的目标检测数据…

计算机网络结课设计:通过思科Cisco进行中小型校园网搭建

上学期计算机网络课程的结课设计是使用思科模拟器搭建一个中小型校园网&#xff0c;当时花了几天时间查阅相关博客总算是做出来了&#xff0c;在验收后一直没管&#xff0c;在寒假想起来了简单分享一下&#xff0c;希望可以给有需求的小伙伴一些帮助 目录 一、设计要求 二、…

从零到一:基于Rook构建云原生Ceph存储的全面指南(下)

接上篇&#xff1a;《从零到一&#xff1a;基于Rook构建云原生Ceph存储的全面指南&#xff08;上&#xff09;》 链接: link 六.Rook部署云原生CephFS文件系统 6.1 部署cephfs storageclass cephfs文件系统与RBD服务类似&#xff0c;要想在kubernetes pod里使用cephfs&#…

AutoMQ 如何实现没有写性能劣化的极致冷读效率

前言 追赶读&#xff08;Catch-up Read&#xff0c;冷读&#xff09;是消息和流系统常见和重要的场景。 削峰填谷&#xff1a;对于消息来说&#xff0c;消息通常用作业务间的解耦和削峰填谷。削峰填谷要求消息队列能将上游发送的数据堆积住&#xff0c;让下游在容量范围内消费…

【Rabbitmq篇】高级特性----TTL,死信队列,延迟队列

目录 一.TTL ???1.设置消息的TTL 2.设置队列的TTL 3.俩者区别? 二.死信队列 定义&#xff1a; 消息成为死信的原因&#xff1a; 1.消息被拒绝&#xff08;basic.reject 或 basic.nack&#xff09; 2.消息过期&#xff08;TTL&#xff09; 3.队列达到最大长度? …

【Java】多线程和高并发编程(三):锁(中)深入ReentrantLock

文章目录 3、深入ReentrantLock3.1 ReentrantLock和synchronized的区别3.2 AQS概述3.3 加锁流程源码剖析3.3.1 加锁流程概述3.3.2 三种加锁源码分析3.3.2.1 lock方法3.3.2.2 tryLock方法3.3.2.3 lockInterruptibly方法 3.4 释放锁流程源码剖析3.4.1 释放锁流程概述3.4.2 释放锁…

电路笔记(元器件):AD 5263数字电位计(暂记)

AD5263 是四通道、15 V、256位数字电位计&#xff0c;可通过SPI/I2C配置具体电平值。 配置模式&#xff1a; W引脚作为电位器的抽头&#xff0c;可在A-B之间调整任意位置的电阻值。也可将W与A(或B)引脚短接&#xff0c;A-W间的电阻总是0欧姆&#xff0c;通过数字接口调整电位器…

webpack【初体验】使用 webpack 打包一个程序

打包前 共 3 个文件 dist\index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Webpack 示例&…