時間識別推理的代碼實現(xiàn)與調參指南)
簡介基于物理信息神經(jīng)網(wǎng)絡的完整實現(xiàn)資料覆蓋離散時間識別、離散時間推理、連續(xù)時間識別、連續(xù)時間推理四類典型方法分別對應時間離散采樣與連續(xù)時空場兩類建模場景側重解決數(shù)據(jù)驅動下帶物理約束的識別與推理問題適合從事物理信息神經(jīng)網(wǎng)絡研究、科學計算及偏微分方程求解的科研人員和工程師使用。壓縮包共559個文件內含13份Python源代碼、12份CSV誤差數(shù)據(jù)表、9份EPS或PDF結果圖、7份MAT數(shù)據(jù)文件以及503個txt文本說明整體約475.95MB便于代碼閱讀、實驗復現(xiàn)和結果對比。已有1546人學習下載。通過四組Python工程可系統(tǒng)掌握物理信息神經(jīng)網(wǎng)絡在離散與連續(xù)時間場景下的識別與推理建模思路配套誤差表、圖件和原始數(shù)據(jù)便于分析不同時間處理方式的參數(shù)影響、驗證算法效果既可作為入門模板也可用于復現(xiàn)論文實驗。1. PINN 物理信息網(wǎng)絡解決的是什么問題為什么把時間項拆成離散和連續(xù)標題里同時出現(xiàn)“離散時間識別/離散時間推理/連續(xù)時間識別/連續(xù)時間推理”四個動作實際是同一套 PINN物理信息神經(jīng)網(wǎng)絡框架下對時間維度的兩種建模方式。PINN 的核心是把控制方程的殘差作為損失項加到網(wǎng)絡訓練里讓網(wǎng)絡輸出既擬合觀測數(shù)據(jù)又不違背物理規(guī)律。離散時間識別做的是從若干時刻的快照反推出方程里的未知參數(shù)離散時間推理是在給定初值后用有限差分或時間步進把網(wǎng)絡沿時間方向延展開。連續(xù)時間版本則直接把時間 t 作為網(wǎng)絡輸入的一維坐標用自動微分計算時間導數(shù)識別和推理都在 t 的連續(xù)區(qū)間內完成。適合流體、熱傳導、結構振動以及工程中需要在數(shù)據(jù)不足時仍保持物理一致性的場景也是 pytorch 和 tensorflow 中可復現(xiàn)的 PINN 入門路徑。2. 離散時間識別與推理的實現(xiàn)路徑從標簽數(shù)據(jù)到物理殘差離散時間處理的共同前提是訓練數(shù)據(jù)是若干時間截面上的完整或局部觀測值。識別和推理的區(qū)別只在損失函數(shù)和目標上不同但網(wǎng)絡結構和時間離散方式幾乎一樣。2.1 離散時間識別讓網(wǎng)絡在多個快照上同時滿足 PDE常見做法是設置一個可訓練參數(shù)unknown_params來代表方程中的待定系數(shù)比如擴散系數(shù) a、源項強度 q然后把網(wǎng)絡輸入設計為(x, t)其中 t 只取離散的時刻集合。損失包含兩項數(shù)據(jù)擬合項每個觀測時間點上的網(wǎng)絡輸出u_net(x,t)與該時點傳感器讀數(shù)之差。物理殘差項在隨機采樣點上計算 PDE 殘差殘差里含unknown_params。物理殘差通過 autograd 計算所以unknown_params也能拿到梯度。這是和純監(jiān)督學習最大的不同目標函數(shù)里的未知數(shù)同時被數(shù)據(jù)項間接約束、被殘差項直接約束。2.2 離散時間推理用有限差分把時間方向串起來推理階段往往不再有后續(xù)時間的數(shù)據(jù)。這時用一個步長dt把時間域切成網(wǎng)格在時間層之間做物理步進。損失函數(shù)只剩物理殘差和初始條件。2.2.1 一階熱傳導方程的最小識別代碼結構下面是一段可以用在 pytorch 中的核心片段完成「離散時間識別」中一個擴散系數(shù)的識別import torch import torch.nn as nn class PINN(nn.Module): def __init__(self, n_layers4, n_neurons32): super().__init__() layers [nn.Linear(2, n_neurons), nn.Tanh()] for _ in range(n_layers - 1): layers [nn.Linear(n_neurons, n_neurons), nn.Tanh()] layers [nn.Linear(n_neurons, 1)] self.net nn.Sequential(*layers) def forward(self, x, t): xt torch.cat([x, t], dim1) return self.net(xt).squeeze(-1) model PINN() a_hat nn.Parameter(torch.tensor(0.1, requires_gradTrue)) optimizer torch.optim.Adam([*model.parameters(), a_hat], lr1e-3) def loss_physics(x_colloc, t_colloc): x_colloc.requires_grad_(True) t_colloc.requires_grad_(True) u model(x_colloc, t_colloc) u_x torch.autograd.grad(u, x_colloc, torch.ones_like(u), create_graphTrue)[0] u_xx torch.autograd.grad(u_x, x_colloc, torch.ones_like(u_x), create_graphTrue)[0] u_t torch.autograd.grad(u, t_colloc, torch.ones_like(u), create_graphTrue)[0] # 殘差u_t - a_hat * u_xx f u_t - a_hat * u_xx return torch.mean(f**2)這段代碼把時間當作普通輸入因此即使觀測數(shù)據(jù)只來自幾個離散時刻殘差項仍然可以在這些時刻之間的任意采樣點上計算。requires_grad_(True)打開二階導create_graphTrue讓導數(shù)也能求導這樣a_hat可以從殘差里拿到梯度。識別出的a_hat在訓練結束后直接打印即為擴散系數(shù)。2.2.2 離散時間推理的循環(huán)結構推理階段要把時間方向顯式串起來。常見做法是在每個時間步內把上一時間層的輸出作為“虛觀測”下一時間層的輸出通過有限差分和殘差約束聯(lián)系起來dt 0.01 def rollout(initial_x, initial_u): x_prev initial_x.reshape(-1, 1) u_prev model(x_prev, torch.zeros_like(x_prev)) for step in range(100): t_cur torch.full_like(x_prev, step * dt) x_cur x_prev.clone() u_cur model(x_cur, t_cur) # 用后向歐拉近似時間導數(shù) residual (u_cur - u_prev) / dt - a_hat * torch.autograd.grad( torch.autograd.grad(u_cur, x_cur, torch.ones_like(u_cur), create_graphTrue)[0], x_cur, torch.ones_like(u_cur), create_graphTrue )[0] loss torch.mean(residual**2) torch.mean((u_cur - u_prev)**2) optimizer.zero_grad(); loss.backward(); optimizer.step() u_prev u_cur.detach().requires_grad_(True)這個循環(huán)在每一步訓練網(wǎng)絡使網(wǎng)絡在離散時間層上的輸出作為解推進。識別和推理的差別在這里體現(xiàn)得很直接識別時殘差里的系數(shù)是待訓練參數(shù)推理時系數(shù)已經(jīng)固定殘差只對時間和空間坐標求導。離散時間推理因為沒有后續(xù)觀測數(shù)據(jù)需要在初始層和每一步的殘差上做雙重約束所以訓練步數(shù)通常比識別更多。2.3 離散時間方案的適用范圍和局限離散時間方式的主要優(yōu)勢是方便把實驗中的時間采樣點直接用作網(wǎng)絡輸入。實際工程數(shù)據(jù)往往是不等間隔采樣的離散時間建模不需要插值只要求在采樣時刻有觀測即可。局限是時間推進步長dt受數(shù)值穩(wěn)定性限制過大的dt會讓殘差項主導出現(xiàn)振蕩和梯度爆炸過小的dt會顯著增加訓練成本。另外離散時間推理的誤差會隨步數(shù)累積一般只適合短時程問題。3. 連續(xù)時間識別與推理把時間作為網(wǎng)絡輸入維度連續(xù)時間方式不再考慮時間層的推進而是讓網(wǎng)絡直接逼近函數(shù)u(x, t)在整個時空域上采樣。識別和推理的區(qū)別同樣體現(xiàn)在未知參數(shù)的訓練模式上。3.1 連續(xù)時間識別在時空域上聯(lián)立所有殘差把時間維放進網(wǎng)絡輸入后損失函數(shù)可以寫成L L_data lambda_1 * L_pde lambda_2 * L_ic lambda_3 * L_bc其中L_pde在時空域隨機采樣點上計算L_ic在 t0 或初始時刻的線上計算L_bc在邊界時空點上計算。識別過程中方程未知參數(shù)作為網(wǎng)絡之外的nn.Parameter與網(wǎng)絡權重一同更新。3.1.1 連續(xù)時間殘差的自動微分寫法與離散時間不同連續(xù)時間不需要有限差分直接對網(wǎng)絡輸入t求一階導數(shù)即可。一個典型代碼如下def pde_residual(x, t): x x.requires_grad_(True) t t.requires_grad_(True) u model(x, t) u_t torch.autograd.grad(u, t, torch.ones_like(u), create_graphTrue)[0] u_x torch.autograd.grad(u, x, torch.ones_like(u), create_graphTrue)[0] u_xx torch.autograd.grad(u_x, x, torch.ones_like(u_x), create_graphTrue)[0] residual u_t - a_hat * u_xx # a_hat 可訓練或凍結 return residual optimizer torch.optim.Adam(list(model.parameters()) [a_hat], lr1e-3)訓練循環(huán)里每輪采樣一批內部時空點、一批初邊值點和一批觀測點分別計算三部分損失后加權相加。加權系數(shù)lambda_1設得越大物理約束越強數(shù)據(jù)噪聲大時應適當減小lambda_1否則網(wǎng)絡會為了滿足物理殘差而忽略噪聲觀測。3.1.2 觀測數(shù)據(jù)稀疏時怎么提高識別穩(wěn)定性稀疏觀測下直接訓練容易把a_hat在訓練初期推向很大/很小的值。一個有效技巧是分階段訓練第一個階段只訓練網(wǎng)絡權重用純數(shù)據(jù)項恢復出大致解場第二個階段再放開a_hat的梯度。另一個技巧是給a_hat加上先驗約束常見做法是在損失里加(a_hat - a_prior)^2 * lambda_prior。這樣可以避免系數(shù)漂移。3.2 連續(xù)時間推理給定初邊值求任意時刻的解推理階段不需要觀測數(shù)據(jù)網(wǎng)絡在時空域上被初邊值和 PDE 殘差約束。網(wǎng)絡學到的是一個從 (x,t) 到 u 的連續(xù)函數(shù)所以推理本質上是「求這個函數(shù)在某個時刻 t 的取值」不需要時間遞推。3.2.1 推理時的時間邊界處理推理質量高度依賴初始條件是否被嚴格執(zhí)行。常見的方法是加重對 t0 整條界線的采樣密度讓初始條件損失收斂到遠低于殘差的量級。可設定如下采樣參數(shù)參數(shù)推薦值作用內部時空采樣點10000決定 PDE 殘差覆蓋的時空范圍初值線采樣點200約束初始狀態(tài)邊界采樣點1000約束邊界條件每個邊界至少 200 個點時間域范圍根據(jù)問題視導數(shù)尺度過大則殘差權重不均過小則推理時程短訓練時用torch.utils.data.DataLoader或直接把隨機采樣點一次性生成。推理時不再采樣而是調用model(x_query, t_query)。3.2.2 連續(xù)時間方案的經(jīng)典坑高次時間導數(shù)對二階及以上時間導數(shù)的 PDE連續(xù)時間方式需要至少create_graphTrue的多層嵌套計算圖會變得很深。因此建議把二階時間導數(shù)用torch.autograd.grad嵌套求一次然后立即釋放中間變量。不要多次.backward()造成圖累積。4. 四份代碼之間的共性與針對性調參標題里的四個代碼典型情況是分別對應離散時間識別、離散時間推理、連續(xù)時間識別、連續(xù)時間推理。它們共享同一個 PINN 骨干網(wǎng)絡區(qū)別主要在數(shù)據(jù)加載、時間處理方式和損失函數(shù)上。4.1 四份代碼對應哪種問題識別代碼的損失里必須有a_hat等參數(shù)推理代碼則把已知參數(shù)凍結。離散時間代碼的采樣點包括離散時間層時間層間距需要手工給定連續(xù)時間代碼則使用隨機采樣的 t 坐標。對照關系可以整理成一張表代碼類型數(shù)據(jù)需求未知參數(shù)量時間推進方式典型損失構成離散識別多個時層快照1~3無數(shù)據(jù) 殘差離散推理初值 參數(shù)0有限差分初值 逐層殘差連續(xù)識別時空散射觀測1~3無數(shù)據(jù) 初邊值 連續(xù)殘差連續(xù)推理初邊值 參數(shù)0無初邊值 連續(xù)殘差4.2 三個必調參數(shù)物理殘差權重lambda_pde。這個權重太小時結果退化成純插值太大時網(wǎng)絡會犧牲邊界擬合。推薦從 0.1 開始用對數(shù)網(wǎng)格試探幾次。網(wǎng)絡寬度和深度。PINN 不需要特別深4~6 層、每層 32~128 個神經(jīng)元通常夠用。太寬會導致邊界區(qū)域振蕩。時間范圍歸一化。把 t 歸一化到 [0,1] 能顯著提升收斂速度。連續(xù)時間推理尤其要注意不歸一化時自動微分的梯度量級會差幾個數(shù)量級。還有一個容易被忽略的點四個代碼里如果只改識別/推理開關而不改損失函數(shù)里的detach()位置很容易出現(xiàn)梯度穿透時間層。離散推理里對上一時間層輸出做detach()是防止梯度沿時間步長回傳導致的計算圖爆炸連續(xù)推理則不需要這種操作因為在單一向前傳播中時間只是普通輸入維度。4.3 損失權重自動調節(jié)的替代做法手動調lambda很累。有一個簡單方案在每次迭代里計算三部分損失的梯度范數(shù)用梯度范數(shù)的倒數(shù)做臨時權重。pytorch 里實現(xiàn)如下pde_grad torch.autograd.grad(L_pde, model.parameters(), retain_graphTrue) data_grad torch.autograd.grad(L_data, model.parameters()) w_pde torch.norm(data_grad[0]) / (torch.norm(pde_grad[0]) 1e-8) total_loss L_data w_pde * L_pde total_loss.backward()這里w_pde是根據(jù)兩個梯度范數(shù)的比值動態(tài)計算的保證網(wǎng)絡權重梯度不被某一部分損失主導。retain_graphTrue是因為計算pde_grad后還要繼續(xù) backward得到data_grad后再算總損失。實際使用中如果發(fā)現(xiàn)w_pde震蕩過大可以對其做滑動平均。4.4 常見失敗模式與驗證方法看到 loss 下降但a_hat不收斂一般是物理權重過低或觀測點覆蓋不足。看到推理結果在邊界處突然抖動是邊界點過少??吹竭B續(xù)時間推理在 t 較大時偏差明顯是時間歸一化沒做好或初值約束沒有降到足夠低。驗證推理結果的方法把 PDE 殘差單獨拿出來在推理得到的新解上重新計算殘差均方根若殘差均方根仍保持訓練時的量級說明外推的物理一致性保持住了。另一種驗證方法是把前 80% 時間段的數(shù)據(jù)拿來訓練用后 20% 時間段的觀測做對比適合有時間序列實測的場景。5. 用一個小例子驗證「先識別再推理」的完整流程假設手里只有兩個時刻的觀測t0 和 t0.1 時 u 在空間上的兩個截面目標是識別擴散系數(shù) a然后推理到 t0.3。第一步用第二章的離散識別代碼得到a_hat第二步固定a_hat用離散推理由 t0.1 逐步走到 t0.3。推理完成后在同一個查詢點 x 上取 30 個時間等距點看解是否平滑t_query torch.linspace(0, 0.3, 30) u_pred [] for t in t_query: with torch.no_grad(): u_pred.append(model(x_ref, t.unsqueeze(0)).item()) # 相鄰時間步的解差用于平滑性檢查 diff_max max(abs(u_pred[i1] - u_pred[i]) for i in range(len(u_pred)-1)) print(smoothness max diff:, diff_max)若diff_max小于千分之一量級說明推理過程沒有出現(xiàn)明顯的數(shù)值振蕩。若相鄰差值突然跳躍優(yōu)先檢查推理步長dt和初值約束是否收斂到位。更關鍵的技巧是“二次殘差驗證”推理完成后用推理得到的u和固定的a_hat重新計算 PDE 殘差并把殘差均方根與訓練結束時的殘差均方根做對比。當兩個值在同一數(shù)量級說明推理結果依然滿足物理方程而不是只做了時間方向上的線性延拓。若推理殘差大了兩個數(shù)量級以上說明推理區(qū)間已經(jīng)超出網(wǎng)絡有效表達范圍需要縮小時間步或增加網(wǎng)絡容量。這個驗證動作可以同時用在離散推理和連續(xù)推理上也是判斷四份代碼結果是否可靠的最直接的客觀指標。本文還有配套的精品資源點擊獲取