Closed guven6 closed 5 years ago
We have a cost function which is very costly to compute - more than an hour. In the cost function I log the iterations (positions and current cost) and it is called twice for a single iteration (specified in optimizer.optimize). Is this expected? Any way to improve it?
Hi @guven6 ,
We will deal with algo optimizations on the next release (v.0.5.0), it might still take a long time since we’re dealing with other tasks
One workaround for your problem is to define your own optimization loop using pyswarms.backend
. You can inherit the Optimizer
you are currently using then override the optimize()
method.
I have just come across to the same problem. The main issue is that you execute the objective function twice because you recalculate the particle best cost. I am not sure why this is (perhaps reading from memory is slower) but for long optimizations (such as myself and @jazcap53) this is surely not useful.
This is the part of the code in global_best.py that is responsible for this:
self.swarm.current_cost = objective_func(self.swarm.position, **kwargs)
self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs)
The solution is initialization of the particles best position to a very large number. I have not yet implemented this but would like advice on how to do it.
Hi @guven6 and @pdiaz2
Sorry I still feel a bit stuck on how to solve this, would you mind expounding what
initialization of the particles best position to a very large number`
mean? Thank you for reporting this issue and hopefully we can work on it right away.
cc: @whzup @SioKCronin mind helping me out? :+1: What's a good way to remove the duplicate call on our objective function?
First of all, I am somewhat new to github so I don't know how to properly cite lines in files etc., so you will have to excuse me :relaxed: I will just paste the lines then:
for i in range(iters):
# Compute cost for current position and personal best
self.swarm.current_cost = objective_func(self.swarm.position, **kwargs)
self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs)
self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest(
self.swarm
)
The loop continues but as you can see the objective function is called twice: once to calculate for the entire swarm and once again to recalculate each particle's best cost. Since this algorithm is iterative, the particle's current best cost was calculated in the past iteration. For iteration 0, I see you initialize the each particle's best cost to an empty array. This is done on the swarms.py module. Changing this to a large number should do the trick and thus the second call can be eliminated.
Please correct me if I am saying anything that is not accurate, but I believe that this is the way Matlab PSO does it (as a matter of fact, I am translating a previous library I wrote in Matlab)
Hi @pdiaz2 !
No it's definitely fine! And thank you for walking me through the solution. Forgive me if I will ask a lot of clarifications so that I'm sure that I understand the proposed solution well. So from what I understood:
pbest_cost[t]
) can already be obtained from the past iteration, specifically form current_cost[t-1]
pbest_cost[t]
again, we can just get it from current_cost[t-1]
numpy.inf
) so that the second call can be eliminated.Hope I got the idea well. If this is OK, we'll try to make a fix end of month (most of the maintainers have day jobs or in university, so it's difficult to dedicate full-time here, unfortunately, inasmuch as we want to). But if you are interested in making a Pull Request, it would really help us and we'd really appreciate your help!
Not exactly. Let me try to explain:
t
, calculate each particle's cost cost[t]
cost[t]
to swarm.pbest_cost[t-1]
through compute_pbest
. Since the algorithm is iterative, this value was calculated in t-1
. For t=0
, set (outside of main loop) swarm.pbest_cost[t-1]
to numpy.inf
(for minimization).The main thing is that at iteration t
you should already have each particle's best cost stored in swarm.pbest_cost
. If you are only storing the position but not the cost then you need to call the objective function twice. Looking at your code it seems that each particle's best cost is saved through all iterations in swarm.pbest_cost
so when you call the objective function again (on each best position) it should return the same cost that is already stored.
Regarding pulling, since I am new to github I would rather not do so. Besides, I am working currently on something else so I too am running low on time. Should I overwrite your method? The simplest way is to assign numpy.inf
to the cost outside the loop.
Okay, now it's much clearer!
Should I overwrite your method? The simplest way is to assign numpy.inf to the cost outside the loop.
Yes, you can inherit GlobalBestPSO
and override it. If it solves the problem, then please tell us right away so that we can incorporate here in the project.
Thank you @pdiaz2 !
Perfect! I will work on this and return as soon as possible. Thank you!
Hello, I have solved this issue. I am actually running an industrial application with in real time and through the use of apscheduler (python cron-like scheduling package) I also discovered what I think is a major flaw in your algorithm design.
The particles positions are generated when the optimizer is instantiated (GlobalBestPSO for example). This means that when running repeated iterations of the PSO (like I am doing with apscheduler) but not executing the script again the particles always start up in the exact same position. The swarm should be generated when the optimizer is called, at the beginning of the PSO algorithm and outside of the iterative loop.
Please correct me if I am wrong. As I said, regarding the first issue I have already corrected it.
Hi @pdiaz2 ,
The particles starting up in the same position is by design. The idea is that if you want to rerun PSO again with different starting positions, then you should call the reset()
method.
import pyswarms as ps
optimizer = ps.single.GlobalBestPSO(*args, **kwargs)
optimizer.optimize()
# If you wish to run again with different starting positions
optimizer.reset() # this will re-generate the positions again
Oh, thanks! Maybe I missed the example! Thanks, I will be sharing the code as soon as possible!
Glad to hear that!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
@pdiaz2 , Do you have solution? Would you like to share it? Thanks in advance.
Yes I do. Since I am not very good at github I think the best way is to share upload the modified optimizer function directly. I will do this on Friday if I get the chance, Christmas at the most.
Hi! Here is a file that contains the modified optimizer. I added a lot of enhancements to it, but the one discussed in this post is specially emphasized. I also modified your compute_position method because it masked the entire particle instead of just the dimension that ended up out of bounds. Since I was only looking for something functional, I did not overwrite that method in the topology library but instead generated one for the optimizer. I leave said method as well.
Hi @ljvmiranda921 and @pdiaz2 ,
I've opened a pull request based on the solution file provided in the previous comment (full credits to @pdiaz2 🏆 ), which removes the second cost function call using the pbest_cost initialization to np.inf.
Hi @danielcorreia96 ! Welcome to Pyswarms! That's really awesome :+1: Ok, we'll review your work in a while
Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
Describe the solution you'd like A clear and concise description of what you want to happen.
Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
Additional context Add any other context or screenshots about the feature request here.