作者:金良([email protected]) csdn博客: http://blog.csdn.net/u012176591
liblbfgs是L-BFGS算法的C语言实现,用于求解非线性优化问题。
liblbfgs的主页:http://www.chokkan.org/software/liblbfgs/
下载链接(见上面的主页链接):
解压文件,进入目录,可参照 软件包里面的说明文档,命令依次如下:
./configure
make
make install
编译后的目录文件:
C源码文件在lib
,include
和 sample
三个文件夹里,而主文件在’sample’ 里,其目录如下:
其中没有文件后缀名的文件sample
就是最终的可执行文件,运行:
只需要把几个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,所以再定义其它两个变量,如下:
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函数里给出了一个用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(¶m);
/*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, ¶m);
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) 定义如下