共计 2147 个字符,预计需要花费 6 分钟才能阅读完成。
数学背景:鲁棒核函数如何工作
在非线性优化问题中,异常值(outliers)会导致目标函数偏离真实的最小值。鲁棒核函数通过降低异常值的权重,使得优化过程对异常值不敏感。数学上,鲁棒核函数作用于残差上,形式如下:

$$
\rho(s) = \rho\left(|f(x)|^2\right)
$$
其中,(f(x)) 是残差函数,(\rho) 是鲁棒核函数。Ceres Solver 通过修改残差的平方项来抑制异常值的影响。
常见损失函数对比
以下是几种常用的损失函数及其特性:
| 损失函数 | 公式 | 适用场景 |
|---|---|---|
| HuberLoss | (\rho(s) = \begin{cases} s & \text{if} s \leq 1 \ 2\sqrt{s} – 1 & \text{otherwise} \end{cases}) | 适度抑制异常值 |
| CauchyLoss | (\rho(s) = \log(1 + s)) | 强异常值抑制 |
| SoftLOneLoss | (\rho(s) = 2(\sqrt{1 + s} – 1)) | 平滑过渡,适合中等异常值 |
代码实战:Bundle Adjustment 中的损失函数应用
下面是一个完整的 Ceres 示例,展示如何在 Bundle Adjustment 中使用不同的损失函数:
#include <ceres/ceres.h>
#include <gflags/gflags.h>
DEFINE_string(loss_function, "huber", "Type of loss function (huber, cauchy, softlone)");
DEFINE_double(scale, 1.0, "Scale parameter for the loss function");
struct BundleAdjustmentCostFunctor {BundleAdjustmentCostFunctor(const Eigen::Vector2d& observed) : observed_(observed) {}
template <typename T>
bool operator()(const T* const camera, const T* const point, T* residuals) const {
// Project 3D point to 2D image plane
// ... (omitted for brevity)
return true;
}
static ceres::CostFunction* Create(const Eigen::Vector2d& observed) {
return new ceres::AutoDiffCostFunction<BundleAdjustmentCostFunctor, 2, 9, 3>(new BundleAdjustmentCostFunctor(observed));
}
Eigen::Vector2d observed_;
};
int main(int argc, char** argv) {google::ParseCommandLineFlags(&argc, &argv, true);
ceres::Problem problem;
ceres::LossFunction* loss_function = nullptr;
if (FLAGS_loss_function == "huber") {loss_function = new ceres::HuberLoss(FLAGS_scale);
} else if (FLAGS_loss_function == "cauchy") {loss_function = new ceres::CauchyLoss(FLAGS_scale);
} else if (FLAGS_loss_function == "softlone") {loss_function = new ceres::SoftLOneLoss(FLAGS_scale);
}
// Add residuals to the problem
// ... (omitted for brevity)
ceres::Solver::Options options;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
std::cout << summary.FullReport() << std::endl;
return 0;
}
性能调优与避坑指南
-
缩放因子(scale parameter):设置不当会导致数值不稳定。通常需要根据残差的分布进行调整。
-
自动微分 vs 数值微分 :优先使用
AutoDiff,它比NumericDiff更高效且精确。确保模板化代码正确,避免运行时错误。 -
算法选择 :LM 算法通常对损失函数的选择更敏感,而 DOGLEG 算法可能更稳定。可以通过实验选择合适的算法。
延伸思考
尝试将自定义损失函数与 Ceres 的 LocalParameterization 结合使用,可以进一步优化特定问题的求解效率。例如,在 SLAM 中,自定义的旋转参数化可能带来更好的收敛性。
总结
选择合适的损失函数是优化问题中的关键步骤。通过实验和调整,可以显著提升 Ceres Solver 的性能和鲁棒性。希望本文能帮助你在实际项目中更好地应用 Ceres。
正文完
发表至: 未分类
近三天内
