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

Improvise NSGA2 #263

Merged
merged 54 commits into from
Apr 14, 2021
Merged

Improvise NSGA2 #263

merged 54 commits into from
Apr 14, 2021

Conversation

jonpsy
Copy link
Member

@jonpsy jonpsy commented Mar 4, 2021

Continuation of #262 .

The goal of this PR is to increase the efficiency of this code, enhance its expressibility and reducing its code size as much as possible.

Summary of my goals:

  • Minimize usage of raw for loops
  • Employing std & arma algorithms whenever possible
  • Potential error fixes.
  • Introduce OMP parallelism [https://ieeexplore.ieee.org/document/6968779] whether on this class or a separate class.

I have a few questions before I do that, let me know your thoughts on that.

Providing logs for the convenience of the reader. Stay tuned for more progress updates!

LOGS

Main Loop

  • Initial population should be within (lowerBound, upperBound) so that they exist inside the solution space link
  • Incorporate CheckArbitraryFunctionTypeAPI<> for NSGA2.
  • Add RequireDenseFloatingType for NSGA2

Fast Non Dominated Sorting

  • Discard the empty vector appended to the front. link
  • fronts.size() > 0 ==> !fronts.empty()

Crowding Distance Assignment

  • Pull the crowdingDistance 0 initialisation out of the function
  • Remove fronts.size() > 0 check, since empty front isn't passed at all. Refer the above section.
  • crowdingDistance is filled using objective values not by taking average of crowdingDistance
  • The calculation seems to be very roundabout, need to confirm with @say4n. If you're reading this, can you check this patch As discussed, going with the patch.

Testing

  • Check for different types of matrices, for ex: fmat

Comment on lines 117 to 119
//TODO: Shouldn't we check if they're inside the upperBound && lowerBound?
for (size_t i = 0; i < populationSize; i++)
{
population.push_back(arma::randu<MatType>(iterate.n_rows,
Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't we check if they're inside the upperBound && lowerBound? Am I missing something?

An example https://github.com/baopng/NSGA-II/blob/29a6ec33f87b32a7fb2596091e1a51c897106e7b/nsga2/problem.py#L20

Copy link
Member

Choose a reason for hiding this comment

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

I have to check the paper, not sure if the constrained was only for the mutation/crossover step or for the initial population as well. Also might be good to reference the paper instead of another python implementation.

Copy link
Member Author

@jonpsy jonpsy Mar 5, 2021

Choose a reason for hiding this comment

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

	  
	  /*if limits are specified it generates the value in 
	    range of minimum and maximum value of the variable*/
	  else
	    {
	      pop_ptr->ind[i].xreal[j] = d*(lim_r[j][1] - lim_r[j][0])+lim_r[j][0];
	    }

Source: realinit.h, Original Implementation in C, IITK Kanpur Genetics Laboratory.

@jonpsy
Copy link
Member Author

jonpsy commented Mar 4, 2021

Requesting reviews @rcurtin @zoq @ShikharJ since you've mentored the original PR. If I've gone ahead of myself with these changes, please do tell me :).

Comment on lines 368 to 386
//Remove the empty final set
fronts.pop_back();
Copy link
Member Author

@jonpsy jonpsy Mar 4, 2021

Choose a reason for hiding this comment

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

Caught a big fish here. Allow me to explain myself,

  • The while loop breaks when the newFront is empty. Note that the newFront is pushed regardless of any of the conditions.
  • At the terminate stage of our while loop, the nextFront is not updated at all! That means its an empty vector which gets pushed into our front
  • This causes the while loop to terminate

Result?

You got an additional empty vector in your front set. Which causes smelly code.

Copy link
Member

Choose a reason for hiding this comment

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

Nice catch!

include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
Comment on lines 117 to 119
//TODO: Shouldn't we check if they're inside the upperBound && lowerBound?
for (size_t i = 0; i < populationSize; i++)
{
population.push_back(arma::randu<MatType>(iterate.n_rows,
Copy link
Member

Choose a reason for hiding this comment

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

I have to check the paper, not sure if the constrained was only for the mutation/crossover step or for the initial population as well. Also might be good to reference the paper instead of another python implementation.

@zoq
Copy link
Member

zoq commented Mar 4, 2021

Summary of my goals:

  • Minimize usage of raw for loops
  • Employing std & arma algorithms whenever possible
  • Potential error fixes.
  • Introduce OMP parallelism [https://ieeexplore.ieee.org/document/6968779] whether on this class or a separate class.

Sounds good to me, if we can show that an OpenMP solution is faster let's integrate it into the current method, but maybe armadillo build against openblas is already faster, haven't read the paper yet.

include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
@@ -150,7 +161,7 @@ typename MatType::elem_type NSGA2::Optimize(

// Perform crowding distance assignment.
crowdingDistance.resize(population.size());

std::fill(crowdingDistance.begin(), crowdingDistance.end(), 0.f);
Copy link
Member

Choose a reason for hiding this comment

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

I guess before the reset to zero, we got lucky, because in the CrowdingDistanceAssignment method we use front[i + 1] which should be undefined:

crowdingDistance[front[i]] += (crowdingDistance[front[i - 1]] -
            crowdingDistance[front[i + 1]])

Copy link
Member

Choose a reason for hiding this comment

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

Ahh, nevermind we set it to zero before as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

@zoq Regarding this, I think this implementation is wrong. Here's an excerpt from the paper

crowdingdistance

Notice the equation should've been

crowdingDistance[front[i]] += (fValue[i+1] - fValue[i-1])/(maxFval - minFval)

and not the average of crowdingDistances

Copy link
Member Author

Choose a reason for hiding this comment

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

I've implemented it in this patch

Copy link
Member

Choose a reason for hiding this comment

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

Good, can you make the patch part of the PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've no problem with that. Thing is, @say4n has implemented assignment first and sorting later which I think is wrong but I guess he must have some reason. I was waiting for his review, very well, I'll add this patch on my PR.

Copy link
Member

@say4n say4n Mar 11, 2021

Choose a reason for hiding this comment

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

I think I had unrolled the first iteration of some parts of the optimisation loop to be outside the for loop. This had the benefit of instantiating some items as far as I recall. I don't remember all the details now so do take this with a grain of salt!

Also, sorry for the delays, I have a bunch of impending exams and a ton of work. 😢

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for clarifying :). I'd say let's merge my patch for now as it is straightforward & adheres to the research paper directly. We can then try your optimization method and see how it all fits in.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, for sure! Great work btw!!

@@ -150,7 +161,7 @@ typename MatType::elem_type NSGA2::Optimize(

// Perform crowding distance assignment.
crowdingDistance.resize(population.size());

std::fill(crowdingDistance.begin(), crowdingDistance.end(), 0.f);
Copy link
Member

Choose a reason for hiding this comment

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

Ahh, nevermind we set it to zero before as well.

include/ensmallen_bits/nsga2/nsga2_impl.hpp Show resolved Hide resolved
@jonpsy jonpsy changed the title [WIP] Improvise NSGA2 Improvise NSGA2 Mar 10, 2021
@jonpsy
Copy link
Member Author

jonpsy commented Mar 11, 2021

All the tests pass, Wohoo!. All the tasks are done as well. @zoq Do you have any comments?

@zoq
Copy link
Member

zoq commented Mar 12, 2021

All the tests pass, Wohoo!. All the tasks are done as well. @zoq Do you have any comments?

I'll do another pass over the PR, in the meantime can you update the HISTORY.md so it passes the Travis CI check.

include/ensmallen_bits/nsga2/nsga2.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
include/ensmallen_bits/nsga2/nsga2_impl.hpp Outdated Show resolved Hide resolved
@jonpsy
Copy link
Member Author

jonpsy commented Mar 15, 2021

AppVeyor is failing, but the tests work, can you throw some light on this please?

@zoq
Copy link
Member

zoq commented Mar 18, 2021

Strange, I have to debug this on a local machine, but looks like the windows build never passed on this PR.

@jonpsy
Copy link
Member Author

jonpsy commented Mar 18, 2021

On second thought, I think its better to keep calculatedObjectives because fitness doesn't always equate to calculated objective value. For ex: SPEA-II has a clearly distinguished fitness and objective value.

@jonpsy
Copy link
Member Author

jonpsy commented Apr 1, 2021

Hm, not sure I can see the fix in the last commits, was this just a strange windows fluke?

Your question is well-founded, it looks like Appveyor cmd does not repeat for 3000 times, even after putting ---repeat-until-fail command. So I went ahead and run it manually for like ~50 times for MSVC15. Here's the pastebin (https://pastebin.com/k641DjC7). For 100 times: https://pastebin.com/t4yMGdec.

Let me know if you require further proof.

@zoq
Copy link
Member

zoq commented Apr 1, 2021

Hm, not sure I can see the fix in the last commits, was this just a strange windows fluke?

Your question is well-founded, it looks like Appveyor cmd does not repeat for 3000 times, even after putting ---repeat-until-fail command. So I went ahead and run it manually for like ~50 times for MSVC15. Here's the pastebin (https://pastebin.com/k641DjC7). For 100 times: https://pastebin.com/t4yMGdec.

Let me know if you require further proof.

Thanks, I just was just wondering what it was, thanks for tracking this down.

@zoq
Copy link
Member

zoq commented Apr 1, 2021

I restarted the windows build. because the build failed, not sure it's because of the RDP session.

@jonpsy
Copy link
Member Author

jonpsy commented Apr 2, 2021

The build fails because of RDP. Its waiting for us to access it, and terminates when we dont. @zoq , do we agree the algorithm is working? If so, I'll revert RDP changes and the build would pass.

@zoq
Copy link
Member

zoq commented Apr 2, 2021

The build fails because of RDP. Its waiting for us to access it, and terminates when we dont. @zoq , do we agree the algorithm is working? If so, I'll revert RDP changes and the build would pass.

Ahh, right I have seen you removed it from one section, but looks like not from the other one. This looks good, so let's remove it.

@jonpsy
Copy link
Member Author

jonpsy commented Apr 3, 2021

Hi @zoq , is this GTM?

Copy link
Member

@zoq zoq left a comment

Choose a reason for hiding this comment

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

This looks really good to me, just one more really minor style issue.

@zoq zoq mentioned this pull request Apr 7, 2021
@jonpsy
Copy link
Member Author

jonpsy commented Apr 8, 2021

Once #283 is merged, I will incorporate that feature along with the rebase changes + static analysis fix changes.

@zoq
Copy link
Member

zoq commented Apr 10, 2021

Once #283 is merged, I will incorporate that feature along with the rebase changes + static analysis fix changes.

Nice, just merged #283.

@jonpsy
Copy link
Member Author

jonpsy commented Apr 10, 2021

All right, waiting for the green tick :) .

@jonpsy
Copy link
Member Author

jonpsy commented Apr 10, 2021

All green! 🥳

Copy link
Member

@zoq zoq left a comment

Choose a reason for hiding this comment

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

Thanks for another great contribution 👍

Copy link

@mlpack-bot mlpack-bot 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. 👍

@zoq zoq merged commit 1e70823 into mlpack:master Apr 14, 2021
@zoq
Copy link
Member

zoq commented Apr 14, 2021

Thanks for digging into the optimization method, really nice improvements.

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.

4 participants