ahmedfgad / GeneticAlgorithmPython

Source code of PyGAD, a Python 3 library for building the genetic algorithm and training machine learning algorithms (Keras & PyTorch).
https://pygad.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.85k stars 462 forks source link

plot_fitness(plot_type="scatter") fails after 2nd run() #62

Open andrey-bat opened 3 years ago

andrey-bat commented 3 years ago

Hi! Great project, thanks. However I've experianced some bugs.

model = pygad.GA(someparameters - may be even sample model from documentation) model.run() model.plot_fitness(plot_type="scatter") ok model.run() model.plot_fitess() ok model.plot_fitness(plot_type="scatter")


ValueError Traceback (most recent call last)

in ----> 1 ga_instance.plot_fitness(plot_type="scatter") ~/.conda/envs/test/lib/python3.9/site-packages/pygad/pygad.py in plot_fitness(self, title, xlabel, ylabel, linewidth, font_size, plot_type, color, save_dir) 3150 matplotlib.pyplot.plot(self.best_solutions_fitness, linewidth=linewidth, color=color) 3151 elif plot_type == "scatter": -> 3152 matplotlib.pyplot.scatter(range(self.generations_completed + 1), self.best_solutions_fitness, linewidth=linewidth, color=color) 3153 elif plot_type == "bar": 3154 matplotlib.pyplot.bar(range(self.generations_completed + 1), self.best_solutions_fitness, linewidth=linewidth, color=color) ~/.conda/envs/test/lib/python3.9/site-packages/matplotlib/pyplot.py in scatter(x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, edgecolors, plotnonfinite, data, **kwargs) 3066 vmin=None, vmax=None, alpha=None, linewidths=None, *, 3067 edgecolors=None, plotnonfinite=False, data=None, **kwargs): -> 3068 __ret = gca().scatter( 3069 x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm, 3070 vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths, ~/.conda/envs/test/lib/python3.9/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs) 1359 def inner(ax, *args, data=None, **kwargs): 1360 if data is None: -> 1361 return func(ax, *map(sanitize_sequence, args), **kwargs) 1362 1363 bound = new_sig.bind(ax, *args, **kwargs) ~/.conda/envs/test/lib/python3.9/site-packages/matplotlib/axes/_axes.py in scatter(self, x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, edgecolors, plotnonfinite, **kwargs) 4496 y = np.ma.ravel(y) 4497 if x.size != y.size: -> 4498 raise ValueError("x and y must be the same size") 4499 4500 if s is None: ValueError: x and y must be the same size
andrey-bat commented 3 years ago

Sometimes there's also an error with model.plot_fitess() on the first run, but could not yet reproduce on some simple dummy case.

Traceback (most recent call last): File "/home/albat/crop_selector/crops_selector.py", line 625, in model.plot_fitness() File "/home/albat/.conda/envs/test/lib/python3.9/site-packages/pygad/pygad.py", line 3150, in plot_fitness matplotlib.pyplot.plot(self.best_solutions_fitness, linewidth=linewidth, color=color) File "/home/albat/.conda/envs/test/lib/python3.9/site-packages/matplotlib/pyplot.py", line 3019, in plot return gca().plot( File "/home/albat/.conda/envs/test/lib/python3.9/site-packages/matplotlib/axes/_axes.py", line 1605, in plot lines = [self._get_lines(args, data=data, **kwargs)] File "/home/albat/.conda/envs/test/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 315, in call yield from self._plot_args(this, kwargs) File "/home/albat/.conda/envs/test/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 504, in _plot_args raise ValueError(f"x and y can be no greater than 2D, but have " ValueError: x and y can be no greater than 2D, but have shapes (11,) and (11, 1, 1)

BTW, don't know where 11 comes from, there were just 10 generations in this run.

ahmedfgad commented 3 years ago

Hi @andrey-bat,

Thanks for using PyGAD.

Before explaining the solution to this issue, let me quickly explain why it is 11 not 10. The reason is that the fitness of the initial population (before the GA starts its evolution) is saved. This is in addition to the fitness of the 10 generations. So, the total is 1+10=11.

For the issue, let me explain why this happens.

There are 4 variables that store information about the solutions and their fitness after each generation. The 4 variables are:

  1. best_solutions: Saves the best solution in each generation.
  2. best_solutions_fitness: Saves the fitness value of the best solution for each generation.
  3. solutions: Saves all solutions in each generation.
  4. solutions_fitness: Saves the fitness of all solutions in each generation.

When the plot_fitness() method is called, the best_solutions_fitness list is used. If there are 10 generations, then this list will hold 11 values after the run() method completes for the first time.

For each call of the run() method, new values will be appended at the end of this list. After the second run, the length of the best_solutions_fitness list will be 11+11=22. Then, it is 33 after the third run.

This issue is solved by resetting the best_solutions_fitness variable and any variable that is extended after each generation.

def run(self):
    ....
    self.best_solutions = []
    self.best_solutions_fitness = []
    self.solutions = []
    self.solutions_fitness = []
   ....

The project will be updated soon and a new release of PyGAD will be published.

Thanks for opening this issue.