Car*_*izz 7 mathematical-optimization nonlinear-optimization ceres-solver
我正在阅读 Ceres Solver教程。
鲍威尔的函数映射自R^4 -> R^4,因此定义一个接受 4 元素数组x并填充 4 元素数组 的残差块似乎很直观residual。
相反,教程中的示例定义了映射 的 4 个不同的残差块R^2 -> R^1。
当然,如果我们试图最小化1/2 || F(x) ||^2,那么最小化 的每个元素F将隐式产生与直接最小化相同的解决方案1/2 || F(x) ||^2(即我的建议是返回单个残差向量F而不是F1...F4单独)。(我已经通过使用下面的成本函子验证了这一点)。
struct F {
template<typename T>
bool operator() (const T* const x, T* residual) const {
residual[0] = x[0] + 10.0 * x[1];
residual[1] = sqrt(5.0) * (x[2] - x[3]);
residual[2] = (x[1] - 2.0*x[2]) * (x[1] - 2.0*x[2]);
residual[3] = T(sqrt(10.0)) * (x[0] - x[3]) * (x[0] - x[3]);
return true;
}
};
Run Code Online (Sandbox Code Playgroud)
为残差向量的每个元素定义单独的残差块(和隐式参数块)有什么好处F?
如果残差F1取决于参数x1和x2,残差F2取决于x3和x4,则 的成本会F影响x1的值吗x3?
另一个示例尝试查找参数m并c绘制曲线y=e^(mx + c)。
它定义了一些ExponentialResidual简单地输出数据点在T(y_) - exp(m[0] * T(x_) + c[0])哪里的内容。(x_, y_)
然后他们继续为每个观察添加一个残差块
double m = 0.0;
double c = 0.0;
Problem problem;
for (int i = 0; i < kNumObservations; ++i) {
CostFunction* cost_function =
new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
new ExponentialResidual(data[2 * i], data[2 * i + 1]));
problem.AddResidualBlock(cost_function, NULL, &m, &c);
}
Run Code Online (Sandbox Code Playgroud)
R^2 -> R^1,其中一维残差只是所有残差的T(y_) - exp(m[0] * T(x_) + c[0])总和(x_, y_)?是否有必要为每个观察定义一个残差块?感谢您阅读这篇长篇文章!
小智 8
主要原因是 Ceres 仅在参数和残差块级别考虑稀疏性,而不是单个项。对于真正密集的问题,其中每个残差项都取决于每个参数,问题的表示方式对运行时性能没有显着影响。
然而,Ceres 旨在处理非常大的稀疏问题,其中每个残差项仅依赖于几个参数,但有很多参数和残差。利用这些问题的稀疏结构来有效地解决它们是绝对关键的——即避免所有项都为零的大量无意义的计算。虽然线性代数在数学上是相同的,但在处理稀疏矩阵时,线性系统的表示和求解方法却截然不同。
第二个原因是它使问题建模变得更容易。损失函数应用于:r^T * r(其中r是残差块)的结果。如果只有一个残差块,则损失函数会有效地缩放总成本,而不是仅降低问题中具有大误差的部分的权重(异常值拒绝)。Ceres还可以线程化残差块的评估,从而加快大问题的评估速度。
你问题的最后一部分是不同的。在曲线拟合示例中,有两个参数和 kNumObservations 残差,问题严重超定。然而,如果您有一个残差在内部计算 kNumObservations 点的误差,但只返回它们的总和,那么所解决的问题有两个参数,但只有一个残差,并且是欠定的。作为单独的说明,返回它们的总和也会有所不同,因为您没有返回平方和,因此不同残差中不同符号的错误可以有效地相互抵消 - 求解器无法观察到这些错误。
| 归档时间: |
|
| 查看次数: |
2423 次 |
| 最近记录: |