Optimization Levenberg-Marquardt算法的局限性

Optimization Levenberg-Marquardt算法的局限性,optimization,math,nonlinear-functions,levenberg-marquardt,Optimization,Math,Nonlinear Functions,Levenberg Marquardt,我用它来最小化6个参数的非线性函数。对于每个最小化,我得到了大约50个数据点,但我没有得到足够精确的结果。我的参数彼此相差几个数量级,这一事实是否如此重要?如果是,我应该在哪里寻找解决方案?如果没有,您在工作中遇到了什么样的LMA限制(这可能有助于发现我的应用程序的其他问题)? 非常感谢你的帮助 编辑:我试图解决的问题是确定最佳转换T: typedef struct { double x_translation, y_translation, z_translation; d

我用它来最小化6个参数的非线性函数。对于每个最小化,我得到了大约50个数据点,但我没有得到足够精确的结果。我的参数彼此相差几个数量级,这一事实是否如此重要?如果是,我应该在哪里寻找解决方案?如果没有,您在工作中遇到了什么样的LMA限制(这可能有助于发现我的应用程序的其他问题)? 非常感谢你的帮助

编辑:我试图解决的问题是确定最佳转换T:

typedef struct 
{
    double x_translation, y_translation, z_translation; 
    double x_rotation, y_rotation, z_rotation;
} transform_3D;
将三维点集拟合到三维线束。详细地说,我已经得到了一组3D点的坐标和相应3D线的方程,它们应该穿过这些点(在理想情况下)。LMA最小化变换后的3D点到相应3D线的距离总和。 转换函数如下所示:

cv::Point3d Geometry::transformation_3D(cv::Point3d point, transform_3D transformation)
{
    cv::Point3d p_odd,p_even;

    //rotation x
    p_odd.x=point.x;
    p_odd.y=point.y*cos(transformation.x_rotation)-point.z*sin(transformation.x_rotation); 
    p_odd.z=point.y*sin(transformation.x_rotation)+point.z*cos(transformation.x_rotation);

    //rotation y
    p_even.x=p_odd.z*sin(transformation.y_rotation)+p_odd.x*cos(transformation.y_rotation);
    p_even.y=p_odd.y;
    p_even.z=p_odd.z*cos(transformation.y_rotation)-p_odd.x*sin(transformation.y_rotation);

    //rotation z
    p_odd.x=p_even.x*cos(transformation.z_rotation)-p_even.y*sin(transformation.z_rotation);
    p_odd.y=p_even.x*sin(transformation.z_rotation)+p_even.y*cos(transformation.z_rotation);
    p_odd.z=p_even.z;

    //translation
    p_even.x=p_odd.x+transformation.x_translation;
    p_even.y=p_odd.y+transformation.y_translation;
    p_even.z=p_odd.z+transformation.z_translation;

    return p_even;
}
希望这个解释能对你有所帮助

编辑2:

下面粘贴一些示例性数据。三维线由中心点和方向向量描述。所有直线的中心点为(0,0,0),每个矢量的“uz”坐标等于1。 方向向量的“ux”坐标集:

-1.0986, -1.0986, -1.0986,
-1.0986, -1.0990, -1.0986,
-1.0986, -1.0986, -0.9995,
-0.9996, -0.9996, -0.9995,
-0.9995, -0.9995, -0.9996,
-0.9003, -0.9003, -0.9004,
-0.9003, -0.9003, -0.9003,
-0.9003, -0.9003, -0.8011,
-0.7020, -0.7019, -0.6028,
-0.5035, -0.5037, -0.4045,
-0.3052, -0.3053, -0.2062,
-0.1069, -0.1069, -0.1075,
-0.1070, -0.1070, -0.1069,
-0.1069, -0.1070, -0.0079,
-0.0079, -0.0079, -0.0078,
-0.0078, -0.0079, -0.0079,
 0.0914,  0.0914,  0.0913,
 0.0913,  0.0914,  0.0915,
 0.0914,  0.0914
-0.2032,  -0.0047,    0.1936,
0.3919,    0.5901,    0.7885,
0.9869,    1.1852,    -0.1040,
0.0944,    0.2927,    0.4911,
0.6894,    0.8877,    1.0860,
-0.2032,  -0.0047,    0.1936,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852,    1.0860,
0.9869,    1.1852,    1.0861,
0.9865,    1.1853,    1.0860,
0.9870,    1.1852,    1.0861,
-0.2032,  -0.0047,    0.1937,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852,    -0.1039,
0.0944,    0.2927,    0.4911,
0.6894,    0.8877,    1.0860,
-0.2032,  -0.0047,    0.1935,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852
方向向量的“uy”坐标集:

-1.0986, -1.0986, -1.0986,
-1.0986, -1.0990, -1.0986,
-1.0986, -1.0986, -0.9995,
-0.9996, -0.9996, -0.9995,
-0.9995, -0.9995, -0.9996,
-0.9003, -0.9003, -0.9004,
-0.9003, -0.9003, -0.9003,
-0.9003, -0.9003, -0.8011,
-0.7020, -0.7019, -0.6028,
-0.5035, -0.5037, -0.4045,
-0.3052, -0.3053, -0.2062,
-0.1069, -0.1069, -0.1075,
-0.1070, -0.1070, -0.1069,
-0.1069, -0.1070, -0.0079,
-0.0079, -0.0079, -0.0078,
-0.0078, -0.0079, -0.0079,
 0.0914,  0.0914,  0.0913,
 0.0913,  0.0914,  0.0915,
 0.0914,  0.0914
-0.2032,  -0.0047,    0.1936,
0.3919,    0.5901,    0.7885,
0.9869,    1.1852,    -0.1040,
0.0944,    0.2927,    0.4911,
0.6894,    0.8877,    1.0860,
-0.2032,  -0.0047,    0.1936,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852,    1.0860,
0.9869,    1.1852,    1.0861,
0.9865,    1.1853,    1.0860,
0.9870,    1.1852,    1.0861,
-0.2032,  -0.0047,    0.1937,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852,    -0.1039,
0.0944,    0.2927,    0.4911,
0.6894,    0.8877,    1.0860,
-0.2032,  -0.0047,    0.1935,
0.3919,    0.5902,    0.7885,
0.9869,    1.1852
以及(x.y.z.x.y.z.x.y.z…)形式的3D点集:


这是一种旋转非常小的“简单”建模数据。

好吧,使用Levenberg-Marquardt的正确方法是需要对参数进行良好的初始估计(“种子”)。回想一下LM是Newton Raphson的变体;与此类迭代算法一样,起点的质量将决定迭代的成败;要么收敛到你想要的,收敛到完全不同的东西(不太可能发生,尤其是当你有很多参数的时候),要么向那边的蓝色狂野发射(发散)


在任何情况下,如果你能提到你正在拟合的模型函数,可能还有你数据的散点图,那会更有帮助;这可能会大大有助于找到一个可行的解决方案。

我建议您尝试使用不同的方法来间接找到旋转参数,即使用a合并平移和旋转参数

这消除了正弦和余弦函数的非线性(你可以在事后弄清楚)


困难的部分是限制变换矩阵的剪切或缩放,这是您不想要的。

在这里,您的问题已经建模并使用Mathematica运行

我用了“莱文伯格-马夸特”的方法

这就是为什么我要你的数据。有了我的数据,您的问题总是会变得更容易:)

输出:

(在实际值的1/1000范围内)

编辑

我对你的数据做了一些处理。
问题是你的系统条件很差。需要更多的数据才能有效地计算如此小的旋转

以下是我得到的结果:

以度为单位的旋转:

rx = 179.99999999999999999999984968493536659553226696793
ry = 180.00000000000000000000006934755799995159952661222
rz = 180.0006286861217378980724139120849587855611645627
运输

tx = 48.503663696727576867196234527227830090575281353092
ty = 63.974139455057300403798198525151849767949596684232
tz = -0.99999999999999999999997957276716543927459921348549  
我应该计算一下误差,但我现在没有时间

顺便说一句,rz=Pi+0.000011(弧度)

嗯,我曾经解决过这个问题,但我确实对您的数据进行了修改。我没有使用“uz=1.0”,而是使用了“uz=0.0”,这使得这完全是一个二维数据拟合

我得到了以下结果。 变速箱:-88.6384,-16.3879,0 rot:0,0,-6.97813e-05

得到这些结果后,手动计算变换点到相应直线的正交距离之和,得到0.0280452

struct CostFunctor {
    CostFunctor(const double p[3],  double ux, double uy){
        p_[0] = p[0];p_[1] = p[1];p_[2] = p[2];
        n_[0] = ux; n_[1] = uy;
        n_[2] = 0.0;
        normalize(n_);
    }

    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        T pDash[3];
        T pIn[3];
        T temp[3];
        pIn[0] = T(p_[0]);
        pIn[1] = T(p_[1]);
        pIn[2] = T(p_[2]);
        //transform the input point p_ to pDash
        xform(x, &pIn[0], &pDash[0]);
        //find dot(pDash, n), where n is the direction of line
        T pDashDotN = T(pDash[0]) * T(n_[0]) + T(pDash[1]) * T(n_[1]) + T(pDash[2]) * T(n_[2]);
        //projection of pDash along line
        temp[0] = pDashDotN * n_[0];temp[1] = pDashDotN * n_[1];temp[2] = pDashDotN * n_[2];
        //orthogonal vector from projection to point
        temp[0] = pDash[0] - temp[0];temp[1] = pDash[1] - temp[1];temp[2] = pDash[2] - temp[2];
        //squared error
        residual[0] = temp[0] * temp[0] + temp[1] * temp[1] + temp[2] * temp[2];
    return true;
    }
    //untransformed point
    double p_[3];

    double ux_;
    double uy_;
    //direction of line
    double n_[3];
};


template<typename T>
void  xform(const T *x, const T * inPoint, T *outPoint3) {
    T xTheta = x[3];
    T pOdd[3], pEven[3];
    pOdd[0] = inPoint[0];
    pOdd[1] = inPoint[1] * cos(xTheta) + inPoint[2] * sin(xTheta);
    pOdd[2] = -inPoint[1] * sin(xTheta) + inPoint[2] * cos(xTheta);

    T yTheta = x[4];
    pEven[0] = pOdd[0] * cos(yTheta) + pOdd[2] * sin(yTheta);
    pEven[1] = pOdd[1];
    pEven[2] = -pOdd[0] * sin(yTheta) + pOdd[2] * cos(yTheta);


    T zTheta = x[5];

    pOdd[0] = pEven[0] * cos(zTheta) - pEven[1] * sin(zTheta);
    pOdd[1] = pEven[0] * sin(zTheta) + pEven[1] * cos(zTheta);
    pOdd[2] = pEven[2];

    T xTrans = x[0], yTrans = x[1], zTrans = x[2];
    pOdd[0] += xTrans;
    pOdd[1] += yTrans;
    pOdd[2] += zTrans;

    outPoint3[0] = pOdd[0];
    outPoint3[1] = pOdd[1];
    outPoint3[2] = pOdd[2];
}
struct-CostFunctor{
余函子(常数双p[3],双ux,双uy){
p_[0]=p[0];p_[1]=p[1];p_[2]=p[2];
n_[0]=ux;n_[1]=uy;
n_2]=0.0;
正常化(n_);
}
模板
布尔运算符()(常数T*常数x,T*残差)常数{
T-pDash[3];
T管脚[3];
T温度[3];
pIn[0]=T(p_[0]);
pIn[1]=T(p_[1]);
pIn[2]=T(p_[2]);
//将输入点p_2;转换为pDash
变换(x,&pIn[0],&pDash[0]);
//查找点(pDash,n),其中n是线的方向
T pDashDotN=T(pDash[0])*T(n_u[0])+T(pDash[1])*T(n_u[1])+T(pDash[2])*T(n_u[2]);
//pDash沿直线的投影
temp[0]=pDashDotN*n_[0];temp[1]=pDashDotN*n_[1];temp[2]=pDashDotN*n_[2];
//从投影到点的正交向量
温度[0]=pDash[0]-temp[0];温度[1]=pDash[1]-temp[1];温度[2]=pDash[2]-temp[2];
//平方误差
剩余[0]=温度[0]*温度[0]+温度[1]*温度[1]+温度[2]*温度[2];
返回true;
}
//未转换点
双p_[3];
双ux_u2;;
双uy_u2;;
//线路走向
双n_[3];
};
模板
void变换(常数T*x,常数T*inPoint,T*outPoint3){
T xTheta=x[3];
T pOdd[3],pEven[3];
pOdd[0]=输入点[0];
pOdd[1]=inPoint[1]*cos(xTheta)+inPoint[2]*sin(xTheta);
pOdd[2]=-inPoint[1]*sin(xTheta)+inPoint[2]*cos(xTheta);
T yTheta=x[4];
pEven[0]=pOdd[0]*cos(yTheta)+pOdd[2]*sin(yTheta);
pEven[1]=pOdd[1];
佩文[2]=-pOdd[0]*sin(yTheta)+pOdd[2]*cos(yTheta);
T zTheta=x[5];
pOdd[0]=pEven[0]*cos(zTheta)-pEven[1]*sin(zTheta);
pOdd[1]=pEven[0]*sin(zTheta)+pEven[1]*cos(zTheta);
pOdd[2]=pEven[2];
T xTrans=x[0],yTrans=x[1],zTrans=x[2];
pOdd[0]+=xTrans;
pOdd[1]+=yTrans;
pOdd[2]+=zTrans;
输出点3[0]=pOdd[0];
输出点3[1]=pOdd[1];
输出点3[2]=pOdd[2];
}

Hi Marcin!你能发布模型和一些数据吗?我有一个使用LM的正在运行的优化器,我可以在您的数据上试用它。如果它很大,你可以在pastebin或ideone上发布…@Marcin我看到你使用了[Mathematica]标签。可以吗?我以为你在用c++/qt/OpenGLYes,sor
struct CostFunctor {
    CostFunctor(const double p[3],  double ux, double uy){
        p_[0] = p[0];p_[1] = p[1];p_[2] = p[2];
        n_[0] = ux; n_[1] = uy;
        n_[2] = 0.0;
        normalize(n_);
    }

    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        T pDash[3];
        T pIn[3];
        T temp[3];
        pIn[0] = T(p_[0]);
        pIn[1] = T(p_[1]);
        pIn[2] = T(p_[2]);
        //transform the input point p_ to pDash
        xform(x, &pIn[0], &pDash[0]);
        //find dot(pDash, n), where n is the direction of line
        T pDashDotN = T(pDash[0]) * T(n_[0]) + T(pDash[1]) * T(n_[1]) + T(pDash[2]) * T(n_[2]);
        //projection of pDash along line
        temp[0] = pDashDotN * n_[0];temp[1] = pDashDotN * n_[1];temp[2] = pDashDotN * n_[2];
        //orthogonal vector from projection to point
        temp[0] = pDash[0] - temp[0];temp[1] = pDash[1] - temp[1];temp[2] = pDash[2] - temp[2];
        //squared error
        residual[0] = temp[0] * temp[0] + temp[1] * temp[1] + temp[2] * temp[2];
    return true;
    }
    //untransformed point
    double p_[3];

    double ux_;
    double uy_;
    //direction of line
    double n_[3];
};


template<typename T>
void  xform(const T *x, const T * inPoint, T *outPoint3) {
    T xTheta = x[3];
    T pOdd[3], pEven[3];
    pOdd[0] = inPoint[0];
    pOdd[1] = inPoint[1] * cos(xTheta) + inPoint[2] * sin(xTheta);
    pOdd[2] = -inPoint[1] * sin(xTheta) + inPoint[2] * cos(xTheta);

    T yTheta = x[4];
    pEven[0] = pOdd[0] * cos(yTheta) + pOdd[2] * sin(yTheta);
    pEven[1] = pOdd[1];
    pEven[2] = -pOdd[0] * sin(yTheta) + pOdd[2] * cos(yTheta);


    T zTheta = x[5];

    pOdd[0] = pEven[0] * cos(zTheta) - pEven[1] * sin(zTheta);
    pOdd[1] = pEven[0] * sin(zTheta) + pEven[1] * cos(zTheta);
    pOdd[2] = pEven[2];

    T xTrans = x[0], yTrans = x[1], zTrans = x[2];
    pOdd[0] += xTrans;
    pOdd[1] += yTrans;
    pOdd[2] += zTrans;

    outPoint3[0] = pOdd[0];
    outPoint3[1] = pOdd[1];
    outPoint3[2] = pOdd[2];
}