-
Notifications
You must be signed in to change notification settings - Fork 333
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
Add cost function decorator #226
Conversation
:code:`int`. | ||
|
||
Attributes | ||
========== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be a second-level header, and Parameters
:
def cost(cost_func):
"""
Parameters
----------
"""
Same with Returns
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thanks for the catch 😄
I'll update this branch first (not sure if you can click the button over there) so that #229 will also reflect here: |
|
||
@pytest.mark.parametrize( | ||
"objective_func", | ||
[np.sum(), np.prod()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just pass the function reference: np.sum
and np.prod
Can you also try np.dot
? Say you're given a particle with d
dimensions, and you dot-product (sumproduct) it to an objective function (randomly-generated array with d
dimensions), you only get 1 output. With the @cost
decorator, you can run this on a set of n
particles with d
dimensions too 👍 This workflow is similar to our neural network example, so we might as well try 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd have to define a new function for this since np.dot
takes two arguments. Shall I put it in the conftest.py
file?
Parameters | ||
---------- | ||
|
||
cost_func : function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be callable
instead of function
---------- | ||
|
||
cost_func : function | ||
A function that can be used as cost function in the optimization (must return a :code:`float` or an :code:`int`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line's a bit long (?) I don't think black formats docstrings, can flake8
catch this line? What does flake8 decorators.py
say?
w_o_decorator = cost_func_w_o_decorator(particles) | ||
w_decorator = cost_func_w_decorator(particles) | ||
|
||
assert isinstance(w_decorator, Number) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I'm not sure why we need to test if the output is a Number
. Maybe we should test the shape of the resulting array? Ensure that it's (n_particles, )
?
------- | ||
|
||
cost_dec : function | ||
The vectorized output for all particles as defined by :code:`cost_func` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be:
"""
Returns
----------
callable
Put description here
"""
needs to resemble a strategy that can be applied to every particle in the swarm | ||
to assign a cost. This means that the decorated cost function must use an array | ||
of shape :code:`(dimensions, )` as an argument and return a :code:`float` or an | ||
:code:`int`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be phrased as:
If you have defined a cost function that only acts upon a single particle, then you can use this decorator to have a vectorized computation for n particles. ...
Then give an example code-block
maybe? I think good keywords here are: wrapper, transforms, etc. Strategy seems a bit odd (I think you got this from hypothesis haha but I think it's more of their local lingo).
"objective_func", | ||
[np.sum(), np.prod()] | ||
) | ||
def test_cost_decorator(objective_func, particles): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do you get the particles? I suggest you can generate them via np.random.uniform
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know a way we can output the seed number with the tests without using pytest -s
? In this way, we don't have fixed particle arrays and if it fails we can use the printed seed to debug it.
[np.sum(), np.prod()] | ||
) | ||
def test_cost_decorator(objective_func, particles): | ||
def cost_func_w_o_decorator(x): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok to spell it out 😆 cost_func_without_decorator(x)
and cost_fun_with_decorator
Aside from my comments, I think this is great, @whzup ! This is an elegant and useful improvement to our current codebase! Very excited to try this out! |
@ljvmiranda921 Thanks for the comments hahaha. Would've been searching for ages to find a solution to these things 🙈 |
Let's update the branch before we merge this one. I had some trouble with the rebasing of the commits. |
# Import modules | ||
import pytest | ||
import numpy as np | ||
import sys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder where you'll use import sys
for... 👨🚀
Ok, I guess we're ready for the merge. I think we can add change the representation of cost functions in another PR. What do you think? |
Hi @whzup
You mean the
OK let me check first then I'll squash-merge this 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this @whzup ! Almost there! Just a few more things:
- Please update
docs/api/_pyswarms.utils.rst/
. Addpyswarms.utils.decorators
at the top (and since you're there, rearrange them alphabetically--decorators, functions, plotters, search) - Just a comment on
__init__
. The previous version is already OK. Just importcost
explicitly for now. I predict this feature will be widely-used compared to other future decorators. It's better to load other decorators viapyswarms.utils.decorators
pyswarms/__init__.py
Outdated
@@ -16,5 +16,8 @@ | |||
|
|||
from .single import global_best, local_best, general_optimizer | |||
from .discrete import binary | |||
from .utils.decorators import * | |||
from . import utils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I think the previous version was enough where cost
is defined explicitly.
I think the @constraint
decorator in the future is better loaded whenever the user needs it.
import numpy as np | ||
|
||
|
||
def cost(cost_func): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 This is good already
"objective_func", | ||
[np.sum, np.prod] | ||
) | ||
def test_cost_decorator(objective_func, particles): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests are good already 💯
Hmm, I see your point. Although, what do you think about the
No, I mean all cost functions in our examples 😄 |
Hi @whzup ,
I thought about that before, that's why there's this presence of import pyswarms as ps
ps.single.GlobalBestPSO # Good enough
ps.utils.functions.single_obj.sphere # Pretty long
ps.utils.decorators.decorators.cost # Kinda long too.. If it is possible to do That's the reason why I decided to have everything be loaded whenever needed. Atleast I know that users will always come for the high-level optimizers (and I'm sure the Right now, the design kinda follows that of Keras, where we have components separated into modules, and we load them whenever needed. The thing about Still open for this idea, but for now just explicitly declare |
Let's open-up an issue after I merge #227. We'd probably update some of our examples later + README (more animations haha) |
Added a cost function decorator which allows the user to write a cost function that serves as a model for how the cost will be computed for every one particle. The decorator is tested with a pytest file where the shape and the equality with an example function is checked. I added a note to the documentation that some numpy functions will return arrays with single values in them.
Done! 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Resolves #228 Added a cost function decorator which allows the user to write a cost function that serves as a model for how the cost will be computed for every one particle. The decorator is tested with a pytest file where the shape and the equality with an example function is checked. I added a note to the documentation that some numpy functions will return arrays with single values in them.
Description
This decorator allows the creation of much simpler cost functions. Instead of writing a cost function that returns a shape of
(n_particles, 0)
it enables the usage of shorter and simpler cost functions that directly return the cost.Related Issue
Resolves: #228
Motivation and Context
At the moment, the way one has to write the cost function is very counterintuitive as it is necessary to write a function that returns an array of shape
(n_particles, )
. This decorator "vectorizes" a cost function which returns just the cost.How Has This Been Tested?
Wrote a new test file.
Types of changes
Checklist: