非线性优化库liblbfgs初探


非线性优化库liblbfgs初探_第1张图片

作者:金良([email protected]) csdn博客: http://blog.csdn.net/u012176591

    • liblbfgs简介
    • Linux下用gcc 编译
    • Windows下用visual studio编译
    • main函数分析
    • python 封装liblbfgs

liblbfgs简介

liblbfgs是L-BFGS算法的C语言实现,用于求解非线性优化问题。

liblbfgs的主页:http://www.chokkan.org/software/liblbfgs/

下载链接(见上面的主页链接):

  • https://github.com/downloads/chokkan/liblbfgs/liblbfgs-1.10.tar.gz 用于Linux平台
  • https://github.com/chokkan/liblbfgs
    用于Windows平台

Linux下用gcc 编译

解压文件,进入目录,可参照 软件包里面的说明文档,命令依次如下:

./configure

make

make install

编译后的目录文件:

C源码文件在lib,includesample 三个文件夹里,而主文件在’sample’ 里,其目录如下:

其中没有文件后缀名的文件sample就是最终的可执行文件,运行:

Windows下用visual studio编译

只需要把几个C/C++源码文件加入到项目即可,其余的文件一律弃之不用,如下图所示的VS项目文件的目录,我们只要 4 个头文件 arithmetic_ansi.h, arithmetic_sse_double.h, arithmetic_sse_float.h, lbfgs.h 和三个源文件
lbfgs.c, sample.c, sample.cpp。

主函数文件(包含main函数)是 sample.c(用C语言写的),和 sample.cpp(用C++写成,封装成一个类)。一个VS项目里只能有一个main函数,所以每次运行要禁用二者中的一个。

需要注意的是头文件中的 arithmetic_ansi.h, arithmetic_sse_double.h, arithmetic_sse_float.h,三个头文件只能用一个,选择哪个由’lbfgs.cpp’中一段代码控制,该段代码如下:

默认情况下 USE_SSE__SSE2____SSE__ 都没有定义,L-BFGS_FLOAT 在 lbfgs.h中定义。由此可知默认情况下采用的是 arithmetic_ansi.h 。

若要采用 arithmetic_sse_double.h,经查L-BFGS_FLOAT 被定义为 64,所以再定义其它两个变量,如下:

非线性优化库liblbfgs初探_第2张图片

SSE2到底是什么东西呢?插入一段相关介绍:

SSE2(Streaming SIMD Extensions 2):指令集,扩展了SSE指令集,并可完全取代MMX。SSE2指令集是Intel公司在SSE指令集的基础上发展起来的。相比于SSE,SSE2使用了144个新增指令,扩展了MMX技术和SSE技术,提高了诸如MPEG-2、MP3、3D图形等应用程序的运行性能。在整数处理方面,随MMX技术引进的SIMD整数指令从64位扩展到了128 位,使SIMD整数类型操作的执行效率成倍提高;在浮点数处理方面,双精度浮点SIMD指令允许以 SIMD格式同时执行两个浮点操作,提供双精度操作支持有助于加速内容创建、财务、工程和科学应用。除SSE2指令之外,最初的SSE指令也得到增强,通过支持多种数据类型(例如双字、四字)的算术运算,支持灵活、动态范围更广的计算功能。

可见引入 arithmetic_sse_double.h 或 arithmetic_sse_float.h 是为了提高浮点数的运算速度,改善程序性能。

main函数分析

main函数里给出了一个用L-BFGS算法进行非线性优化的例子,贴出main函数的代码:

#include <stdio.h>
#include "lbfgs.h"

//注意lbfgsfloatval_t在lbfgs.h里定义,32位机上是float,64位机上是double。

//evaluate定义要优化的非线性函数fx及其梯度g
static lbfgsfloatval_t evaluate( 
    void *instance,
    const lbfgsfloatval_t *x,
    lbfgsfloatval_t *g,
    const int n,
    const lbfgsfloatval_t step
    )
{
    int i;
    lbfgsfloatval_t fx = 0.0;

    for (i = 0;i < n;i += 2) {
        lbfgsfloatval_t t1 = 1.0 - x[i];
        lbfgsfloatval_t t2 = 10.0 * (x[i+1] - x[i] * x[i]);
        g[i+1] = 20.0 * t2;
        g[i] = -2.0 * (x[i] * g[i+1] + t1);
        fx += t1 * t1 + t2 * t2;
    }
    return fx;
}

//progress函数每次迭代结束就执行一次,打印迭代信息
static int progress(
    void *instance,
    const lbfgsfloatval_t *x,
    const lbfgsfloatval_t *g,
    const lbfgsfloatval_t fx,
    const lbfgsfloatval_t xnorm,
    const lbfgsfloatval_t gnorm,
    const lbfgsfloatval_t step,
    int n,
    int k,
    int ls
    )
{
    printf("Iteration %d:\n", k);
    printf(" fx = %f,", fx);
    printf(" xnorm = %f, gnorm = %f, step = %f\n", xnorm, gnorm, step);
    return 0;
}

#define N 100 //参数个数

int main(int argc, char *argv[])
{

    int i, ret = 0;
    lbfgsfloatval_t fx;
    lbfgsfloatval_t *x = lbfgs_malloc(N); //x是长度为N的数组
    lbfgs_parameter_t param;

    if (x == NULL) {
        printf("ERROR: Failed to allocate a memory block for variables.\n");
        return 1;
    }

    /* Initialize the variables. */
    for (i = 0;i < N;i += 2) {
        x[i] = -1.2;
        x[i+1] = 1.0;
    }

    /* Initialize the parameters for the L-BFGS optimization. */
    lbfgs_parameter_init(&param);
    /*param.linesearch = LBFGS_LINESEARCH_BACKTRACKING;*/

    /* Start the L-BFGS optimization; this will invoke the callback functions evaluate() and progress() when necessary. */
    ret = lbfgs(N, x, &fx, evaluate, progress, NULL, &param);

    printf("算法收敛后的函数取值 fx = %f\n", fx, x[0], x[1]);

    printf("最终的解(长度为100个浮点数的数组):");
    for(i=0;i<N;i++) {
        if (i%10 == 0) {
            printf("\n");
        }
        printf("%2.2lf ",x[i]);
    }
    lbfgs_free(x); //释放参数数组所占的内存

    return 0;
}

非线性函数 f(x) 及其 梯度 g(x) 的定义如下:

for (i = 0;i < n;i += 2) {
    lbfgsfloatval_t t1 = 1.0 - x[i];
    lbfgsfloatval_t t2 = 10.0 * (x[i+1] - x[i] * x[i]);
    g[i+1] = 20.0 * t2;
    g[i] = -2.0 * (x[i] * g[i+1] + t1);
    fx += t1 * t1 + t2 * t2;
}

可知输入参数 有100个,即数组 x ,函数 f(x) 定义如下

f(x)=i=0,2,4,...,N2(1xi)2+(10(xi+1x2i))2

其奇数位置 (i=1,3,5,...) 的参数的梯度
200(xi+1x2i)

其偶数位置 (i=0,2,4,6,...) 的参数的梯度
2(1xi)400xi(xi+1x2i)

python 封装liblbfgs

  • pylbfgs 用Python封装的 liblbfgs
    https://github.com/larsmans/pylbfgs
  • PyLBFGS
    https://github.com/sseemayer/PyLBFGS/blob/master/test.py

你可能感兴趣的:(liblbfgs)