OptimLib เป็นไลบรารี C ++ ที่มีน้ำหนักเบาของวิธีการเพิ่มประสิทธิภาพเชิงตัวเลขสำหรับฟังก์ชั่นไม่เชิงเส้น
คุณสมบัติ:
float ) หรือห้องสมุดความแม่นยำสองเท่า ( double )รายการอัลกอริทึมที่มีอยู่ในปัจจุบันรวมถึง:
เอกสารฉบับเต็มมีให้ออนไลน์:
เอกสารเวอร์ชัน PDF มีอยู่ที่นี่
OptimLiB API เป็นไปตามการประชุมที่ค่อนข้างง่ายโดยมีอัลกอริทึมส่วนใหญ่เรียกในลักษณะดังต่อไปนี้:
algorithm_id(<initial/final values>, <objective function>, <objective function data>);
อินพุตตามลำดับคือ:
ตัวอย่างเช่นอัลกอริทึม BFGS เรียกใช้โดยใช้
bfgs (ColVec_t& init_out_vals, std::function< double ( const ColVec_t& vals_inp, ColVec_t* grad_out, void * opt_data)> opt_objfn, void* opt_data); โดยที่ ColVec_t ถูกใช้เพื่อเป็นตัวแทนเช่น arma::vec หรือ Eigen::VectorXd ประเภท
OptimLib มีให้บริการเป็นไลบรารีที่ใช้ร่วมกันหรือเป็นไลบรารีส่วนหัวอย่างเดียวสำหรับระบบ UNIX-ALIKE เท่านั้น (เช่น distros ที่ใช้ Linux ที่ได้รับความนิยมรวมถึง MacOS) ไม่รองรับ การใช้ไลบรารีนี้กับระบบที่ใช้ Windows โดยมีหรือไม่มี MSVC
OptimLib ต้องการ armadillo หรือ eigen C ++ ไลบรารีพีชคณิตเชิงเส้น (โปรดทราบว่า Eigen เวอร์ชัน 3.4.0 ต้องการคอมไพเลอร์ C ++ 14 ที่เข้ากันได้))
ก่อนที่จะรวมไฟล์ส่วนหัวให้กำหนด ข้อใด ต่อไปนี้:
# define OPTIM_ENABLE_ARMA_WRAPPERS
# define OPTIM_ENABLE_EIGEN_WRAPPERSตัวอย่าง:
# define OPTIM_ENABLE_EIGEN_WRAPPERS
# include " optim.hpp " ห้องสมุดสามารถติดตั้งบนระบบ Unix-Aliike ผ่านมาตรฐาน ./configure && make method
ก่อนอื่นโคลนห้องสมุดและ submodules ที่จำเป็น:
# clone optim into the current directory
git clone https://github.com/kthohr/optim ./optim
# change directory
cd ./optim
# clone necessary submodules
git submodule update --init ตั้งค่า (หนึ่ง) ของตัวแปรสภาพแวดล้อมต่อไปนี้ ก่อนที่ จะเรียกใช้ configure :
export ARMA_INCLUDE_PATH=/path/to/armadillo
export EIGEN_INCLUDE_PATH=/path/to/eigenในที่สุด:
# build and install with Eigen
./configure -i " /usr/local " -l eigen -p
make
make install คำสั่งสุดท้ายจะติดตั้ง OptimLib ลงใน /usr/local
ตัวเลือกการกำหนดค่า (ดู ./configure -h ):
หลัก
-h ช่วยพิมพ์-i เส้นทางการติดตั้ง; ค่าเริ่มต้น: ไดเรกทอรีบิลด์-f โหมดความแม่นยำจุดลอยตัว; ค่าเริ่มต้น: double-l ระบุตัวเลือกของไลบรารีพีชคณิตเชิงเส้น เลือก arma หรือ eigen-m ระบุไลบรารี BLAS และ LAPACK เพื่อเชื่อมโยงกับ; ตัวอย่างเช่น -m "-lopenblas" หรือ -m "-framework Accelerate"-o ตัวเลือกการเพิ่มประสิทธิภาพคอมไพเลอร์; ค่าเริ่มต้นเป็น -O3 -march=native -ffp-contract=fast -flto -DARMA_NO_DEBUG-p เปิดใช้งานคุณสมบัติการทำให้คู่ขนาน OpenMP ( แนะนำ )รอง
-c การสร้างความครอบคลุม (ใช้กับ codecov)-d สร้าง 'การพัฒนา'-g การดีบักบิลด์ (ธงปรับให้เหมาะสมตั้งค่าเป็น -O0 -g )พิเศษ
--header-only-version สร้าง OptimLib เวอร์ชันส่วนหัวเท่านั้น (ดูด้านล่าง) OptimLib ยังมีอยู่ในห้องสมุดส่วนหัวเท่านั้น (เช่นโดยไม่จำเป็นต้องรวบรวมไลบรารีที่ใช้ร่วมกัน) เพียงแค่เรียก configure ด้วยตัวเลือก --header-only-version :
./configure --header-only-version สิ่งนี้จะสร้างไดเรกทอรีใหม่ header_only_version ซึ่งมีสำเนาของ OptimLib แก้ไขให้ทำงานบนพื้นฐานแบบอินไลน์ ด้วยเวอร์ชันส่วนหัวอย่างเดียวเพียงแค่รวมไฟล์ส่วนหัว ( #include "optim.hpp ) และตั้งค่าพา ธ รวมไปยังไดเรกทอรี head_only_version (เช่น -I/path/to/optimlib/header_only_version )
หากต้องการใช้ OptimLib ด้วยแพ็คเกจ R ให้สร้างไลบรารีรุ่นส่วนหัวอย่างเดียว (ดูด้านบน) จากนั้นเพียงเพิ่มคำจำกัดความคอมไพเลอร์ก่อนที่จะรวมไฟล์ OptimLib
# define OPTIM_USE_RCPP_ARMADILLO
# include " optim.hpp "# define OPTIM_USE_RCPP_EIGEN
# include " optim.hpp " เพื่อแสดงให้เห็นถึง OptimLib ในที่ทำงานให้พิจารณาค้นหาขั้นต่ำทั่วโลกของฟังก์ชั่น Ackley:

นี่คือฟังก์ชั่นการทดสอบที่รู้จักกันดีพร้อม minima ท้องถิ่นมากมาย วิธีการประเภทนิวตัน (เช่น BFGs) มีความอ่อนไหวต่อการเลือกค่าเริ่มต้นและจะทำงานได้ค่อนข้างไม่ดีที่นี่ ดังนั้นเราจะใช้วิธีการค้นหาทั่วโลก-ในกรณีนี้: วิวัฒนาการที่แตกต่างกัน
รหัส:
# define OPTIM_ENABLE_EIGEN_WRAPPERS
# include " optim.hpp "
# define OPTIM_PI 3.14159265358979
double
ackley_fn ( const Eigen::VectorXd& vals_inp, Eigen::VectorXd* grad_out, void * opt_data)
{
const double x = vals_inp ( 0 );
const double y = vals_inp ( 1 );
const double obj_val = 20 + std::exp ( 1 ) - 20 * std::exp ( - 0.2 * std::sqrt ( 0.5 *(x*x + y*y)) ) - std::exp ( 0.5 *( std::cos ( 2 * OPTIM_PI * x) + std::cos ( 2 * OPTIM_PI * y)) );
return obj_val;
}
int main ()
{
Eigen::VectorXd x = 2.0 * Eigen::VectorXd::Ones ( 2 ); // initial values: (2,2)
bool success = optim::de (x, ackley_fn, nullptr );
if (success) {
std::cout << " de: Ackley test completed successfully. " << std::endl;
} else {
std::cout << " de: Ackley test completed unsuccessfully. " << std::endl;
}
std::cout << " de: solution to Ackley test: n " << x << std::endl;
return 0 ;
}ในคอมพิวเตอร์ที่ใช้ X86 ตัวอย่างนี้สามารถรวบรวมได้โดยใช้:
g++ -Wall -std=c++14 -O3 -march=native -ffp-contract=fast -I/path/to/eigen -I/path/to/optim/include optim_de_ex.cpp -o optim_de_ex.out -L/path/to/optim/lib -loptimเอาท์พุท:
de: Ackley test completed successfully.
elapsed time: 0.028167s
de: solution to Ackley test:
-1.2702e-17
-3.8432e-16
บนแล็ปท็อปมาตรฐาน OptimLib จะคำนวณวิธีแก้ปัญหาภายในความแม่นยำของเครื่องในส่วนที่สอง
ตัวอย่างที่ใช้ armadillo ที่ใช้ตัวอย่างนี้:
# define OPTIM_ENABLE_ARMA_WRAPPERS
# include " optim.hpp "
# define OPTIM_PI 3.14159265358979
double
ackley_fn ( const arma::vec& vals_inp, arma::vec* grad_out, void * opt_data)
{
const double x = vals_inp ( 0 );
const double y = vals_inp ( 1 );
const double obj_val = 20 + std::exp ( 1 ) - 20 * std::exp ( - 0.2 * std::sqrt ( 0.5 *(x*x + y*y)) ) - std::exp ( 0.5 *( std::cos ( 2 * OPTIM_PI * x) + std::cos ( 2 * OPTIM_PI * y)) );
return obj_val;
}
int main ()
{
arma::vec x = arma::ones ( 2 , 1 ) + 1.0 ; // initial values: (2,2)
bool success = optim::de (x, ackley_fn, nullptr );
if (success) {
std::cout << " de: Ackley test completed successfully. " << std::endl;
} else {
std::cout << " de: Ackley test completed unsuccessfully. " << std::endl;
}
arma::cout << " de: solution to Ackley test: n " << x << arma::endl;
return 0 ;
}รวบรวมและเรียกใช้:
g++ -Wall -std=c++11 -O3 -march=native -ffp-contract=fast -I/path/to/armadillo -I/path/to/optim/include optim_de_ex.cpp -o optim_de_ex.out -L/path/to/optim/lib -loptim
./optim_de_ex.out ตรวจสอบไดเรกทอรี /tests สำหรับตัวอย่างเพิ่มเติมและ https://optimlib.readthedocs.io/en/latest/ สำหรับคำอธิบายโดยละเอียดของอัลกอริทึมแต่ละตัว
สำหรับตัวอย่างที่ใช้ข้อมูลให้พิจารณาการประมาณค่าความน่าจะเป็นสูงสุดของแบบจำลอง logit ซึ่งพบได้ทั่วไปในสถิติและการเรียนรู้ของเครื่อง ในกรณีนี้เรามีการแสดงออกแบบปิดสำหรับการไล่ระดับสีและ Hessian เราจะใช้วิธีการไล่ระดับสีที่ได้รับความนิยม Adam (การประมาณโมเมนต์แบบปรับตัว) และเปรียบเทียบกับอัลกอริทึมที่ใช้นิวตันบริสุทธิ์
# define OPTIM_ENABLE_ARMA_WRAPPERS
# include " optim.hpp "
// sigmoid function
inline
arma::mat sigm ( const arma::mat& X)
{
return 1.0 / ( 1.0 + arma::exp (-X));
}
// log-likelihood function data
struct ll_data_t
{
arma::vec Y;
arma::mat X;
};
// log-likelihood function with hessian
double ll_fn_whess ( const arma::vec& vals_inp, arma::vec* grad_out, arma::mat* hess_out, void * opt_data)
{
ll_data_t * objfn_data = reinterpret_cast < ll_data_t *>(opt_data);
arma::vec Y = objfn_data-> Y ;
arma::mat X = objfn_data-> X ;
arma::vec mu = sigm (X*vals_inp);
const double norm_term = static_cast < double >(Y. n_elem );
const double obj_val = - arma::accu ( Y% arma::log (mu) + ( 1.0 -Y)% arma::log ( 1.0 -mu) ) / norm_term;
//
if (grad_out)
{
*grad_out = X. t () * (mu - Y) / norm_term;
}
//
if (hess_out)
{
arma::mat S = arma::diagmat ( mu%( 1.0 -mu) );
*hess_out = X. t () * S * X / norm_term;
}
//
return obj_val;
}
// log-likelihood function for Adam
double ll_fn ( const arma::vec& vals_inp, arma::vec* grad_out, void * opt_data)
{
return ll_fn_whess (vals_inp,grad_out, nullptr ,opt_data);
}
//
int main ()
{
int n_dim = 5 ; // dimension of parameter vector
int n_samp = 4000 ; // sample length
arma::mat X = arma::randn (n_samp,n_dim);
arma::vec theta_0 = 1.0 + 3.0 * arma::randu (n_dim, 1 );
arma::vec mu = sigm (X*theta_0);
arma::vec Y (n_samp);
for ( int i= 0 ; i < n_samp; i++)
{
Y (i) = ( arma::as_scalar ( arma::randu ( 1 )) < mu (i) ) ? 1.0 : 0.0 ;
}
// fn data and initial values
ll_data_t opt_data;
opt_data. Y = std::move (Y);
opt_data. X = std::move (X);
arma::vec x = arma::ones (n_dim, 1 ) + 1.0 ; // initial values
// run Adam-based optim
optim:: algo_settings_t settings;
settings. gd_method = 6 ;
settings. gd_settings . step_size = 0.1 ;
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now ();
bool success = optim::gd (x,ll_fn,&opt_data,settings);
std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now ();
std::chrono::duration< double > elapsed_seconds = end-start;
//
if (success) {
std::cout << " Adam: logit_reg test completed successfully. n "
<< " elapsed time: " << elapsed_seconds. count () << " s n " ;
} else {
std::cout << " Adam: logit_reg test completed unsuccessfully. " << std::endl;
}
arma::cout << " n Adam: true values vs estimates: n " << arma::join_rows (theta_0,x) << arma::endl;
//
// run Newton-based optim
x = arma::ones (n_dim, 1 ) + 1.0 ; // initial values
start = std::chrono::system_clock::now ();
success = optim::newton (x,ll_fn_whess,&opt_data);
end = std::chrono::system_clock::now ();
elapsed_seconds = end-start;
//
if (success) {
std::cout << " newton: logit_reg test completed successfully. n "
<< " elapsed time: " << elapsed_seconds. count () << " s n " ;
} else {
std::cout << " newton: logit_reg test completed unsuccessfully. " << std::endl;
}
arma::cout << " n newton: true values vs estimates: n " << arma::join_rows (theta_0,x) << arma::endl;
return 0 ;
}เอาท์พุท:
Adam: logit_reg test completed successfully.
elapsed time: 0.025128s
Adam: true values vs estimates:
2.7850 2.6993
3.6561 3.6798
2.3379 2.3860
2.3167 2.4313
2.2465 2.3064
newton: logit_reg test completed successfully.
elapsed time: 0.255909s
newton: true values vs estimates:
2.7850 2.6993
3.6561 3.6798
2.3379 2.3860
2.3167 2.4313
2.2465 2.3064
ด้วยการรวม Eigen เข้ากับ Autodiff Library ทำให้ OptimLib ให้การสนับสนุนการทดลองสำหรับความแตกต่างอัตโนมัติ
ตัวอย่างการใช้ความแตกต่างอัตโนมัติโหมดไปข้างหน้าด้วย BFGs สำหรับฟังก์ชั่น Sphere:
# define OPTIM_ENABLE_EIGEN_WRAPPERS
# include " optim.hpp "
# include < autodiff/forward/real.hpp >
# include < autodiff/forward/real/eigen.hpp >
//
autodiff::real
opt_fnd ( const autodiff::ArrayXreal& x)
{
return x. cwiseProduct (x). sum ();
}
double
opt_fn ( const Eigen::VectorXd& x, Eigen::VectorXd* grad_out, void * opt_data)
{
autodiff::real u;
autodiff::ArrayXreal xd = x. eval ();
if (grad_out) {
Eigen::VectorXd grad_tmp = autodiff::gradient (opt_fnd, autodiff::wrt (xd), autodiff::at (xd), u);
*grad_out = grad_tmp;
} else {
u = opt_fnd (xd);
}
return u. val ();
}
int main ()
{
Eigen::VectorXd x ( 5 );
x << 1 , 2 , 3 , 4 , 5 ;
bool success = optim::bfgs (x, opt_fn, nullptr );
if (success) {
std::cout << " bfgs: forward-mode autodiff test completed successfully. n " << std::endl;
} else {
std::cout << " bfgs: forward-mode autodiff test completed unsuccessfully. n " << std::endl;
}
std::cout << " solution: x = n " << x << std::endl;
return 0 ;
}รวบรวมด้วย:
g++ -Wall -std=c++17 -O3 -march=native -ffp-contract=fast -I/path/to/eigen -I/path/to/autodiff -I/path/to/optim/include optim_autodiff_ex.cpp -o optim_autodiff_ex.out -L/path/to/optim/lib -loptimดูเอกสารสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับหัวข้อนี้
Keith O'Hara
Apache เวอร์ชัน 2