- 人工智能
- 机器学习
- 深度学习
- NLP
- 大模型
- 模型推理服务
- 数据可视化
【免费下载链接】smile
Statistical Machine Intelligence & Learning Engine
SMILE(Statistical Machine Intelligence & Learning Engine)在smile.math.rbf包中提供了一套完整的径向基函数(Radial Basis Function, RBF)内核实现,广泛用于 RBF 网络、散乱数据插值以及无网格数值方法。本文以该包为骨架,系统讲解 RBF 的数学定义、RadialBasisFunction接口、六种内置基函数的公式与性质、尺度参数r₀的选取策略,并结合仓库源码给出可运行的 Java 示例,帮助读者在插值与神经网络场景中正确选型和调参。
什么是径向基函数(RBF)
径向基函数是一类取值只依赖于到某个固定中心点c距离的实值函数:
φ(x, c) = φ( ‖x − c‖ )通常采用欧氏距离作为范数。径向基函数之和可以逼近任意函数:
y(x) = Σᵢ wᵢ φ( ‖x − cᵢ‖ )其中中心点cᵢ通常从训练数据中选取,权重wᵢ通过线性最小二乘求解。由于近似式对权重是线性的,拟合过程既快又有完善的数值方法支撑。
在 SMILE 的源码注释中(见 RadialBasisFunction.java),还特别指出:该近似过程可以解释为一种简单的神经网络,且已被用于时间序列预测、非线性系统的混沌控制以及计算机图形学中的 3D 重建(如分层 RBF)等场景。同时,若采用概率度量(probability metric),对某些径向函数可以避免求解权重时出现的病态矩阵问题。
RadialBasisFunction 接口
smile.math.rbf包中所有类都实现RadialBasisFunction接口。该接口本身是空接口,继承了smile.util.function.Function,因此具备Serializable序列化能力以及两个核心方法:
public interface RadialBasisFunction extends Function { // Inherits: double f(double r) // Inherits: default double apply(double r) }每个 RBF 都可以作为关于距离r的一元函数直接调用:
RadialBasisFunction rbf = new GaussianRadialBasis(1.0); double v = rbf.f(2.5); // evaluate at distance r = 2.5 double v2 = rbf.apply(2.5); // same result — Scala / lambda friendly测试用例 RadialBasisFunctionTest.java 明确验证了f()与apply()返回值一致,且所有 RBF 类都通过Function间接实现了java.io.Serializable,这意味着它们可以被安全地序列化保存和传输。
六种内置径向基函数
smile.math.rbf包共提供 7 个类(见 rbf 目录):接口RadialBasisFunction加上 6 个具体实现。下面逐一介绍。
Gaussian(高斯)
φ(r) = exp( −r² / (2 r₀²) )| 属性 | 值 |
|---|---|
φ(0) | 1 |
| 值域 | (0, 1] |
| 单调性 | 递减 |
| 尾部 | 快速衰减到 0 |
高斯核是最流行的 RBF。对于光滑函数,只要r₀选择得当,可以获得非常高的插值精度,但它对尺度参数很敏感。源码实现见 GaussianRadialBasis.java:f(r)先将r除以r₀再计算exp(-0.5·(r/r₀)²)。其 Javadoc 也提醒:高斯基函数的插值精度对r₀极其敏感,因此常因此被回避;但对于光滑函数且r₀最优时,可实现非常高的精度,并且高斯核会在远离数据处快速把函数外推为 0。
GaussianRadialBasis rbf = new GaussianRadialBasis(1.0); // r₀ = 1.0 double v = rbf.f(0.0); // 1.0 double v2 = rbf.f(2.0); // exp(-2) ≈ 0.135 // 查询尺度 double r0 = rbf.scale(); // 1.0尺度效应:r₀越小 → 核越尖锐、影响越局部;r₀越大 → 核越平滑、影响越全局。
GaussianRadialBasis sharp = new GaussianRadialBasis(0.5); GaussianRadialBasis smooth = new GaussianRadialBasis(2.0); // sharp.f(1.0) < smooth.f(1.0)这一性质同样被测试覆盖:testGaussianScaleEffect断言r₀=0.5时在固定r>0处的取值小于r₀=2.0(见 RadialBasisFunctionTest.java)。
Multiquadric(多二次)
φ(r) = sqrt( r² + r₀² )| 属性 | 值 |
|---|---|
φ(0) | r₀ |
| 值域 | [r₀, ∞) |
| 单调性 | 递增 |
| 尾部 | 无界增长 |
多二次函数通常对r₀的选择不如其他 RBF 敏感。与衰减型 RBF 不同,它随距离增长——插值时需要多项式修正项以保证系统适定性(well-conditioned)。实现见 MultiquadricRadialBasis.java,其中构造函数缓存了r₀²以提升性能。
MultiquadricRadialBasis rbf = new MultiquadricRadialBasis(1.0); double v = rbf.f(3.0); // sqrt(9 + 1) = sqrt(10) ≈ 3.162 double r0 = rbf.scale(); // 1.0Inverse Multiquadric(逆多二次)
φ(r) = 1 / sqrt( r² + r₀² )| 属性 | 值 |
|---|---|
φ(0) | 1/r₀ |
| 值域 | (0, 1/r₀] |
| 单调性 | 递减 |
| 尾部 | 衰减到 0 |
逆多二次在适定性方面与多二次表现类似,但有上界且衰减到零,性质更接近高斯。其 Javadoc 指出:尽管听起来奇怪,逆多二次的结果与多二次相当、有时更好,因为真正重要的是光滑性以及函数傅里叶变换的某些性质;而且逆多二次会把函数外推到远距离处为零。实现见 InverseMultiquadricRadialBasis.java。
InverseMultiquadricRadialBasis rbf = new InverseMultiquadricRadialBasis(1.0); double v = rbf.f(0.0); // 1/sqrt(0+1) = 1.0 double v2 = rbf.f(3.0); // 1/sqrt(10) ≈ 0.316 // 与多二次的精确倒数关系: // imq.f(r) == 1.0 / mq.f(r) (相同 r₀)这个倒数关系不是口头说法——测试testMultiquadricInverseRelationship对r ∈ [0, 5]逐点断言1/mq.f(r) == imq.f(r)(见 RadialBasisFunctionTest.java)。
Inverse Quadratic(逆二次)
φ(r) = 1 / ( 1 + (r/r₀)² )| 属性 | 值 |
|---|---|
φ(0) | 1 |
| 值域 | (0, 1] |
| 单调性 | 递减 |
| 尾部 | 代数衰减(比高斯重) |
逆二次是完全单调函数(completely monotone),保证了正定性,因而是合法的正定核(positive-definite kernel)。相比高斯,它的尾部更重,在需要捕捉长程相关时很有优势。值得注意的是φ(r₀) = 1/(1+1) = 0.5,即距离恰好等于尺度时取值精确为 0.5,测试testInverseQuadraticKnownValue对此做了断言。实现见 InverseQuadraticRadialBasis.java。
InverseQuadraticRadialBasis rbf = new InverseQuadraticRadialBasis(2.0); double v = rbf.f(0.0); // 1.0 double v2 = rbf.f(2.0); // 0.5 (at r = r₀) double v3 = rbf.f(6.0); // 1/(1+9) = 0.1Thin Plate Spline(薄板样条)
φ(r) = r² log(r / r₀), φ(0) = 0| 属性 | 值 |
|---|---|
φ(0) | 0(极限值) |
r < r₀时符号 | 负 |
r > r₀时符号 | 正 |
φ(r₀) | 0 |
| 尾部 | 以r² log r增长 |
薄板样条源于弹性薄板弯曲的能量最小化问题——它在加权 Sobolev 意义下产生最光滑的插值函数。当r₀ = 1时,它与二阶PolyharmonicSpline完全等价。实现见 ThinPlateRadialBasis.java:源码通过r <= 0.0 ? 0.0 : ...显式处理了φ(0)的极限值,避免出现 NaN。
ThinPlateRadialBasis rbf = new ThinPlateRadialBasis(1.0); double v1 = rbf.f(0.0); // 0.0 (not NaN) double v2 = rbf.f(0.5); // negative (r < r₀) double v3 = rbf.f(1.0); // 0.0 (at r = r₀) double v4 = rbf.f(Math.E); // e² ≈ 7.389 (φ(e) = e²·log(e/1) = e²·1)Polyharmonic Spline(多调和样条)
这是薄板样条以整数阶k参数化的推广,实现见 PolyharmonicSpline.java:
k 为奇数:φ(r) = rᵏ k 为偶数:φ(r) = rᵏ log(r), φ(0) = 0| 阶数 | 公式 | 常用名 |
|---|---|---|
| 1 | r | 线性样条 |
| 2 | r² log r | 薄板样条(r₀ = 1) |
| 3 | r³ | 三次样条 |
| 4 | r⁴ log r | 双调和样条 |
| 5 | r⁵ | — |
高阶样条产生更光滑的插值,但需要在基中加入更多多项式项以保持适定性。源码注释引用 Hardy(1971)的多二次地形插值工作与 Duchon(1977)的 Sobolev 空间极小化理论作为背景。
PolyharmonicSpline linear = new PolyharmonicSpline(1); // φ(r) = r PolyharmonicSpline tps = new PolyharmonicSpline(2); // φ(r) = r² log r (默认) PolyharmonicSpline cubic = new PolyharmonicSpline(3); // φ(r) = r³ PolyharmonicSpline biharm = new PolyharmonicSpline(4); // φ(r) = r⁴ log r int k = tps.order(); // 2 // k=2 与 ThinPlateRadialBasis(1.0) 精确等价: double r = 2.5; double v1 = new PolyharmonicSpline(2).f(r); double v2 = new ThinPlateRadialBasis(1.0).f(r); // v1 == v2 // k=3 是标准三次 RBF: double v3 = new PolyharmonicSpline(3).f(3.0); // 27.0k=2与ThinPlateRadialBasis(1.0)的等价性同样被测试逐点验证(testPolyharmonicOrder2EqualsThinPlate,见 RadialBasisFunctionTest.java)。注意:PolyharmonicSpline的默认无参构造使用k=2,且构造函数要求k为正整数,否则抛出IllegalArgumentException。
汇总对比表
| 类 | 公式 | φ(0) | 尾部 | 有界 |
|---|---|---|---|---|
GaussianRadialBasis | exp(−r²/2r₀²) | 1 | 快速衰减 | ✓ (0,1] |
InverseMultiquadricRadialBasis | 1/√(r²+r₀²) | 1 | 慢速衰减 | ✓ (0,1] |
InverseQuadraticRadialBasis | 1/(1+(r/r₀)²) | 1 | 代数衰减 | ✓ (0,1] |
MultiquadricRadialBasis | √(r²+r₀²) | r₀ | 增长 | ✗ |
ThinPlateRadialBasis | r² log(r/r₀) | 0 | 增长 | ✗ |
PolyharmonicSpline | rᵏ或rᵏ log r | 0 | 增长 | ✗ |
尺度参数r₀的 API 约定
所有基于尺度的 RBF 都暴露scale()方法:
GaussianRadialBasis rbf1 = new GaussianRadialBasis(2.0); MultiquadricRadialBasis rbf2 = new MultiquadricRadialBasis(2.0); InverseMultiquadricRadialBasis rbf3 = new InverseMultiquadricRadialBasis(2.0); InverseQuadraticRadialBasis rbf4 = new InverseQuadraticRadialBasis(2.0); ThinPlateRadialBasis rbf5 = new ThinPlateRadialBasis(2.0); rbf1.scale(); // 2.0所有构造函数都校验r₀ > 0,否则抛出IllegalArgumentException(例如 GaussianRadialBasis.java 中的if (scale <= 0) throw new IllegalArgumentException("scale is not positive: " + scale))。测试testGaussianInvalidScale、testMultiquadricInvalidScale等对0.0与负值均断言抛出该异常。所有类也提供默认无参构造,r₀ = 1:
// 以下均使用 r₀ = 1.0 GaussianRadialBasis g = new GaussianRadialBasis(); MultiquadricRadialBasis m = new MultiquadricRadialBasis(); InverseMultiquadricRadialBasis i = new InverseMultiquadricRadialBasis(); InverseQuadraticRadialBasis q = new InverseQuadraticRadialBasis(); ThinPlateRadialBasis t = new ThinPlateRadialBasis(); PolyharmonicSpline p = new PolyharmonicSpline(); // k=2此外,每个类的toString()都会格式化输出其参数(如GaussianRadialBasis(r0 = 1.0000)、PolyharmonicSpline(k = 2)),便于日志调试。
如何选择尺度r₀
尺度参数对插值质量影响极大。通用经验法则是:
r₀应大于数据点之间的典型间距,但小于被逼近函数的特征尺寸(外部尺度)。
这一准则在 GaussianRadialBasis.java 与 MultiquadricRadialBasis.java 的 Javadoc 中都有明确阐述:r₀的好坏选择可能造成插值精度相差数个数量级,因此值得认真实验调参。
最实用的调参手段是留一交叉验证(leave-one-out cross-validation):
// LOO 尺度搜索伪代码 double bestR0 = 1.0; double bestError = Double.MAX_VALUE; for (double r0 : candidates) { GaussianRadialBasis rbf = new GaussianRadialBasis(r0); // 每次省略一个数据点构建插值器,度量被省略点处的误差 double error = leaveOneOutError(data, rbf); if (error < bestError) { bestError = error; bestR0 = r0; } }在 RBF 网络中使用(RBF Networks)
SMILE 的 RBF 网络使用RadialBasisFunction实例定义每个隐层神经元的激活函数。网络模型位于 RBFNetwork.java,每个神经元由 RBF.java 封装,其激活计算为rbf.f(distance.d(x, center))——即先求样本到中心的度量距离,再送入径向基函数。
import smile.classification.RBFNetwork; import smile.model.rbf.RBF; // 拟合含 30 个神经元的 Gaussian RBF 网络 RBFNetwork<double[]> model = RBFNetwork.fit(x, y, RBF.fit(x, 30)); // 自定义 RBF 类型 GaussianRadialBasis customRbf = new GaussianRadialBasis(0.5); RBF<double[]>[] neurons = RBF.of(centers, customRbf, new EuclideanDistance()); RBFNetwork<double[]> model2 = RBFNetwork.fit(x, y, neurons);RBF.fit(x, 30)在底层使用 K-Means 选取中心并自动估计高斯宽度:默认宽度取d_max / sqrt(2k)(d_max为中心间最大距离,k为中心数),该估计在数据均匀分布时接近最优(见 RBF.java)。RBF.of则支持传入自定义基函数与度量距离,且校验基函数数量必须与中心数量一致(RBF.java)。RBFNetwork还提供了带normalize参数的fit重载以及基于Properties参数的版本(见 RBFNetwork.java)。
在散乱数据插值中使用(RBF Interpolation)
RBF 同样是散乱数据插值的主力方法。SMILE 的smile.interpolation包提供了泛型插值器 RBFInterpolation.java,它直接接受任意RadialBasisFunction:
import smile.interpolation.RBFInterpolation; import smile.math.rbf.GaussianRadialBasis; double[][] x = { /* 散乱数据点 */ }; double[] y = { /* 对应函数值 */ }; // 普通 RBF 插值 RBFInterpolation interp = new RBFInterpolation(x, y, new GaussianRadialBasis(1.0)); // 归一化 RBF(NRBF)插值 RBFInterpolation ninterp = new RBFInterpolation(x, y, new GaussianRadialBasis(1.0), true); double v = interp.interpolate(0.5, 0.5); // 在任意点求值从源码看(RBFInterpolation.java),构造时会构建 n×n 的 Gram 矩阵并用rbf.f(MathEx.distance(x[i], x[j]))填充,随后求解线性方程组求权重:当基函数是GaussianRadialBasis时走 Cholesky 分解,否则走 LU 分解。归一化模式(NRBF)要求基函数之和为 1(即sumw / sum,见 RBFInterpolation.java);该变体源自贝叶斯统计视角,但源码注释也说明并无证据表明 NRBF 一贯优于普通 RBF。
包内还提供了面向 1D / 2D 的便捷子类 RBFInterpolation1D.java 与 RBFInterpolation2D.java。此外,在 RBFInterpolation.java 的类注释中总结了重要结论:薄板样条的适定性对尺度缩放不变;高斯、多二次与逆多二次都是无穷光滑的且包含形状参数r₀ > 0;减小r₀会使基函数更扁平,增大r₀则能改善矩阵适定性(放大的点间分离距离增大)。
如何选择正确的 RBF
| 场景 | 推荐 |
|---|---|
| 一般插值 | GaussianRadialBasis(调优r₀) |
对r₀不太敏感 | MultiquadricRadialBasis |
| 光滑且有界的插值 | InverseMultiquadricRadialBasis |
| 重尾相关 | InverseQuadraticRadialBasis |
| 物理动机的光滑性 | ThinPlateRadialBasis或PolyharmonicSpline(2) |
| C¹ 光滑、紧支撑 | PolyharmonicSpline(3)(三次) |
| 更高阶光滑性 | 更大的k的PolyharmonicSpline(k) |
快速验证与测试
仓库自带完整的单元测试 RadialBasisFunctionTest.java,覆盖每个 RBF 的φ(0)值、已知点取值、单调性、有界性、scale()/order()访问器、默认构造、非法参数异常、toString()格式、跨函数性质(如 IMQ 与 MQ 的倒数关系、k=2 与薄板样条的等价性、衰减型 RBF 有界于 1)以及Serializable能力。运行测试即可快速验证本文中所有数值示例的正确性。
- 人工智能
- 机器学习
- 深度学习
- NLP
- 大模型
- 模型推理服务
- 数据可视化
【免费下载链接】smile
Statistical Machine Intelligence & Learning Engine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考