Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't reset the objective estimate on the last iteration #417

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

rcurtin
Copy link
Member

@rcurtin rcurtin commented Dec 23, 2024

I noticed while working with RNNs in mlpack that the estimated objective would be 0 if I was training sequences of different length one iteration at a time... digging into it, I discovered that any time you optimize a separable function with SGD-like optimizers and the number of iterations you use is an exact multiple of the number of functions (e.g. number of sequences given to the RNN), then the returned objective estimate is 0 unless you specify exactObjective.

This is because the objective estimate gets reset after every epoch, but if it is the last epoch... it still resets it anyway, it doesn't return the estimate.

So I fixed that for all optimizers I could find that had the condition, and then I updated the documentation to be a little clearer about what does get returned for separable functions.

A test program:

#include <ensmallen.hpp>

using namespace ens;
using namespace ens::test;

int main()
{
  GeneralizedRosenbrockFunction f(11);
  std::cout << "Number of functions: " << f.NumFunctions() << ".\n";

  // With one epoch only.
  StandardSGD s(0.001, 1, f.NumFunctions(), 1e-5);
  arma::mat coordinates = f.GetInitialPoint();
  double result = s.Optimize(f, coordinates);
  std::cout << "Optimized to result: " << result << ".\n";

  // With not an even number of epochs.
  s.MaxIterations() = f.NumFunctions() - 1;
  coordinates = f.GetInitialPoint();
  result = s.Optimize(f, coordinates);
  std::cout << "Optimized to result: " << result << ".\n";
}

Compile with:

g++ -O3 -DENS_PRINT_INFO -DENS_PRINT_WARN -I../include/ -o out_test out_test.cpp

or similar.

Output before this PR:

$ ./out_test
Number of functions: 10.
SGD: iteration 10, objective 2257.11.
SGD: maximum iterations (10) reached; terminating optimization.
Optimized to result: 0.
SGD: maximum iterations (9) reached; terminating optimization.
Optimized to result: 2399.38.

Output after this PR:

$ ./out_test 
Number of functions: 10.
SGD: iteration 10, objective 2257.11.
SGD: maximum iterations (10) reached; terminating optimization.
Optimized to result: 2257.11.
SGD: maximum iterations (9) reached; terminating optimization.
Optimized to result: 2399.38.

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()`).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same note I used for all optimizers with the exactObjective option. Happy to accept any suggestions that can make it more concise or clearer without breaking the meaning.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second approval provided automatically after 24 hours. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants