Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions notebooks/report.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "e6898559",
"metadata": {},
"source": [
"# How to get more info about the optimization run\n",
"\n",
"The `report` parameter is optional when initializing the optimizer.\n",
"For detailed run information, provide a Report callback object to the optimizer. \n",
"This is done by passing an instance of the Report callback class during initialization."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "f6b0aef6",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pyensmallen as pye\n",
"from pprint import pprint"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "25fc7777",
"metadata": {},
"outputs": [],
"source": [
"def square(x):\n",
" return x@x\n",
"\n",
"def objective_function(x, grad):\n",
" grad[:] = 2*x\n",
" return square(x)\n",
" "
]
},
{
"cell_type": "markdown",
"id": "a3ad6515",
"metadata": {},
"source": [
"It is optional to get a more detailed optimization report.\n",
"You can run the optimizer normally."
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "1eeb4af0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[-1.13686838e-13 1.13686838e-13]\n"
]
}
],
"source": [
"# Initial guess\n",
"initial_x = np.array([-1000, 1000.0])\n",
"\n",
"# Initialize L-BFGS optimizer\n",
"optimizer = pye.L_BFGS()\n",
"\n",
"# Optimize\n",
"result = optimizer.optimize(objective_function, initial_x)\n",
"\n",
"print(result)"
]
},
{
"cell_type": "markdown",
"id": "407d1a4c",
"metadata": {},
"source": [
"## Getting more info about the optimization\n",
"Passing this callback object allows to retrieve more info about the optimization run."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "e9b998dc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[-1.13686838e-13 1.13686838e-13]\n",
"{'evaluate_calls': 10,\n",
" 'gradient_calls': 10,\n",
" 'iterations': 2,\n",
" 'objective_value': 2.5849394142282115e-26,\n",
" 'total_time': 3.4675e-05}\n"
]
}
],
"source": [
"\n",
"# Initialize L-BFGS optimizer\n",
"optimizer = pye.L_BFGS()\n",
"\n",
"# Initialize a dict to store optimization run info \n",
"info = dict()\n",
"\n",
"# Initialize Report callback object \n",
"report = pye.Report(info, disableOutput=True)\n",
"\n",
"# Initialize L-BFGS optimizer passing a Report object\n",
"result = optimizer.optimize(objective_function, initial_x, report=report)\n",
"print(result)\n",
"pprint(info)"
]
},
{
"cell_type": "markdown",
"id": "5ef84c09",
"metadata": {},
"source": [
"By setting `disableOutput=False`, callback prints a optimizer report to stdout which shows various info about the optimization run."
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "09f97e11",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Modified Optimization Report\n",
"--------------------------------------------------------------------------------\n",
"\n",
"Initial Coordinates:\n",
" -1.0000e+03 1.0000e+03\n",
"\n",
"Final coordinates:\n",
" -1.1369e-13 1.1369e-13\n",
"\n",
"iter loss loss change |gradient| total time \n",
"0 1.52e+06 0 2.47e+03 2.87e-05 \n",
"1 2.58e-26 1.52e+06 3.22e-13 3.44e-05 \n",
"\n",
"--------------------------------------------------------------------------------\n",
"\n",
"Version:\n",
"ensmallen: 2.22.1 (E-Bike Excitement)\n",
"armadillo: 12.6.7 (Cortisol Retox)\n",
"\n",
"Function:\n",
"Number of functions: 1\n",
"Coordinates rows: 2\n",
"Coordinates columns: 1\n",
"\n",
"Loss:\n",
"Initial 1.52e+06\n",
"Final 2.58e-26\n",
"Change 1.52e+06\n",
"\n",
"Optimizer:\n",
"Maximum iterations: 10000\n",
"Reached maximum iterations: false\n",
"Iterations: 2\n",
"Coordinates max. norm: 2.47e+03\n",
"Evaluate calls: 10\n",
"Gradient calls: 10\n",
"Time (in seconds): 3.44e-05\n"
]
}
],
"source": [
"# Initialize L-BFGS optimizer\n",
"optimizer = pye.L_BFGS()\n",
"\n",
"# Initialize a dict to store optimization run info \n",
"info = dict()\n",
"\n",
"# Initialize Report callback object \n",
"report = pye.Report(info, disableOutput=False)\n",
"\n",
"# Initialize L-BFGS optimizer passing a Report object\n",
"result = optimizer.optimize(objective_function, initial_x, report=report)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2da4dbe3",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "optimagic",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.18"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
21 changes: 19 additions & 2 deletions pyensmallen/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
#include "newton_type.hpp"
#include "constrained.hpp"
#include "first_order.hpp"

#include "report.hpp"
namespace py = pybind11;

PYBIND11_MODULE(_pyensmallen, m)
{

// L-BFGS (Newton-type) optimizer
py::class_<PyL_BFGS>(m, "L_BFGS")
.def(py::init<>())
Expand Down Expand Up @@ -40,7 +41,11 @@ PYBIND11_MODULE(_pyensmallen, m)
&PyL_BFGS::setMaxLineSearchTrials)
.def_property("minStep", &PyL_BFGS::getMinStep, &PyL_BFGS::setMinStep)
.def_property("maxStep", &PyL_BFGS::getMaxStep, &PyL_BFGS::setMaxStep)
.def("optimize", &PyL_BFGS::Optimize);
.def("optimize", &PyL_BFGS::Optimize,
py::arg("f"),
py::arg("initial_point"),
py::arg("report") = nullptr);


// FrankWolfe - constrained optimization
py::class_<PyFrankWolfe>(m, "FrankWolfe")
Expand Down Expand Up @@ -245,4 +250,16 @@ PYBIND11_MODULE(_pyensmallen, m)
&PyAdamType<ens::NadamUpdate>::getResetPolicy,
&PyAdamType<ens::NadamUpdate>::setResetPolicy)
.def("optimize", &PyAdamType<ens::NadamUpdate>::Optimize);

py::class_<ens::PyReport>(m, "Report")
.def(py::init<
py::dict,
bool,
double,
size_t>(),
py::arg("resultIn"),
py::arg("disableOutput") = false,
py::arg("iterationsPercentageIn") = 0.1,
py::arg("outputMatrixSizeIn") = 4
);
}
29 changes: 16 additions & 13 deletions pyensmallen/newton_type.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "utils.hpp"
#include "report.hpp"

// Wrapper for L-BFGS optimizer
class PyL_BFGS
Expand Down Expand Up @@ -79,19 +80,21 @@ class PyL_BFGS
void setMaxStep(double maxStep) { optimizer.MaxStep() = maxStep; }

py::array_t<double> Optimize(DifferentiableFunction f,
py::array_t<double> initial_point)
{
py::buffer_info buf_info = initial_point.request();
arma::vec arma_initial_point(static_cast<double *>(buf_info.ptr),
buf_info.shape[0], false, true);

DifferentiableFunctionWrapper fw(f);
arma::vec result = arma_initial_point;

optimizer.Optimize(fw, result);

return py::array_t<double>(result.n_elem, result.memptr());
}
py::array_t<double> initial_point, ens::PyReport* report = nullptr)
{
py::buffer_info buf_info = initial_point.request();
arma::vec arma_initial_point(static_cast<double *>(buf_info.ptr),
buf_info.shape[0], false, true);

DifferentiableFunctionWrapper fw(f);
arma::vec result = arma_initial_point;
if (report)
optimizer.Optimize(fw, result, *report);
else
optimizer.Optimize(fw, result);
return py::array_t<double>(result.n_elem, result.memptr());

}

private:
ens::L_BFGS optimizer;
Expand Down
Loading