Deepxde学习笔记——DeepONet求解偏微分方程相关理论与代码实战

🚩本文内容

  • 偏微分方程算子,万能近似定理,损失函数设计等理论内容
  • 使用Deepxde对DeepONet代码编写
  • 一般的PI-DeepONet流程

最近用Deepxde写了一个带参数的偏微分方程求解,感觉自己略有所得,想和着理论一起整理记录一点小小的心得。

理论内容

1. 算子

在偏微分方程里,我们给一个非线性的微分算子 N \mathcal{N} N,其满足
N ( u , s ) = 0 (1) \mathcal{N} (u,s) = 0 \tag{1} N(u,s)=0(1)
其中 u u u是输入函数(注意是映射本身), s s s是我们想要的,但目前不知道的函数。那么DeepONet(The Deep Operator Network)学到的就是函数与函数之间的映射,如下:
G ( u ) = s (2) G(u) = s \tag{2} G(u)=s(2)
在偏微分方程问题里,我们有
u = u ( x 1 , x 2 , … , x n , t ) (3) u = u(x_1,x_2,\dots,x_n,t) \tag{3} u=u(x1,x2,,xn,t)(3)
那么(2)即
G ( u ) ( x 1 , x 2 , … , x n , t ) = s (4) G(u)(x_1,x_2,\dots,x_n,t) = s \tag{4} G(u)(x1,x2,,xn,t)=s(4)
可能有失偏颇的概括说,Lu etal.(2019)等人提出的Deeponet在偏微分方程上所要实现的就是这点。

2. 对算子的万能近似定理(The Universal Approximation Theorem for Operator)

2.1 PINN理论回顾

介绍这个定理之前,首先回顾,在PINN(Physics Informed Neural Network)里面,我们利用深度神经网络所学习到的如下:
N N ( X ) = W n σ n − 1 ( W n − 1 σ n − 2 ( … W 2 σ 1 ( W 1 X + b 1 ) + b 2 ) + …   ) + b n − 1 ) + b n NN(X)=W_n\sigma_{n-1}(W_{n-1}\sigma_{n-2}(\dots W_2\sigma_{1}(W_1X+b_1)+b_2)+\dots)+b_{n-1})+b_n NN(X)=Wnσn1(Wn1σn2(W2σ1(W1X+b1)+b2)+)+bn1)+bn
PINN对初值条件(即IC,Initial Condition,之后用IC叙述),边界条件(即BC,Boundary Condition,之后用BC叙述)以及你在训练时所提供的数据点作为一个个约束(输入),去让PINN学到 W i W_i Wi b i b_i bi,从而得到
N N ( x , t ) ≈ u ( x , t ) NN(x,t) \approx u(x,t) NN(x,t)u(x,t)

2.2 DeepONet的理论知识

我们可以看到,上式本质上是使用深度神经网络在每一层的叠加后,利用深度神经网络对函数进行近似学习。那么DeepONet其实也是一样的出发点: ∀ ϵ > 0 \forall \epsilon >0 ϵ>0, 有正数 n , p , m n,p,m n,p,m,对以下的数或矩阵: c i k , W i j k , b i k , b k ∈ R , W k ∈ R n c_i^k,W_{ij}^k,b_{i}^k,b_{k} \in R,\boldsymbol{W_{k}} \in R^n cik,Wijk,bik,bkR,WkRn,有如下万能近似定理:
∣ G ( u ) ( y ) − ∑ k = 1 p ∑ i = 1 n c i k σ ( ∑ j = 1 m W i j k u ( x j ) + b i k ) ⏟ B r a n c h σ ( W k ⋅ y + b k ) ⏟ T r u n k ∣ < ϵ (THM1) \left|G(u)(y)-\sum_{k=1}^{p} \underbrace{\sum_{i=1}^{n}c_i^k\sigma\left(\sum_{j=1}^{m}W_{ij}^{k}u(x_j)+b_{i}^k\right)}_{Branch} \underbrace{\sigma(\boldsymbol{W_{k}} \cdot \textbf{y}+b_{k})}_{Trunk} \right|<\epsilon \tag{THM1} G(u)(y)k=1pBranch i=1ncikσ(j=1mWijku(xj)+bik)Trunk σ(Wky+bk) <ϵ(THM1)
这里需要注意的是, y \textbf{y} y是一个向量,和 W k \boldsymbol{W_{k}} Wk大小一致。上文PINN中 σ \sigma σ是激活函数,这里的 σ \sigma σ是一个连续的非多项式函数, X X X是一个Banach空间,其中的一个紧致集上的元素为 x j x_j xj。Lu etal.(2019)等人的原文是根据紧致集上的拓扑映射给出的 G G G,此处不表。
大致来说,(THM1)式子中,Branch代表的 u u u就是类似PINN所学习到的 N N NN NN,Trunk代表的 y \textbf{y} y也是类似的,外面再套一层 G G G,相当于用深度神经网络去做拟合连续做两次,对相应元素作点积求和得到的 G G G
所以这个式子可以化简:
G ( u ) ( y ) ≈ ∑ k = 1 q b k ( u ( x 1 ) , u ( x 2 ) , . . . , u ( x m ) ) ⏟ B r a n c h ⋅ t k ( y ) ⏟ T r u n k (5) G(u)(y) \approx \sum_{k=1}^q\underset{Branch}{\underbrace{b_k\left(u(x_1),u(x_2),...,u(x_m)\right)}} \cdot \underset{Trunk}{\underbrace{t_k(\textbf{y})}} \tag{5} G(u)(y)k=1qBranch bk(u(x1),u(x2),...,u(xm))Trunk tk(y)(5)
故而有更广泛的对算子的万能近似定理(Generalized Universal Approximation Theoremfor Operator)这是基于Banach空间做内积提出的,这里只写出其形式,对于定义不多描述:
∣ G ( u ) ( y ) − ⟨ g ( u ( x 1 ) , u ( x 2 ) , ⋯   , u ( x m ) ) ⏟ branch  , f ( y ) ⏟ trunk ⟩ ∣ < ϵ (THM2) |G(u)(y)-\underbrace{\left\langle\mathbf{g}\left(u\left(x_{1}\right), u\left(x_{2}\right), \cdots, u\left(x_{m}\right)\right)\right.}_{\text {branch }},\underbrace{\mathbf{f}(y)}_{\text {trunk}}\rangle \mid<\epsilon \tag{THM2} G(u)(y)branch  g(u(x1),u(x2),,u(xm)),trunk f(y)∣<ϵ(THM2)
其中: g : R m → R p , f : R n → R p \mathbf{g}:R^m \rightarrow R^p, \mathbf{f}:R^n \rightarrow R^p g:RmRp,f:RnRp

3. 损失函数设计

根据上面的理论知识,误差就在于这个 ϵ \epsilon ϵ了,在Deeponet中, G ( u ) ( y ) G(u)(y) G(u)(y)代表理想情况,实际上我们所训练到的是 G θ ( u ) ( y ) G_\theta(u)(y) Gθ(u)(y)
G θ ( u ) ( y ) = ∑ k = 1 q b k ( u ( x 1 ) , u ( x 2 ) , . . . , u ( x m ) ) ⏟ B r a n c h ⋅ t k ( y ) ⏟ T r u n k (6) G_{\theta}(u)(y) = \sum_{k=1}^q\underset{Branch}{\underbrace{b_k\left(u(x_1),u(x_2),...,u(x_m)\right)}} \cdot \underset{Trunk}{\underbrace{t_k(\textbf{y})}} \tag{6} Gθ(u)(y)=k=1qBranch bk(u(x1),u(x2),...,u(xm))Trunk tk(y)(6)
将其代入下面的算子损失函数:
L O p e r a t o r ( θ ) = 1 N P ∑ i = 1 N ∑ j = 1 P ∣ G θ ( u ( i ) ) y j ( i ) − G ( u ( i ) ) y j ( i ) ∣ 2 \mathcal{L}_{Operator}(\theta)=\frac{1}{NP}\sum_{i=1}^N\sum_{j=1}^P\left|G_{\theta}(u^{(i)})y_j^{(i)}-G(u^{(i)})y_j^{(i)}\right|^2 LOperator(θ)=NP1i=1Nj=1P Gθ(u(i))yj(i)G(u(i))yj(i) 2
L O p e r a t o r ( θ ) = 1 N P ∑ i = 1 N ∑ j = 1 P ∣ ∑ k = 1 q b k ( u ( x 1 ) , u ( x 2 ) , . . . , u ( x m ) ) ⋅ t k ( y j ( i ) ) − G ( u ( i ) ) y j ( i ) ∣ 2 \mathcal{L}_{Operator}(\theta)= \frac{1}{NP}\sum_{i=1}^N\sum_{j=1}^P\left|\sum_{k=1}^q{b_k\left(u(x_1),u(x_2),...,u(x_m)\right)} \cdot t_k(y_j^{(i)})-G(u^{(i)})y_j^{(i)}\right|^2 LOperator(θ)=NP1i=1Nj=1P k=1qbk(u(x1),u(x2),...,u(xm))tk(yj(i))G(u(i))yj(i) 2
这里:

  • m m m代表训练点的个数。
  • N N N代表输入函数个数(函数空间中的)。
  • P P P代表我们评估输出函数的那些点。

与PINN类似,我们所提供的IC,BC条件以及我们提供的数据点相当于一个个约束(输入)去逼近得到 G G G

那么从函数的构造我们得到了一个损失函数,因为偏微分方程是从物理问题提取出来的,所以在解决实际问题的时候,我们一般都会考虑到相应的物理定律。在PINN里,物理定律也是作为了损失函数的参考。
一般地,考虑一个广泛的非线性偏微分方程如下:
{ ∂ u ∂ t + L ( u ) = 0 , ( x , t ) ∈ Ω × ( 0 , T ] u ( x , t ) = g ( x , t ) , ( x , t ) ∈ ∂ Ω × ( 0 , T ] u ( x , 0 ) = h ( x ) , x ∈ Ω (GPINN) \begin{cases} \begin{array}{ll} \frac{\partial \boldsymbol{u}}{\partial t}+\mathcal{L}(\boldsymbol{u})=0, & (x, t) \in \Omega \times(0, T] \\ \boldsymbol{u}(x, t)=\boldsymbol{g}(x, t), & (x, t) \in \partial \Omega \times(0, T] \\ \boldsymbol{u}(x, 0)=\boldsymbol{h}(x), & x \in \Omega \end{array} \end{cases} \tag{GPINN} tu+L(u)=0,u(x,t)=g(x,t),u(x,0)=h(x),(x,t)Ω×(0,T](x,t)Ω×(0,T]xΩ(GPINN)
这里 L \mathcal{L} L是非线性微分算子, Ω ∈ R d \Omega \in R^d ΩRd u ( x , t ) \boldsymbol{u}(x,t) u(x,t)是方程(5)的精确解。
构建一个深度学习网络,对于 u ~ ( x , t , θ ) \boldsymbol{\tilde{u}}(x,t,θ) u~(x,t,θ),其中 θ ∈ R k θ \in R^k θRk为网络权重, ( x , t ) (x,t) (x,t)为网络输入, u ~ = [ u 1 ~ ( x , t ) , . . . , u n ~ ( x , t ) ] \boldsymbol{\tilde{u}} = [\tilde{u_1}(x,t),...,\tilde{u_n}(x,t)] u~=[u1~(x,t),...,un~(x,t)]为输出。
根据Karniadakis et al., 2019,标准损失如下:
G ( θ ) = 1 N f ∥ ∂ u ~ ∂ t ( x , t , θ ) + L ( u ~ ( x , t , θ ) ) ∥ Ω × ( 0 , T ] , ν 1 2 + 1 N I C ∥ u ~ ( x , 0 , θ ) − h ( x ) ∥ Ω , ν 2 2 + 1 N B C ∥ u ~ ( x , t , θ ) − g ( x , t ) ∥ ∂ Ω × ( 0 , T ] , ν 3 2 \begin{aligned} G(\theta)&=\frac{1}{N_{f}}\left\|\frac{\partial \tilde{\boldsymbol{u}}}{\partial t}(x, t, \theta)+\mathcal{L}(\tilde{\boldsymbol{u}}(x, t, \theta))\right\|_{\Omega \times(0, T], \nu_{1}}^{2} \\ & +\frac{1}{N_{I C}}\|\tilde{\boldsymbol{u}}(x, 0, \theta)-\boldsymbol{h}(x)\|_{\Omega, \nu_{2}}^{2} \\ & +\frac{1}{N_{B C}}\|\tilde{\boldsymbol{u}}(x, t, \theta)-\boldsymbol{g}(x, t)\|_{\partial \Omega \times(0, T], \nu_{3}}^{2} \end{aligned} G(θ)=Nf1 tu~(x,t,θ)+L(u~(x,t,θ)) Ω×(0,T],ν12+NIC1u~(x,0,θ)h(x)Ω,ν22+NBC1u~(x,t,θ)g(x,t)Ω×(0,T],ν32
其中, N f 、 N I C N_f、N_{IC} NfNIC N B C N_BC NBC分别对应于根据内部条件、初始条件和边界条件各自的概率密度 ν 1 ν_1 ν1 ν 2 ν_2 ν2 ν 3 ν_3 ν3采样的点数。内部条件其实就是在给定定义域范围内部的数据点条件。
我们注意到这个损失函数的后两部分是从残差出发的。和PINN一样,Deeponet的operator下的损失函数也是从残差去设计的,至于其物理定律的损失函数,则是从(1)出发,实际情况下,operator的 G ( u ( i ) ) y j ( i ) G(u^{(i)})y_j^{(i)} G(u(i))yj(i)是从边界和初值条件取点,而物理定律的损失函数会用残差,这一点可以见编码流程设计。
L P h y s i c s ( θ ) = 1 N Q m ∑ i = 1 N ∑ j = 1 Q ∑ k = 1 m ∣ N ( u ( i ) ( x k ) , G θ ( u ( i ) ) ( y j ( i ) ) ) ∣ 2 \mathcal{L}_{Physics}(\theta)=\frac{1}{NQm}\sum_{i=1}^{N}\sum_{j=1}^{Q}\sum_{k=1}^{m}\left|\mathcal{N}(u^{(i)}(x_k),G_{\theta}(u^{(i)})(y_j^{(i)}))\right|^2 LPhysics(θ)=NQm1i=1Nj=1Qk=1m N(u(i)(xk),Gθ(u(i))(yj(i))) 2

N \mathcal{N} N是一个非线性微分算子, { y j } i = 1 Q \{y_j\}_{i=1}^{Q} {yj}i=1Q就是那些用于满足物理定律约束的数据点。
所以Deeponet在结合物理定律后的总误差如下:
L ( θ ) = L O p e r a t o r ( θ ) + L P h y s i c s ( θ ) \mathcal{L}(\theta)=\mathcal{L}_{Operator}(\theta)+\mathcal{L}_{Physics}(\theta) L(θ)=LOperator(θ)+LPhysics(θ)

此时DeepONet在结合物理定律后,便是PI-DeepONet。

程序编码

1.1 编码前的准备与了解

那么到目前为止,我们弄明白了DeepONet的拟合本质,了解了其网络,输出和损失函数的设计。那么DeepONet的输入就和PINN是一样的只是 ( x , t ) (x,t) (x,t)吗?答案是否定的,读者也许能发现上述损失函数的设计中出现了输入函数。DeepONet有两个网络,Branch网络和Trunk网络:
Branch网络:使用深度神经网络,编码离散的输入函数空间
Trunk网络:使用深度神经网络,编码输出函数的定义域
DeepONet真正的强大之处在于:其可以学习各种显式算子,如积分和分数拉普拉斯算子,以及表示确定性和随机微分方程的隐式算子。

这里贴一下deepxde库的最新指南pde_operator:deepxde库最新指南pde_operator里,下面的函数中:

class deepxde.data.pde_operator.PDEOperator(pde, function_space, evaluation_points, num_function, function_variables=None, num_test=None)
  • pde:是dde.data.PDE或者dde.data.TimePDE的一种,待会阐述。
  • function_space:便是Branch网络所定义的输入函数空间,函数空间有PowerSeries,GRF,chebyshev等几种。
  • evaluation_points:是numpy array的形式,数组大小为(n_points, dimension)。它作为一组测试评估点,在输入函数空间中随机取样获得的输入函数中进行评估(相当于Branch网络的输入锚定点,让输入函数在它们的基础上计算值)。
  • num_function:function_space中抽样的函数个数。
  • function_variable:function_space中抽样的函数与哪几个自变量关联。这里注意,以下对于关联的解读仅为个人猜测:0是x,1是t,2开头是你所定义的参数或者辅助变量,具体0,1,2等谁指定谁需要看你在dde.geometry的定义。
  • num_test:测试样本的数量,默认为None,表示测试数据与训练数据相同(即输入函数会被拿来测试)。

该函数定义了Branch网络的行为,那么Trunk网络是从如下函数定义的。
在deepxde.data.pde module里,下面的函数中:

class deepxde.data.pde.PDE(geometry, pde, bcs, num_domain=0, num_boundary=0, train_distribution='Hammersley', anchors=None, exclusions=None, solution=None, num_test=None, auxiliary_var_function=None)

我们一个个解读:

  • geometry:dde.geometry的一种,待会阐述。
  • pde:你所定义的pde函数,如何定义,待会阐述。
  • bcs:BC条件,如何写BC条件待会阐述。
  • num_domain:定义域划分部分个数(在定义域里抽样点个数)。
  • num_boundary:定义域边界条件抽样点个数。
  • train_distribution:抽样点的分布,有“uniform","Hammersley"等。
  • anchors:我们所提供的训练点的Numpy array,以及取样点的 num_domain 和 num_boundary。
  • exclusions:我们提供的Numpy array用于排除这些点的训练。
  • solution:精确解,显式解参考。
  • num_test:测试点个数,用于测试损失,如果"None",则使用训练点进行测试。
  • auxiliary_var_function:辅助变量的函数输入(需要提前定义好辅助变量的函数)。

那么TimePDE也类似的,只不过在bcs变成了ic_bcs用于IC,BC条件的输入,多了一个num_initial,在定义域初值条件的抽样点个数。

class deepxde.data.pde.TimePDE(geometryxtime, pde, ic_bcs, num_domain=0, num_boundary=0, num_initial=0, train_distribution='Hammersley', anchors=None, exclusions=None, solution=None, num_test=None, auxiliary_var_function=None)

接下来阐述deepxde.geometry:
1d是Interval,比如我想定义x的定义域为 [ − 1 , 6 ] [-1,6] [1,6]

x = dde.geometry.Interval(-1,6)

2d是Rectangle,比如我想定义 x , y x,y x,y的定义域分别为 [ − 1 , 6 ] , [ 0 , 5 ] [-1,6],[0,5] [1,6],[0,5],把它们用geom统一表示。

geom = dde.geometry.Rectangle([-1, 0], [6, 5])

3d是Cuboid,nd是Hypercube,时间是TimeDomain。

geom = dde.geometry.Cuboid([-1,0,0],[6,5,5])
t = dde.geometry.TimeDomain(0, 10)

针对TimePDE,我们需要把非t变量和t变量统一,例子如下:

geomtime = dde.geometry.GeometryXTime(geom,t)

如何定义pde?
github官方:diff_rec_aligned_pideeponet.py为例子:

def pde(x, y, v):
    D = 0.01
    k = 0.01
    dy_t = dde.grad.jacobian(y, x, j=1)
    dy_xx = dde.grad.hessian(y, x, j=0)
    return dy_t - D * dy_xx + k * y**2 - v

这里,j=0是对x,j=1是对y,v是参数。要注意的是,pde定义里,x包含了所有的自变量,诸如x,t等,y是唯一因变量。
以advection_aligned_pideeponet.py为例:

def pde(x, y, v):
    dy_x = dde.grad.jacobian(y, x, j=0)
    dy_t = dde.grad.jacobian(y, x, j=1)
    return dy_t + dy_x

如果v作为参数不在pde式子里,就要在ic_bcs条件里。

那么如何写IC,BC条件?
deepxde的IC,BC条件是从匿名函数定义的,匿名函数即lambda x,其针对单个函数的传值,能快捷的计算出一个函数对于这个输入值的值,比如lambda x,y:x+y就定义了一个简单的加法。
这里,lambda后面可以空转,也就是lambda _,也可以写lambda x。icbc中无论BC还是IC都会给你自动找到x,也可以传入函数,故而以下几个写法均可:

bc = dde.icbc.DirichletBC(geom, lambda x: 0, lambda _, on_boundary: on_boundary)
bc = dde.icbc.DirichletBC(geom, lambda x: 0, lambda x, on_boundary: on_boundary)
bc = dde.icbc.DirichletBC(geom, boundary_condition, lambda _, on_boundary: on_boundary)
ic = dde.icbc.IC(geom, initial_condition, lambda _, on_initial: on_initial)
ic = dde.icbc.IC(geom, initial_condition, lambda x, on_initial: on_initial)
ic = dde.icbc.IC(geomtime, lambda _: 0, lambda _, on_initial: on_initial)

要注意这样定义的IC,BC全是软约束,神经网络训练时,不会强迫pde相关数据点去正好得到这些数,而是尽可能地靠近IC,BC条件所给的值。如果要使用硬约束,请检查github issue
在这里贴一个个人写的分段函数初值条件:

def initial_condition(x, c):
    x = x[:, 0:1]
    return np.piecewise(
        x,
        [x < 0, (0 <= x) & (x < 1), x >= 1],
        [0, 1, 0]
    )

第一行的x = x[:, 0:1]表明在x(包括x,t等)的第一个变量(x)中,有如上初值条件。

最后的问题就是网络定义问题了,在deepxde.nn.pytorch.deeponet module里有如下内容,以pytorch为例,前者是普通数据,后者是用笛卡尔坐标定义的数据(卡氏积)。

class deepxde.nn.pytorch.deeponet.DeepONet(layer_sizes_branch, layer_sizes_trunk, activation, kernel_initializer, num_outputs=1, multi_output_strategy=None
class deepxde.nn.pytorch.deeponet.DeepONetCartesianProd(layer_sizes_branch, layer_sizes_trunk, activation, kernel_initializer, num_outputs=1, multi_output_strategy=None)

我们还是一一解读:

  • layer_sizes_branch:Branch网络,用list构建,或者(dimension, f),其中dimension是输入维度,f 是网络函数。在multi_output_strategy里,除"split_branch"和 "split_trunk"外,所有策略的Branch和Trunk网络最后一层的宽度都应相同。
  • layer_sizes_trunk:Trunk网络,用list构建。
  • activation:激活函数。
  • kernel_initializer:参数初始化方法,比如Xavier Glorot初始化方法:“Glorot normal”。
  • num_outputs:神经网络输出个数。
  • multi_output_strategy:多输出策略,默认为None,具体可参考deepxde:multi_output_strategy

1.2 个人建议与笔记

  1. 使用DeepONet注意,如果是anchor自己提供值,在没有足够bc,ic值的情况下或者bc,ic有一定冲突的情况下,建议在PDE和TimePDE里给num_boundary和num_initial一定初始值。
  2. dde.data.PDEOperator或者dde.data.PDEOperatorCartesianProd中,evaluation_points个数与Branch网络第一层输入神经元个数相同。建议通过linspace均匀取样测试。
  3. pde定义中,IC,BC条件中有component的说法。当在pde定义的自变量有多个同类型坐标(除了x,t这种一个空间坐标一个时间坐标的),需要使用component针对一个变量,对其求导或者对其定义bc,ic条件。
    以stokes_aligned_pideeponet.py为例子:
# PDE equation
def pde(xy, uvp, aux):
    mu = 0.01
    # first order
    du_x = dde.grad.jacobian(uvp, xy, i=0, j=0)
    dv_y = dde.grad.jacobian(uvp, xy, i=1, j=1)
    dp_x = dde.grad.jacobian(uvp, xy, i=2, j=0)
    dp_y = dde.grad.jacobian(uvp, xy, i=2, j=1)
    # second order
    du_xx = dde.grad.hessian(uvp, xy, component=0, i=0, j=0)
    du_yy = dde.grad.hessian(uvp, xy, component=0, i=1, j=1)
    dv_xx = dde.grad.hessian(uvp, xy, component=1, i=0, j=0)
    dv_yy = dde.grad.hessian(uvp, xy, component=1, i=1, j=1)
    motion_x = mu * (du_xx + du_yy) - dp_x
    motion_y = mu * (dv_xx + dv_yy) - dp_y
    mass = du_x + dv_y
    return motion_x, motion_y, mass
   
# Boundary condition
# other boundary conditions will be enforced by output transform
def bc_slip_top_func(x, aux_var):
    # using (perturbation / 10 + 1) * x * (1 - x)
    return (aux_var / 10 + 1.) * dde.backend.as_tensor(x[:, 0:1] * (1 - x[:, 0:1]))
bc_slip_top = dde.icbc.DirichletBC(
    geom=geom,
    func=bc_slip_top_func,
    on_boundary=lambda x, on_boundary: np.isclose(x[1], 1.),
    component=0)

1.3 编码流程参考

DeepONet中,对于训练的神经网络,默认采用的前馈连接网络FNN。当然,可以自己定义网络,比如多层感知机,这里不表。
PI-DeepONet编码大致流程如下,假设给定 y = ( x , t ) y = (x,t) y=(x,t),u仅仅只是x的一个函数。

  1. 选择N个不同的函数u: { u ( i ) ( x ) } i = 1 N = [ u ( 1 ) ( x ) , u ( 2 ) ( x ) , . . . , u ( N ) ( x ) ] \{u^{(i)}(\textbf{x})\}_{i=1}^{N}={[u^{(1)}(\textbf{x}),u^{(2)}(\textbf{x}),...,u^{(N)}(\textbf{x})]} {u(i)(x)}i=1N=[u(1)(x),u(2)(x),...,u(N)(x)].

  2. x 1 , … , x m x_1,\dots,x_m x1,,xm点评估 N N N个u函数: [ u ( 1 ) ( x 1 ) u ( 1 ) ( x 2 ) . . . u ( 1 ) ( x m ) u ( 2 ) ( x 1 ) u ( 2 ) ( x 2 ) . . . u ( 2 ) ( x m ) ⋮ ⋮ ⋱ ⋮ u ( N ) ( x 1 ) u ( N ) ( x 2 ) . . . u ( N ) ( x m ) ] \begin{bmatrix}u^{(1)}(x_1)&u^{(1)}(x_2)&...&u^{(1)}(x_m)\\ u^{(2)}(x_1)&u^{(2)}(x_2)&...&u^{(2)}(x_m)\\ \vdots&\vdots&\ddots&\vdots\\ u^{(N)}(x_1)&u^{(N)}(x_2)&...&u^{(N)}(x_m)\end{bmatrix} u(1)(x1)u(2)(x1)u(N)(x1)u(1)(x2)u(2)(x2)u(N)(x2).........u(1)(xm)u(2)(xm)u(N)(xm) .

  3. 将结果输入branch网络: b k ( u ( 1 ) ( x 1 ) u ( 1 ) ( x 2 ) . . . u ( 1 ) ( x m ) u ( 2 ) ( x 1 ) u ( 2 ) ( x 2 ) . . . u ( 2 ) ( x m ) ⋮ ⋮ ⋱ ⋮ u ( N ) ( x 1 ) u ( N ) ( x 2 ) . . . u ( N ) ( x m ) ) b_k\begin{pmatrix}u^{(1)}(x_1)&u^{(1)}(x_2)&...&u^{(1)}(x_m)\\ u^{(2)}(x_1)&u^{(2)}(x_2)&...&u^{(2)}(x_m)\\ \vdots&\vdots&\ddots&\vdots\\ u^{(N)}(x_1)&u^{(N)}(x_2)&...&u^{(N)}(x_m)\end{pmatrix} bk u(1)(x1)u(2)(x1)u(N)(x1)u(1)(x2)u(2)(x2)u(N)(x2).........u(1)(xm)u(2)(xm)u(N)(xm) .

  4. 从边界和初始条件中选择 P P P个点准备评估: y u = y u 1 , y u 2 , . . . , y u P \textbf{y}_u=y_{u1},y_{u2},...,y_{uP} yu=yu1,yu2,...,yuP.

  5. 将评估点输入trunk网络: t k ( y u 1 , y u 2 , . . . , y u P ) t_k(y_{u1},y_{u2},...,y_{uP}) tk(yu1,yu2,...,yuP).

  6. 通过计算branch网络的输出与trunk网络的输出之间的点积来近似算子,即(THM2): G θ ( u ) ( y ) = ∑ k = 1 q b k ( u ( x 1 ) , u ( x 2 ) , . . . , u ( x m ) ) ⏟ B r a n c h ⋅ t k ( y ) ⏟ T r u n k G_\theta(u)(\textbf{y})=\sum\limits_{k=1}^q \underset{Branch}{\underbrace{b_k\left(u(x_1),u(x_2),...,u(x_m)\right)}} \cdot \underset{Trunk}{\underbrace{t_k(\textbf{y})}} Gθ(u)(y)=k=1qBranch bk(u(x1),u(x2),...,u(xm))Trunk tk(y).

  7. 根据(5),(6),从理论上知道: G θ ( u ) ( y u ) ≈ G ( u ) ( y u ) G_\theta(u)(\textbf{y}_u)\approx G(u)(\textbf{y}_u) Gθ(u)(yu)G(u)(yu) G ( u ( i ) ) y j ( i ) G(u^{(i)})y_j^{(i)} G(u(i))yj(i)中的 y j ( i ) y_j^{(i)} yj(i)从初值和边界条件取点,计算损失: L O p e r a t o r ( θ ) = 1 N P ∑ i = 1 N ∑ j = 1 P ∣ G θ ( u ( i ) ) y j ( i ) − G ( u ( i ) ) y j ( i ) ∣ 2 \mathcal{L}_{Operator}(\theta)=\frac{1}{NP}\sum\limits_{i=1}^N\sum\limits_{j=1}^P\left|G_{\theta}(u^{(i)})y_j^{(i)}-G(u^{(i)})y_j^{(i)}\right|^2 LOperator(θ)=NP1i=1Nj=1P Gθ(u(i))yj(i)G(u(i))yj(i) 2.

  8. 在定义域内选择Q个点: y r = y r 1 , y r 2 , . . . , y r Q \textbf{y}_r=y_{r1},y_{r2},...,y_{rQ} yr=yr1,yr2,...,yrQ.

  9. 根据相关物理定律,计算损失: L P h y s i c s ( θ ) = 1 N Q ∑ i = 1 N ∑ j = 1 Q ∣ R θ ( i ) ( y r , j ( i ) ) − u ( i ) ( x r , j ( i ) ) ∣ 2 \mathcal{L}_{Physics}(\theta)=\frac{1}{NQ}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{Q}\left|R_{\theta}^{(i)}(y_{r,j}^{(i)})-u^{(i)}(x_{r,j}^{(i)})\right|^2 LPhysics(θ)=NQ1i=1Nj=1Q Rθ(i)(yr,j(i))u(i)(xr,j(i)) 2.

  10. 计算整体损失: L ( θ ) = L o p e r a t o r ( θ ) + L P h y s i c s ( θ ) \mathcal{L}(\theta)=\mathcal{L}_{operator}(\theta)+\mathcal{L}_{Physics}(\theta) L(θ)=Loperator(θ)+LPhysics(θ).

  11. 更新branch网络和trunk网络参数来最小化: L ( θ ) \mathcal{L}(\theta) L(θ).

  12. 选取 ϵ \epsilon ϵ作为终止条件,重复这个过程直到: G θ ( u ) ( x , t ) ≈ G ( u ) ( x , t ) G_\theta(u)(x,t)\approx G(u)(x,t) Gθ(u)(x,t)G(u)(x,t).

文末

DeepONet与PINN优缺点

特性DeepONetPINN
核心概念学习输入输出之间的算子关系将物理定律嵌入神经网络的损失函数中
数据需求通常需要大量的数据可以在物理约束下使用较少的数据
泛化能力对不同输入函数有良好的泛化能力通常针对特定问题,泛化能力有限
预测速度训练后预测速度快每次求解需要较多计算,预测速度相对慢
适用场景需要快速多次预测、数据驱动的复杂系统需要满足物理定律的精确求解、逆问题

附录

如果你还有关于deepxde的问题,欢迎去deepxde库查看!
也可以去github官方查看例子学习!

### DeepONet预训练概述 DeepONet是一种用于解决微分方程和其他复杂物理系统的神经网络架构。为了有效利用DeepONet,在实际应用之前通常会对其进行预训练以提高性能和稳定性。 对于DeepONet的预训练,主要依赖于Python API来构建训练流程并集成到Omniverse平台中[^1]。具体来说,通过该API可以定义数据集、配置超参数以及设置损失函数等重要组件。 ### 数据准备处理 在开始预训练前,需准备好适合的数据集。这些数据应该能够代表目标领域内的典型情况,并尽可能覆盖广泛的情景。常用的方法是从已知解析解或数值模拟结果中提取样本点作为输入输出对。 ```python import numpy as np def prepare_data(): # 假设这里有一个函数generate_samples()可以从外部源获取样本 samples = generate_samples() inputs, outputs = zip(*samples) X_train = np.array(inputs).reshape(-1, 1) # 输入特征向量 y_train = np.array(outputs) return X_train, y_train ``` ### 构建DeepONet模型结构 接下来是创建DeepONet的具体实现。这涉及到设计分支网(branch net)和干网(trunk net),二者共同作用完成从给定条件映射至解决方案的任务。 ```python from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Dense def build_deep_onet(input_dim=1, output_dim=1): branch_input = Input(shape=(input_dim,)) trunk_input = Input(shape=(output_dim,)) # Branch Net: 处理特定实例的信息 b = Dense(64, activation='relu')(branch_input) b = Dense(64)(b) # Trunk Net: 学习通用模式 t = Dense(64, activation='tanh')(trunk_input) t = Dense(64)(t) merged = tf.multiply(b, t) out = Dense(output_dim)(merged) model = Model([branch_input, trunk_input], out) return model ``` ### 训练过程中的优化策略 采用Adam优化器配合均方误差(MSE)作为损失度量来进行梯度下降更新权重。此外还可以考虑加入早停机制(Early Stopping),当验证集上的表现不再提升时提前终止迭代防止过拟合现象发生。 ```python model.compile(optimizer='adam', loss='mse') history = model.fit( [X_branch, X_trunk], Y, epochs=epochs, batch_size=batch_size, validation_split=0.2, callbacks=[EarlyStopping(monitor='val_loss', patience=patience)] ) ``` 最后一步就是将经过充分调优后的DeepONet导出为可以在Omniverse环境中加载使用的格式文件,以便后续部署使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值