使用ensmallen优化约束函数遇问题:求解后变量未更新
解决ensmallen约束优化中AugLagrangian未更新变量的问题
我尝试用ensmallen实现约束优化,目标函数是f(x)=x²,约束条件为x=3,初始值设为x=-1,预期结果是x=3,但实际求解后x没有变化。编写了最小可运行示例但未找到错误,请求帮助。
原代码如下:
#include <iostream> #include "ensmallen.hpp" using namespace ens; class ConstrainedFunctionType { public: // f(x) = x * x double Evaluate(const arma::mat& x){ return x(0,0) * x(0,0); } // f'(x) = 2x void Gradient(const arma::mat& x, arma::mat& g){ g(0,0) = 2*x(0,0); } // 1 Constraint, x = 3 size_t NumConstraints(){ return 1; } // Return distance from x to 3 double EvaluateConstraint(const size_t i, const arma::mat& x){ if(x(0,0) < 3){ return 3 - x(0,0); } else if(x(0,0) > 3){ return x(0,0) - 3; } return 0; } // If x was too small, gradient = 1 so it increases // If x was too big, gradient =-1 so it decreases void GradientConstraint(const size_t i, const arma::mat& x, arma::mat& g){ g.reshape(1,1); if(x(0,0) < 3){ g(0,0) = 1; } else if (x(0,0) > 3){ g(0,0) = -1; } } }; int main() { ConstrainedFunctionType f; arma::mat x (1,1); x(0,0) = -1; arma::cout << "init = " << x << arma::endl; AugLagrangian optimizer; optimizer.Optimize(f, x); arma::cout << "result = " << x << arma::endl; return 0; }
问题分析
代码存在两个核心问题导致优化失效:
- 约束函数形式不符合要求:AugLagrangian对等式约束的处理需要标准的
h(x)=0形式,原代码返回绝对值将等式约束转化为非光滑的不等式约束,破坏了优化算法的收敛条件。 - 约束梯度存在未定义情况:当
x=3时,GradientConstraint未对梯度赋值,会产生未初始化的内存值,干扰优化迭代。 - 默认优化器参数强度不足:默认的惩罚参数、迭代次数无法驱动变量从初始点
-1移动到约束点3。
修正后的代码
#include <iostream> #include "ensmallen.hpp" using namespace ens; class ConstrainedFunctionType { public: // f(x) = x * x double Evaluate(const arma::mat& x){ return x(0,0) * x(0,0); } // f'(x) = 2x void Gradient(const arma::mat& x, arma::mat& g){ g(0,0) = 2*x(0,0); } // 1 个等式约束:x = 3 size_t NumConstraints(){ return 1; } // 等式约束标准形式:h(x) = x - 3 = 0 double EvaluateConstraint(const size_t i, const arma::mat& x){ return x(0,0) - 3; } // 约束的梯度:d(h(x))/dx = 1,无需分支判断 void GradientConstraint(const size_t i, const arma::mat& x, arma::mat& g){ g.resize(1, 1); // 确保梯度矩阵尺寸正确 g(0,0) = 1.0; } }; int main() { ConstrainedFunctionType f; arma::mat x (1,1); x(0,0) = -1; arma::cout << "init = " << x << arma::endl; // 调整优化器参数,增强约束惩罚力度与迭代次数 AugLagrangian optimizer( 1000, // 最大迭代次数 1e-6, // 收敛阈值 10.0, // 初始惩罚参数 2.0, // 惩罚参数缩放因子 1e-6, // 约束容忍度 true // 打印迭代信息(可选,便于调试) ); optimizer.Optimize(f, x); arma::cout << "result = " << x << arma::endl; return 0; }
关键修正说明
- 约束函数标准化:将约束改为
x-3,符合AugLagrangian要求的等式约束h(x)=0形式,保证函数可微性。 - 约束梯度完整性:直接设置梯度为1,避免未赋值的未定义行为,确保梯度计算稳定。
- 优化器参数调优:
- 提升最大迭代次数,保证优化有足够步骤收敛
- 提高初始惩罚参数,增强约束的优先级
- 设置惩罚参数缩放因子,迭代中逐步加大约束力度
- 开启迭代日志,方便追踪优化过程
内容的提问来源于stack exchange,提问作者Adrian8
相关产品推荐
相关产品推荐

