You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ceres Solver估计参数不确定性的问题求助

问题

使用Ceres Solver对小型数据集做非线性曲线拟合时,能得到与数据匹配良好的参数,但计算参数方差时结果异常——方差比参数本身大数个数量级。数据集点数与拟合模型参数数量接近,比如4个数据点对应3个参数。已知残差缩放会影响协方差矩阵计算的可信度,但缺乏数学背景,不清楚如何调整,求改进建议。

代码片段

代价函数

struct BiExponential1 {
BiExponential1( double x, double y, double s ) : x_( x ), y_( y ), s_( s ) {}
template <typename T>
bool operator()( const T* const a, const T* const b, const T* const c, T* residual ) const {
    residual[0] = y_ - a[0] * ( exp( -b[0] * x_ ) - exp( -c[0] * x_ ) ); // observed - estimated = y - ( a' [exp( -b' * x ) - exp(-c' * x)] )
    return true;
}
private:
    const double x_;
    const double y_;
};

Solver/Covariance 使用代码

double a = init_value_a;
double b = init_value_b;
double c = init_value_c;

double data_x[nData] = {<dummy data>};
double data_y[nData] = {<dummy data>};

for ( int i = 0; i < nData; ++i ) {
    problem.AddParameterBlock( &a, 1 );
    problem.AddParameterBlock( &b, 1 );
    problem.AddParameterBlock( &c, 1 );
    problem.AddResidualBlock(
        new ceres::AutoDiffCostFunction<BiExponential1, 1, 1, 1, 1>(
            new BiExponential1( data_x[i], data_y[i] ) ), 
        nullptr,
        &a,
        &b,
        &c );
}

// Run the solver and record the results.
ceres::Solve( solverOptions, &problem, &summary );

// Variance estimates
// Code adapted from: http://ceres-solver.org/nnls_covariance.html#example-usage
Covariance::Options covOptions;
// TESTED non-default algorithm type - no effect.
//covOptions.algorithm_type = ceres::CovarianceAlgorithmType::DENSE_SVD;
Covariance covariance( covOptions );

std::vector<std::pair<const double*, const double*> > covariance_blocks;
covariance_blocks.push_back( std::make_pair( &a, &a ) );
covariance_blocks.push_back( std::make_pair( &b, &b ) );
covariance_blocks.push_back( std::make_pair( &c, &c ) );
covariance_blocks.push_back( std::make_pair( &a, &b ) );
covariance_blocks.push_back( std::make_pair( &a, &c ) );
covariance_blocks.push_back( std::make_pair( &b, &c ) );

CHECK( covariance.Compute( covariance_blocks, &problem ) );

// Get the diagonal variance terms
double covariance_aa[1 * 1];
double covariance_bb[1 * 1];
double covariance_cc[1 * 1];
covariance.GetCovarianceBlock( &a, &a, covariance_aa );
covariance.GetCovarianceBlock( &b, &b, covariance_bb );
covariance.GetCovarianceBlock( &c, &c, covariance_cc );
关键问题与改进建议
  • 参数块重复添加:循环中每次都调用AddParameterBlock添加a、b、c,会让Ceres把同一个参数当成多个独立参数处理,严重干扰协方差计算。正确做法是仅在循环外添加一次参数块,循环内只添加残差块。
  • 数据集自由度不足:4个数据点对应3个参数,自由度仅为1,这种情况下协方差矩阵的估计本身就极不稳定,方差偏大是数学上的必然结果。如果可能,尽量收集更多数据点,让自由度(数据点数-参数数)至少大于3,才能得到可靠的方差估计。
  • 残差未做归一化处理:Ceres计算协方差时默认假设残差是归一化的(残差方差为1),如果残差实际量级很大,会直接导致协方差被放大。可以通过两种方式修正:
    1. 利用数据的噪声水平s_(代价函数中定义但未使用的参数)归一化残差,把残差计算改成residual[0] = (y_ - a[0] * (exp(-b[0]*x_) - exp(-c[0]*x_))) / s_;
    2. 给残差块添加缩放损失函数,比如使用ceres::ScaledLoss手动调整残差量级。
  • 协方差算法选择:当自由度低导致矩阵病态时,启用DENSE_SVD算法(取消代码中对应行的注释),SVD对病态矩阵的处理能力更强,能提升协方差计算的稳定性。

内容的提问来源于stack exchange,提问作者Spencer Manwell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 05:54:17