基于贝叶斯物理信息神经网络的矿产预测与不确定性量化,MATLAB代码及复现报告

把扩散方程写进损失函数:一次 MATLAB 复现贝叶斯 PINN 的完整记录

前段时间翻到一篇 2026 年发在《新疆地质》上的文章,常金雨、张楠楠、李平写的,标题是《基于贝叶斯物理信息神经网络的矿产预测与不确定性量化------以东天山铜镍矿为例》。

铜镍矿、贝叶斯、物理约束神经网络,三个词摆在一起,正好是我一直想弄明白的一类问题:找矿预测从来不缺「画一张图」,缺的是「这张图有多可信」。

那篇论文给了框架,但很多实现细节没写透。归一化怎么做,边界条件怎么进损失,扩散系数怎么识别,认知不确定性和观测噪声怎么分开,正文里都是一笔带过。

于是我把整套东西在 MATLAB 里重写了一遍,从有限差分造真值,到 3000 轮训练,再到 100 次后验采样出区间。这篇文章就是这次复现的记录。

先给结论。六个训练回合跑完,最反直觉的一件事是,去掉扩散方程约束之后,浓度拟合反而更准了,测试区 RMSE 从 0.71 降到 0.47。但同一批后验样本在独立配点上的物理残差,从 0.77 涨到 8.59,差了十一倍。

物理约束在这里不是精度加速器。它更像一份保险,代价是拟合。


一、为什么矿产预测非要谈不确定性

矿产预测的老问题是样本少、空间自相关强、外推距离远。

一个钻孔打下去,周围几公里的推断全靠插值。插值方法本身会给你一条平滑的曲线,但不会告诉你「这里其实没把握」。

深部找矿尤其明显。地表有异常,往下推三百米,模型给你的数字和真实含量之间可能差一个数量级,而报告上只写一个均值。

贝叶斯方法补的就是这块。它不满足于给出浓度场,还要给出这个浓度场的后验分布。同一位置采一百组权重,算出一百个预测值,均值和分位数就是答案。

物理信息神经网络(PINN)补的是另一块。神经网络拟合观测很容易过拟合,加上一条「结果必须满足扩散方程」的约束,等于把成矿的空间连续性塞进了模型。

两者叠起来,就是这篇论文的 B-PINN。代码里我给它配了个对照组,只关掉扩散项,其余断裂、岩体、边界、标签约束全部保留。这样比较才干净。


二、这套代码能干什么

跑一次 main,输出九张 600 dpi 图、六个检查点、逐种子指标表和两份 JSON 核验记录。具体包含:

  • 四元素(Cu、Ni、Co、Cr)浓度场的后验均值与认知标准差
  • 矿化概率图,输出 0 到 1 的连续值
  • 四元素加概率通道的 95% 认知区间与 95% 预测区间,覆盖率单独统计
  • 独立配点上的物理残差,用来看方程到底有没有被满足
  • 可学习的扩散系数 D,从初值 1.0 迭代到收敛
  • 双模型 × 三种子的消融对比

预测网格 100×100,真值在 121×121 的有限差分网格上求解,再插值到预测网格。分辨率不同,不是同一套离散点,省得「验证」变成自己考自己。

图 1 模拟研究区、两条断裂、三个椭圆岩体与 600 个观测点的位置,虚线框为低采样密度区


三、技术路线:一条从偏微分方程到分位数的链

整条链分五段。

第一段造真值。 在归一化坐标上定义两条线段断裂、三个椭圆岩体,用最近距离算出断裂影响场 exp(-d/0.10) 和岩体指示场,再合成四元素的源项。

第二段解方程。 用五点差分在 121×121 网格上解 D∇²u + S = 0,零边界。解出来的 u 乘振幅加背景,就是物理浓度 C。有限差分相对残差 3.3×10⁻¹³,不是靠拟合曲线凑出来的形状。

第三段造数据。 在真值场上采样 600 个观测点,加独立高斯噪声(Cu 1.2、Ni 0.9、Co 0.5、Cr 2.0 mg/kg),浓度低于 0.01 截断。再采 500 个标签点,按潜在真值生成 0/1 矿化标签。空间按 5×5 区块整体切分,15/5/5 个区块进训练、验证、测试,观测实际落到 370/114/116。

第四段训练。 网络输入是二维坐标,隐层 4×32,输出 4 个浓度加 1 个概率。每次前向采样一组权重,同时算九项损失,反传更新均值和尺度参数。

第五段出结果。 固定训练好的变分参数,采样 100 次,在空间每个点上共享同一组权重,保证随机场连续。再取 2.5% 和 97.5% 分位数,得到区间。

图 2 种子 42 的四联图:加权总损失、原始损失分项、基础扩散系数 D 的迭代轨迹、验证区 RMSE

小图 © 里的虚线是真值 0.32,实线是模型学到的 D。两条线始终没合上,这件事后面会单独说。

训练不是一上来就全约束。前 450 轮把方程、断裂、岩体三项权重置零,先让网络把观测拟合住。450 到 1650 轮线性抬升,从 0.2/0.1/0.1 加到 0.5/0.3/0.3,之后保持。

这个安排有它的道理。一开始就用强物理约束,网络还没找到大致的浓度形态,梯度会被方程残差带偏,容易停在平凡解上。


四、公式原理:九项损失是怎么拼起来的

4.1 前向与重参数化

贝叶斯部分用的是均值场变分。每个权重不是一个数,而是一个高斯分布:

复制代码
σ = softplus(ρ) + 1e-6
W = μ + σ ⊙ ε,   ε ~ N(0, 1)

ρ 初始化为 -5 附近,softplus 之后 σ 约 0.0067,起步阶段接近确定性网络,训练稳定后再靠梯度把尺度放开。这是实用配置,原文没有写这么细。

均值初始化用 Glorot 型,sqrt(2/(fan_in+fan_out))。

同一组 ε 在整张预测网格上共用。这一条如果做错,每个点独立采样,空间导数就成了噪声,方程损失直接失效。

4.2 物理方程

复制代码
D(x,y) · ∇²u(x,y) + S(x,y) = 0
C(x,y) = b + a · u(x,y)

D 用 softplus 参数化保证为正,初值 1.0,真值 0.32。源项 S 按训练观测的极差缩放,背景边界做同一仿射变换,保证归一化后方程仍然成立。代码里专门有一条核验,把归一化后的源项代回方程,残差必须小于 1×10⁻⁸。

拉普拉斯算子靠自动微分算,四个元素逐个求二阶导。不能把四个输出通道一起求和再求导,那样会把通道混在一起。

写这段时踩过一个坑。dlgradient 默认不保留高阶导数,求二阶导必须打开 EnableHigherDerivatives,否则拿到的是零。

4.3 九项损失

复制代码
L = Σ λ_i · L_i,   i = 1..9
编号 损失项 作用 权重
1 数据 训练观测的均方误差 5
2 方程 Huber 化后的 PDE 残差 0.5
3 边界 四周边界回到背景值 0.1
4 断裂 断裂带内浓度不得低于全局均值 0.3
5 岩体 岩体内浓度不得低于全局均值 0.3
6 非负 物理浓度不得为负 0.05
7 KL 变分后验与先验的散度,除以训练观测数 1e-4
8 标签 标签点浓度需越过阈值 5
9 分类 矿化概率的交叉熵 1

方程残差用 Huber 而不是平方,δ 取 1。原因是早期残差动辄几十,平方会把梯度放大到无法训练,Huber 在超过 δ 之后退化成线性。

断裂和岩体的约束写成单边惩罚:

复制代码
mean( fault · max(globalMean - c, 0) )

只在「低于全局均值」时罚,高于不罚。这是成矿先验,不是硬等式。

非负损失作用在还原后的物理浓度上,不能作用在归一化值上。否则负的背景值会被错误惩罚,这条我在第一版里写反了,训练曲线一直抖。

KL 项除以训练观测数,是明确的样本归一化约定。原文没交代这一点,两种写法差三个数量级。

4.4 后验区间

采样 100 次得到 samples,然后:

复制代码
mean = mean(samples, 3)
std  = std(samples, 0, 3)
lower = quantile(samples, 0.025, 3)
upper = quantile(samples, 0.975, 3)

这里直接取经验分位数,不假设正态。概率通道的分位数天然落在 0,1,不需要额外截断。

认知区间只含参数不确定性。预测区间再叠加已知的观测噪声,逐次独立生成,这样才能和实测值比对覆盖率。


五、算法步骤

  1. 固定数据种子 2026,生成地质场、源项、有限差分真值、观测与标签
  2. 只用训练观测拟合 Min-Max 参数,背景边界做同一仿射变换
  3. 数值核验:归一化可逆、边界变换、方程残差、区块无泄漏、自动微分二阶导对照解析解
  4. 初始化变分参数,ρ 在 -5 附近扰动
  5. 每轮随机抽 256 个配点,与 370 个观测、200 个边界点、307 个标签点拼成一个批次
  6. 采样 3 组权重噪声,平均九项损失,反传
  7. 梯度范数超过 10 就整体缩放,Adam 更新,学习率按余弦从 3×10⁻⁴ 衰减到 5%
  8. 每 100 轮用后验均值做一次验证集 RMSE 记录,不参与更新
  9. 训练完成后采样 100 次,出均值、标准差、区间
  10. 在 512 个独立配点上抽 10 个后验样本,算归一化浓度尺度的方程残差
  11. 三个种子重复,模型 1 与模型 2 配对,预热阶段损失逐位相同才认可对照有效

第 11 条是我额外加的核验。两个模型在物理权重为 0 的前 450 轮里,损失必须完全一致,否则说明随机序列已经分叉,后面的消融比较就没有意义。三个种子的最大绝对差都是 0.0。


六、参数设定

类别 参数 取值
网络 输入 / 隐层 / 输出 2 / 32×4 / 5
训练 轮次 / 配点 / 每轮物理批 3000 / 2048 / 256
训练 学习率 / 阶段分界 3e-4 / 450、1650
贝叶斯 训练采样数 / 预测采样数 3 / 100
数据 观测 / 标签 / 边界点 600 / 500 / 200
数据 网格 / 差分网格 100×100 / 121×121
物理 扩散系数真值 / 初值 0.32 / 1.0
噪声 Cu / Ni / Co / Cr 1.2 / 0.9 / 0.5 / 2.0
损失 九项权重 5、0.5、0.1、0.3、0.3、0.05、1e-4、5、1
其他 Huber δ / 种子 1 / 42、43、44

另有一档 paper 配置,8×256 隐层、10000 轮、5000 个全批量配点,用于检验容量是否是瓶颈。本文报告的全部数字来自默认配置,没混用。


七、结果:拟合与物理约束的拉扯

三种子均值如下。

指标 B-PINN 去扩散约束
Cu 测试 RMSE(mg/kg) 0.878 0.597
Ni 测试 RMSE 0.722 0.464
Co 测试 RMSE 0.363 0.204
Cr 测试 RMSE 0.858 0.609
平均 R² 0.39 0.74
独立配点物理残差 0.77 8.59
95% 认知区间覆盖率 0.67 0.87
95% 预测区间覆盖率 0.92 0.95
矿化概率 AUC 0.725 0.762
Brier 分数 0.120 0.102
学到的 D 0.948 1.000(未识别)

两个方向都值得说。

拟合更差,残差更小。 B-PINN 的 RMSE 全面落后,R² 均值只有 0.39。原因不难找:测试区块被完全隔离,测试点的观测不参与训练,网络只能靠方程和边界把浓度往远处推。物理约束会把场拉向平滑的扩散解,峰值被压平,R² 自然低。

对照组没有这层约束,它更敢于贴着训练观测走,所以测试 RMSE 低。但它在 512 个独立配点上的方程残差是 8.59,B-PINN 是 0.77。换句话说,对照组在数据点上更准,在数据点之外不讲物理。

这就是我说的那份保险。如果只看测试误差,你会得出「物理约束没用」的结论,这个结论是错的。

D 没被识别出来。 真值 0.32,B-PINN 学到 0.948,接近三倍。对照组停在 1.000,因为它只由方程损失驱动,物理项权重为 0,梯度也就为零,参数从初值一步都没动。这不是「学到 D=1」,是代码层面的必然结果。

B-PINN 偏大三倍,说明 D 和源项在平滑场里存在尺度混淆。浓度场越平滑,拉普拉斯越小,D 的变化对残差影响越弱,后验就很宽。要真正识别扩散系数,观测得覆盖浓度梯度大的区域,或者多给几个时间层。

矿化概率这一块,结果不好看,但必须写出来。 测试集 113 个标签,正类 15 个。六个回合里有五个 F1 为 0,意味着 0.5 阈值下网络几乎不判正类。准确率 0.867 是因为全部判负也能拿到这个数,不能当成模型有效。

AUC 0.66 到 0.80,概率 RMSE 0.14 到 0.23,说明排序能力有一点,绝对概率校准不够。原因在标签生成端:潜在概率整体偏低,正类只占 13%,而分类损失和标签损失同时又在推高标签点浓度,两个目标在少数正类上互相拉扯。

认知区间偏窄。 95% 名义覆盖率只拿到 0.67。以种子 42 为例,低采样区(图中虚线框内)的平均标准差 0.0106,其他区域 0.0121,稀疏区甚至更低。这是均值场变分加对角高斯的典型症状,后验塌缩,区间撑不开。

预测区间覆盖率 0.92 左右,接近名义值,但那是靠叠加已知噪声撑起来的。把噪声去掉,参数本身的不确定性是不够的。


八、运行环境

  • MATLAB R2025b,Deep Learning Toolbox 必需,Parallel Computing Toolbox 用于 GPU
  • 实测设备 RTX 5060 Laptop,开了 CUDA 前向兼容模式。这个模式是针对当前硬件的适配,换卡换版本不保证能跑
  • 没有 GPU 也能跑,把 useGPU 关掉走 CPU 路径,只是慢
  • 单回合墙钟 78 到 353 秒。种子 44 那次记了 11207 秒,是计算环境中途暂停,不是模型性能差异,这个字段不能拿来做设备对比
  • Word 报告由 Python 的 python-docx 装配,只读 MATLAB 输出,不重新训练

主程序是 main.m,下面挂 20 个函数文件,配置集中在 experiment_config.m,改参数只动这一个文件。检查点按「种子 × 模型」存,配置签名不一致会直接报错拒绝复用,避免新旧结果混在一起。


九、能用在哪

深部找矿靶区排序。 输出不是一张浓度图,而是「概率 + 区间」。区间宽的地方,钻井前需要补采样,这个信息比均值有用。

采样设计。 后验标准差可以直接当作下一次布点的依据。不过前面说过,这份代码的后验偏窄,真要用于设计,得先把变分后验放开,或者换 last-layer Laplace、深度集成这类校准更好的方案。

多源数据融合。 断裂、岩体、边界条件都是软约束,换成重力、磁法、化探的响应场,损失项结构不用大改,加几项残差就行。

教学与复现。 九项损失、三阶段训练、配对消融、数值核验这几块,是一个比较完整的「怎么把论文写成可跑代码」的样本。README 里逐条列了与原文口径不同的地方,包括归一化、边界、KL 缩放和初始化。


十、这份复现的边界

必须说清楚:全部观测、断裂、岩体、矿点标签都是可重复的科学模拟,不是东天山真实数据,结果不代表任何真实找矿结论。

代码能证明的只有一件事,在这套模拟设定下,把扩散方程放进损失,会让模型在观测之外更守物理,同时牺牲一部分拟合精度。它不证明 B-PINN 在真实矿区一定更好。

还有几处没解决。

D 的识别问题,靠现有观测密度做不动。矿化概率的类别不平衡,需要在采样端或损失端单独处理,比如加权交叉熵、阈值搜索,而不是硬用 0.5。认知区间的校准,均值场变分先天不足,得换后验形式。

写这篇的时候我一直在想一件事。找矿报告上那个数字,背后其实有两种错误:一种是把没矿的地方说成有矿,一种是把有矿的地方说成没矿。

前者浪费钻探,后者错过资源。而一个只给均值的模型,根本没能力区分这两种错误。

区间存在的意义,就是让决策者知道自己站在哪一边。


相关推荐
weixin_449229382 小时前
Skill应用11:详细设计自动生成|强制“文字先行”,杜绝AI只堆代码不讲设计
人工智能·agent·架构设计·详细设计·trae·skill应用
AiNightVision2 小时前
电力巡检夜视方案选型指南——无人机/机器人/固定监测三种场景怎么选
人工智能·科技·车载系统·机器人·无人机·边缘计算·视频
涛声依旧-底层原理研究所2 小时前
拆解 AI Agent 的四个内核:Loop、Tools、Memory 与 Harness
人工智能·架构
田里的水稻2 小时前
FA_CNN卷积神经网络十八---感知机到多层感知机PyTorch
人工智能·pytorch·python
irislinAmelia2 小时前
汽车产线端侧AI视觉质检完整指南
人工智能·汽车
Highcharts.js2 小时前
CSUN 2026|Highcharts无障碍数据与AI分享
javascript·人工智能·数据分析·highcharts·图表开发
J-JunLiang2 小时前
提示词修炼手册-04-让AI先想后说
人工智能·提示词工程·agent prompt·agent提问·提示词修炼手册
終不似少年遊*2 小时前
【Skill】为中型研发团队制作的敏捷迭代AI副驾Skill
人工智能·python·华为云·agent·ai编程·skill
爱吃火鸡面呀2 小时前
BERT 从入门到实战:为什么需要它、核心原理与工程落地全解析
人工智能·自然语言处理·bert