Skip to content
Merged
Show file tree
Hide file tree
Changes from 93 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
81affe2
Add CMake modules to find Bandicoot libraries and includes.
zoq May 8, 2025
c3059c3
Add initial GitHub Actions to build against Bandicoot and run the tests.
zoq May 8, 2025
5a2cc99
1. Add type proxies to select the right type based on the used backen…
zoq May 8, 2025
61bdef8
Refactor CNE optimizer and tests cases to work with Armadillo and Ban…
zoq May 8, 2025
344c17d
Refactor Katyusha optimizer and tests cases to work with Armadillo an…
zoq May 8, 2025
1df8812
Refactor optimizers to work with Armadillo and Bandicoot datatypes:
zoq May 9, 2025
3c19fa9
Refactor optimizers to work with Armadillo and Bandicoot datatypes:
zoq May 13, 2025
2448177
Refactor optimizers to work with Armadillo and Bandicoot datatypes:
zoq May 13, 2025
dcd8875
Use inverse transform sampling to replicating arma::randg sampling si…
zoq May 21, 2025
2f515be
Apply suggestions from code review by @rcurtin.
zoq May 21, 2025
dadca56
Group test cases and fix indentations.
zoq May 21, 2025
7784b15
Update optimizer reference styling.
zoq May 21, 2025
2779deb
Add option to build against Bandicoot (by default we build against Ba…
zoq May 21, 2025
8286511
Mention AugLagrangianType constructor in the optimizer documentation,…
zoq May 21, 2025
3738c82
Use data type specific element type for the bounds parameter.
zoq May 21, 2025
93e963a
Make sure we follow the max character line limitation from the style …
zoq May 21, 2025
ff6ce5e
Remove backports for outdates armadillo versions.
zoq May 21, 2025
9f83931
Indentation fixes.
zoq May 21, 2025
0433639
Indentation fixes.
zoq May 26, 2025
0ffdd79
Use the correct data type during testing.
zoq May 26, 2025
aab9f5e
Do not use the namespace twice.
zoq May 26, 2025
d3fee05
Test against CPU/OpenCL/CUDA backend.
zoq May 26, 2025
3f2f607
Use the correct test case type.
zoq May 27, 2025
2a693ac
We don't need Bandicoot when we test against Armadillo (CPU) backend.
zoq May 27, 2025
abfd69b
Use the correct minimal Bandicoot version.
zoq Jun 3, 2025
67f40be
Comment on the added proxies.
zoq Jun 17, 2025
197ac1a
Merge arma and coot traits into a single file.
zoq Jun 17, 2025
27a00e6
Fix deprecation warning from newer Armadillo.
rcurtin Jul 14, 2025
d8177a2
Fix spacing.
rcurtin Jul 14, 2025
de5ec97
Add logging output for PSO.
rcurtin Jul 14, 2025
9d61317
Adapt problems to be templatized.
rcurtin Jul 14, 2025
d892ecc
Templatize tests to use ENS_TEST_TYPES.
rcurtin Jul 14, 2025
5054ee8
Fix name of AdaGrad in the documentation.
rcurtin Jul 15, 2025
91c64b7
Apply suggestions from code review.
zoq Jul 17, 2025
f9e1fd6
Update about half the optimizers to use FP16.
rcurtin Jul 22, 2025
44b215f
Refactor ForwardType into two different structures to avoid std::cond…
rcurtin Jul 22, 2025
9dd54ca
Minor changes to get tests to pass on the Pi.
rcurtin Jul 22, 2025
957ab23
Remove unused proxies.
zoq Jul 25, 2025
263bf53
Update the other half of the optimizers to use FP16.
rcurtin Jul 25, 2025
01363f2
Minor fixes to work on non-emulated FP16.
rcurtin Jul 26, 2025
43b6510
Update to arma::hmat and enable sparse types.
rcurtin Jul 26, 2025
4b1a388
Make CMake standard easily configurable.
rcurtin Jul 26, 2025
01ee111
Revert CategoryType to arma::Row<size_t> since that should always sta…
rcurtin Jul 30, 2025
c3af24b
Add convenience IsMatrixType<> struct.
rcurtin Jul 30, 2025
6180759
Catch underflow for RMSprop.
rcurtin Aug 8, 2025
1d963d6
Revert to norm()-only implementation for gradient norm computation.
rcurtin Aug 8, 2025
a19ecd6
Remove proxies, use using instead.
rcurtin Aug 8, 2025
ea1dc58
Older Armadillo versions don't support changing sparse-to-dense and a…
rcurtin Aug 8, 2025
cde745b
Remove sort_index() proxy and use using instead.
rcurtin Aug 8, 2025
5e4c891
Oops, fix compatibility conv_to implementation.
rcurtin Aug 8, 2025
3bf96d9
Fix divide by zero condition.
rcurtin Aug 8, 2025
a71f41b
Individually accessed vector, so keep vector on the CPU, for faster a…
zoq Aug 11, 2025
bd44d62
Apply suggestions from code review
zoq Aug 17, 2025
e7c9f18
Kepp the indicies on the CPU.
zoq Aug 17, 2025
048650a
Apply suggestions from code review.
zoq Aug 24, 2025
b3775d5
Remove outdated test case.
zoq Aug 24, 2025
503ecd1
Use initialization list for the velocity vector.
zoq Aug 24, 2025
f597b08
Apply suggestions from code review
zoq Aug 24, 2025
d339032
Readd removed test cases for MOEAD.
zoq Aug 24, 2025
be5f811
Use sort_index for sorting that is supported for both armadillo and b…
zoq Aug 26, 2025
83ab897
Revert changes to Parallel SGD optimizer, no benefit to upload to the…
zoq Aug 26, 2025
040bd44
Only reset if we haven't reached the end of the iterations.
zoq Aug 26, 2025
954fbe5
Use accu to the the sum of the vector.
zoq Aug 26, 2025
6ed7d8a
Use clamp instead of min, for a more efficient computation.
zoq Aug 26, 2025
2b5a38f
Add missing data type.
zoq Aug 26, 2025
f9521ad
Use ENS_HAVE_COOT instead of USE_COOT and automatically detect when B…
rcurtin Aug 26, 2025
e62d607
Fix incorrect initialization list.
rcurtin Aug 26, 2025
74219d2
Remove unnecessary GetFillType<MatType>::zeros, which does not work f…
rcurtin Aug 26, 2025
be1d8fa
Clean up the last few proxy functions.
rcurtin Aug 26, 2025
e2b67b2
Refactor problems to avoid adding extra template parameters.
rcurtin Aug 26, 2025
c8c4fed
NSGA2: introduce a new Optimize function that takes the front and the…
zoq Aug 27, 2025
90da959
MOEAD: introduce a new Optimize function that takes the front and the…
zoq Aug 27, 2025
fa9bbf6
Remove unnecessary lr matrix.
rcurtin Aug 27, 2025
dcbdcdc
Minor cleanups for SA.
rcurtin Aug 27, 2025
7032a78
Clean up member initialization for PSO.
rcurtin Aug 27, 2025
13c228c
Update documentation for multi-objective optimizers.
rcurtin Aug 27, 2025
1d3102c
Update API for Snapshots().
rcurtin Aug 27, 2025
a9ce40c
Keep the MOEAD front indices on the CPU, to be more efficient.
zoq Aug 27, 2025
7442e83
Remove class template parameter for the bound parameter, to make the …
zoq Aug 27, 2025
2d2c1cc
Merge remote-tracking branch 'zoq/bandicoot-integration' into fp16_tests
rcurtin Aug 28, 2025
572abaa
Use the correct location for the bandicoot wrapper.
zoq Aug 28, 2025
8a90b83
No need to set the backend for testing, we will test whatever was ava…
zoq Aug 28, 2025
7375ab3
Use the correct def to enable the bandicoot backend.
zoq Aug 28, 2025
4fdf07c
use the correct name for the def.
zoq Aug 28, 2025
6e5f1e3
Fixes so that Bandicoot actually gets detected and compiled in correc…
rcurtin Aug 28, 2025
3ff00de
Oops, fix merge.
rcurtin Aug 28, 2025
664c431
Merge remote-tracking branch 'zoq/bandicoot-integration' into fp16_tests
rcurtin Aug 28, 2025
a0c427d
Add tolerances for Bandicoot matrices.
rcurtin Aug 29, 2025
8f2fb21
Fix missing typedef.
rcurtin Aug 29, 2025
61983ab
Fix some failing tests.
rcurtin Aug 31, 2025
df3e6f4
Merge remote-tracking branch 'origin/master' into fp16_tests
rcurtin Aug 31, 2025
b930cca
Fix minor compilation issues.
rcurtin Aug 31, 2025
3d6d6c8
Fix compilation errors and warnings.
rcurtin Sep 1, 2025
4305ab9
Minor issues discovered in self-review.
rcurtin Sep 2, 2025
9932d68
Oops, fix missing type.
rcurtin Sep 2, 2025
b54a78a
Merge branch 'master' into fp16_tests
rcurtin Sep 4, 2025
e1aad8d
Reduce batch size to try and prevent NaNs.
rcurtin Sep 6, 2025
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
10 changes: 7 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ option(USE_BANDICOOT "If available, build against Bandicoot for GPU support." ON

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake")

# Set required C++ standard to C++14.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Set minimum required C++ standard to C++14.
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
elseif (${CMAKE_CXX_STANDARD} LESS 14)
message(FATAL_ERROR "ensmallen requires C++14 or newer!")
endif ()

# Extract version from sources.
set(ENSMALLEN_VERSION_FILE_NAME "${PROJECT_SOURCE_DIR}/include/ensmallen_bits/ens_version.hpp")
Expand Down
22 changes: 19 additions & 3 deletions doc/optimizers.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ optimizer.Optimize(f, coordinates);
* [AdaGrad](#adagrad)
* [Differentiable separable functions](#differentiable-separable-functions)

## Adagrad
## AdaGrad

*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*

Expand Down Expand Up @@ -1297,7 +1297,7 @@ total contribution of a gradient to all future updates.
* `DemonAdam()`
* `DemonAdam(`_`stepSize, batchSize`_`)`
* `DemonAdam(`_`stepSize, batchSize, momentum, beta1, beta2, eps, maxIterations, tolerance, shuffle`_`)`
* `DemonAdam(`_`stepSize, batchSize, momentum, beta1, beta2, eps, maxIterations, tolerance, shuffle, resetPolicy`_`)`
* `DemonAdam(`_`stepSize, batchSize, momentum, beta1, beta2, eps, maxIterations, tolerance, shuffle, resetPolicy, exactObjective`_`)`

Note that the `DemonAdam` class is based on
the `DemonAdamType<`_`UpdateRule`_`>` class with _`UpdateRule`_` = AdamUpdate`.
Expand Down Expand Up @@ -1329,12 +1329,20 @@ For convenience the following typedefs have been defined:
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective at the end of optimization. (This could be computationally expensive!) | `false` |

The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Momentum()`, `MomentumIterations()`, `Beta1()`,
`Beta2()`, `Eps()`, `MaxIterations()`, `Tolerance()`, `Shuffle()`, and
`ResetPolicy()`.

***Note:*** if `exactObjective` is `false`, then `Optimize(f, coordinates)` will
return an estimate of the objective function. This estimate is the sum of the
objectives obtained on the last pass of the separable functions. The estimate
will not include contributions from any separable functions not visited in the
last pass (e.g., if `maxIterations` is not an integer multiple of
`f.NumFunctions()`).

#### Examples

<details open>
Expand Down Expand Up @@ -1386,7 +1394,7 @@ optimizer:
* `DemonSGD()`
* `DemonSGD(`_`stepSize, batchSize`_`)`
* `DemonSGD(`_`stepSize, batchSize, momentum, maxIterations, tolerance, shuffle`_`)`
* `DemonSGD(`_`stepSize, batchSize, momentum, maxIterations, tolerance, shuffle, resetPolicy`_`)`
* `DemonSGD(`_`stepSize, batchSize, momentum, maxIterations, tolerance, shuffle, resetPolicy, exactObjective`_`)`

#### Attributes

Expand All @@ -1399,11 +1407,19 @@ optimizer:
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective at the end of optimization. (This could be computationally expensive!) | `false` |

The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Momentum()`, `MomentumIterations()`,
`MaxIterations()`, `Tolerance()`, `Shuffle()`, and `ResetPolicy()`.

***Note:*** if `exactObjective` is `false`, then `Optimize(f, coordinates)` will
return an estimate of the objective function. This estimate is the sum of the
objectives obtained on the last pass of the separable functions. The estimate
will not include contributions from any separable functions not visited in the
last pass (e.g., if `maxIterations` is not an integer multiple of
`f.NumFunctions()`).

#### Examples

<details open>
Expand Down
29 changes: 21 additions & 8 deletions include/ensmallen_bits/ada_belief/ada_belief_update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class AdaBeliefUpdate
class Policy
{
public:
typedef typename MatType::elem_type ElemType;

/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
Expand All @@ -89,10 +91,16 @@ class AdaBeliefUpdate
*/
Policy(AdaBeliefUpdate& parent, const size_t rows, const size_t cols) :
parent(parent),
beta1(ElemType(parent.beta1)),
beta2(ElemType(parent.beta2)),
epsilon(ElemType(parent.epsilon)),
iteration(0)
{
m.zeros(rows, cols);
s.zeros(rows, cols);
// Prevent underflow.
if (epsilon == ElemType(0) && parent.epsilon != 0.0)
epsilon = 10 * std::numeric_limits<ElemType>::epsilon();
}

/**
Expand All @@ -109,18 +117,18 @@ class AdaBeliefUpdate
// Increment the iteration counter variable.
++iteration;

m *= parent.beta1;
m += (1 - parent.beta1) * gradient;
m *= beta1;
m += (1 - beta1) * gradient;

s *= parent.beta2;
s += (1 - parent.beta2) * pow(gradient - m, 2.0) + parent.epsilon;
s *= beta2;
s += (1 - beta2) * pow(gradient - m, 2) + epsilon;

const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const ElemType biasCorrection1 = 1 - std::pow(beta1, ElemType(iteration));
const ElemType biasCorrection2 = 1 - std::pow(beta2, ElemType(iteration));

// And update the iterate.
iterate -= ((m / biasCorrection1) * stepSize) / (sqrt(s /
biasCorrection2) + parent.epsilon);
iterate -= ((m / biasCorrection1) * ElemType(stepSize)) /
(sqrt(s / biasCorrection2) + epsilon);
}

private:
Expand All @@ -133,6 +141,11 @@ class AdaBeliefUpdate
// The exponential moving average of squared gradient values.
GradType s;

// Parent parameters converted to the element type of the matrix.
ElemType beta1;
ElemType beta2;
ElemType epsilon;

// The number of iterations.
size_t iteration;
};
Expand Down
53 changes: 38 additions & 15 deletions include/ensmallen_bits/ada_bound/ada_bound_update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class AdaBoundUpdate
class Policy
{
public:
typedef typename MatType::elem_type ElemType;

/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
Expand All @@ -105,10 +107,24 @@ class AdaBoundUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdaBoundUpdate& parent, const size_t rows, const size_t cols) :
parent(parent), first(true), initialStepSize(0), iteration(0)
parent(parent),
finalLr(ElemType(parent.finalLr)),
gamma(ElemType(parent.gamma)),
epsilon(ElemType(parent.epsilon)),
beta1(ElemType(parent.beta1)),
beta2(ElemType(parent.beta2)),
first(true),
initialStepSize(0),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);

// Check for underflows in conversions.
if (gamma == ElemType(0) && parent.gamma != 0.0)
gamma = 10 * std::numeric_limits<ElemType>::epsilon();
if (epsilon == ElemType(0) && parent.epsilon != 0.0)
epsilon = 10 * std::numeric_limits<ElemType>::epsilon();
}

/**
Expand All @@ -129,30 +145,30 @@ class AdaBoundUpdate
if (first)
{
first = false;
initialStepSize = stepSize;
initialStepSize = ElemType(stepSize);
}

// Increment the iteration counter variable.
++iteration;

// Decay the first and second moment running average coefficient.
m *= parent.beta1;
m += (1 - parent.beta1) * gradient;
m *= beta1;
m += (1 - beta1) * gradient;

v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
v *= beta2;
v += (1 - beta2) * (gradient % gradient);

const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const ElemType biasCorrection1 = 1 - std::pow(beta1, ElemType(iteration));
const ElemType biasCorrection2 = 1 - std::pow(beta2, ElemType(iteration));

const ElemType fl = parent.finalLr * stepSize / initialStepSize;
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration));
const ElemType fl = finalLr * ElemType(stepSize) / initialStepSize;
const ElemType lower = fl * (1 - 1 / (gamma * iteration + 1));
const ElemType upper = fl * (1 + 1 / (gamma * iteration));

// Applies bounds on actual learning rate.
iterate -= clamp((stepSize *
std::sqrt(biasCorrection2) / biasCorrection1) / (sqrt(v) +
parent.epsilon), lower, upper) % m;
iterate -= clamp((ElemType(stepSize) *
std::sqrt(biasCorrection2) / biasCorrection1) / (sqrt(v) + epsilon),
lower, upper) % m;
}

private:
Expand All @@ -165,11 +181,18 @@ class AdaBoundUpdate
// The exponential moving average of squared gradient values.
GradType v;

// Parameters of the parent, casted to the element type of the problem.
ElemType finalLr;
ElemType gamma;
ElemType epsilon;
ElemType beta1;
ElemType beta2;

// Whether this is the first call of the Update method.
bool first;

// The initial (Adam) learning rate.
double initialStepSize;
ElemType initialStepSize;

// The number of iterations.
size_t iteration;
Expand Down
55 changes: 37 additions & 18 deletions include/ensmallen_bits/ada_bound/ams_bound_update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class AMSBoundUpdate
class Policy
{
public:
typedef typename MatType::elem_type ElemType;

/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
Expand All @@ -105,11 +107,25 @@ class AMSBoundUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AMSBoundUpdate& parent, const size_t rows, const size_t cols) :
parent(parent), first(true), initialStepSize(0), iteration(0)
parent(parent),
finalLr(ElemType(parent.finalLr)),
gamma(ElemType(parent.gamma)),
epsilon(ElemType(parent.epsilon)),
beta1(ElemType(parent.beta1)),
beta2(ElemType(parent.beta2)),
first(true),
initialStepSize(0),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
vImproved.zeros(rows, cols);

// Check for underflows in conversions.
if (gamma == ElemType(0) && parent.gamma != 0.0)
gamma = 10 * std::numeric_limits<ElemType>::epsilon();
if (epsilon == ElemType(0) && parent.epsilon != 0.0)
epsilon = 10 * std::numeric_limits<ElemType>::epsilon();
}

/**
Expand All @@ -123,40 +139,36 @@ class AMSBoundUpdate
const double stepSize,
const GradType& gradient)
{
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;

// Save the initial step size.
if (first)
{
first = false;
initialStepSize = stepSize;
initialStepSize = ElemType(stepSize);
}

// Increment the iteration counter variable.
++iteration;

// Decay the first and second moment running average coefficient.
m *= parent.beta1;
m += (1 - parent.beta1) * gradient;
m *= beta1;
m += (1 - beta1) * gradient;

v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
v *= beta2;
v += (1 - beta2) * (gradient % gradient);

const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const ElemType biasCorrection1 = 1 - std::pow(beta1, ElemType(iteration));
const ElemType biasCorrection2 = 1 - std::pow(beta2, ElemType(iteration));

const ElemType fl = parent.finalLr * stepSize / initialStepSize;
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration));
const ElemType fl = finalLr * ElemType(stepSize) / initialStepSize;
const ElemType lower = fl * (1 - 1 / (gamma * iteration + 1));
const ElemType upper = fl * (1 + 1 / (gamma * iteration));

// Element wise maximum of past and present squared gradients.
vImproved = max(vImproved, v);

// Applies bounds on actual learning rate.
iterate -= clamp((stepSize * std::sqrt(biasCorrection2) /
biasCorrection1) / (sqrt(vImproved) + parent.epsilon),
lower, upper) % m;
iterate -= clamp((ElemType(stepSize) * std::sqrt(biasCorrection2) /
biasCorrection1) / (sqrt(vImproved) + epsilon), lower, upper) % m;
}

private:
Expand All @@ -169,11 +181,18 @@ class AMSBoundUpdate
// The exponential moving average of squared gradient values.
GradType v;

// Parameters of the parent, casted to the element type of the problem.
ElemType finalLr;
ElemType gamma;
ElemType epsilon;
ElemType beta1;
ElemType beta2;

// Whether this is the first call of the Update method.
bool first;

// The initial (Adam) learning rate.
double initialStepSize;
ElemType initialStepSize;

// The optimal squared gradient value.
GradType vImproved;
Expand Down
Loading