-
Notifications
You must be signed in to change notification settings - Fork 207
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
Straggler handling Follow-up #1097
base: develop
Are you sure you want to change the base?
Straggler handling Follow-up #1097
Conversation
Signed-off-by: Ishant Thakare <ishantrog752@gmail.com>
Signed-off-by: Ishant Thakare <ishantrog752@gmail.com>
@ishant162 , did you test for regression by raising a PR in OpenFL-Security? |
This needs to be done @teoparvanov . We will feedback once it is 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.
This is a good improvement over the previous layout.
Most suggestions, though seem like nitpicks, have measurable changes on developers and users in the look-and-feel of the framework. Please take a look.
@@ -69,7 +69,7 @@ def __init__( | |||
best_state_path, | |||
last_state_path, | |||
assigner, | |||
straggler_handling_policy=None, | |||
straggler_handling_policy=CutoffPolicy, |
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.
Add a typehint.
straggler_handling_policy: BasePolicy = CutoffPolicy,
@@ -92,7 +92,7 @@ def __init__( | |||
weight. | |||
assigner: Assigner object. | |||
straggler_handling_policy (optional): Straggler handling policy. | |||
Defaults to CutoffTimeBasedStragglerHandling. | |||
Defaults to CutoffPolicy. |
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.
Suggest removing the mention of default. Most IDEs show this when defaults are provided. One less line to maintain if default changes in the future.
if straggler_handling_policy == CutoffPolicy: | ||
self.straggler_handling_policy = straggler_handling_policy() | ||
else: | ||
self.straggler_handling_policy = straggler_handling_policy | ||
|
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 suggest creating a DefaultPolicy
. This simplifies:
self.straggler_handling_policy = straggler_handling_policy()
regardless of what is given, saves 4 lines.DefaultPolicy
would be the equivalent of providing no straggler handling capabilities. Dummy class.
Also the condition check is wrong. What if PercentagePolicy
is provided? It will go to else block and fail in code, it seems.
def start_policy(self, **kwargs) -> None: | ||
""" | ||
Start straggler handling policy for collaborator for a particular round. | ||
NOTE: Refer CutoffPolicy for reference. |
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.
Why is CutoffPolicy
mentioned here?
""" | ||
Reset policy variable for the next round. | ||
|
||
Args: | ||
None | ||
|
||
Returns: | ||
None |
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.
If this is the case for subclassed policies, please eliminate empty lines. It suffices to say Resets policy for the next round
and not using 6 lines to say it takes or returns nothing. The -> None
and no args make it obvious to the user in an IDE.
Also on the info itself: It is better to mention what exactly is being reset without leaking into the detail. Example Resets countdown timer for collaborator reporting until next round
, or along those lines.
"""Initialize a PercentagePolicy object. | ||
|
||
Args: | ||
percent_collaborators_needed (float, optional): The percentage of | ||
collaborators needed. Defaults to 1.0. | ||
minimum_reporting (int, optional): The minimum number of | ||
collaborators that should report. Defaults to 1. | ||
**kwargs: Variable length argument list. | ||
""" |
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.
Class docstring should go near attributes, not in __init__
. Example:
class PercentagePolicy(StragglerHandlingPolicy):
"""Percentage based Straggler Handling function.
Args:
percent_collaborators_needed (float, optional): The percentage of
collaborators required before concluding the round. Defaults to 1.0.
minimum_reporting (int, optional): The minimum number of
collaborators that should report, regardless of percentage threshold. Defaults to 1.
**kwargs: Variable length argument list.
"""
def __init__(self, percent_collaborators_needed=1.0, minimum_reporting=1, **kwargs):
if minimum_reporting <= 0:
raise ValueError("minimum_reporting must be >0")
self.percent_collaborators_needed = percent_collaborators_needed
self.minimum_reporting = minimum_reporting
self.logger = getLogger(__name__)
On the **kwargs
: Why would a user provide this? Where does it get used, please mention like keyword arguments forwarded to some.module.class
). If they are never forwarded or stored (which seems to be the case looking at certain classes, they should not be accepted from the user either.
if minimum_reporting <= 0: | ||
raise ValueError("minimum_reporting must be >0") |
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.
One liner: assert minimum_reporting > 0, "Minimum reporting must be >0"
|
||
self.percent_collaborators_needed = percent_collaborators_needed | ||
self.minimum_reporting = minimum_reporting | ||
self.logger = getLogger(__name__) |
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.
Can we start defining logger = getLogger(__name__)
below imports and use it globally within this file?
We should slowly move away from these tiny design choices.
""" | ||
Not required in PercentagePolicy. | ||
""" |
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.
Save lines!
def reset_policy_for_round(self) -> None:
"""Ignored in `PercentagePolicy`."""
pass
@@ -421,7 +421,7 @@ def get_tensor_pipe(self): | |||
|
|||
def get_straggler_handling_policy(self): | |||
"""Get straggler handling policy.""" | |||
template = "openfl.component.straggler_handling_functions.CutoffTimeBasedStragglerHandling" | |||
template = "openfl.component.aggregator.straggler_handling.CutoffPolicy" |
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.
Is this default? What is the default behavior?
This pull request is a follow-up to the Straggler Handling PR #996 . Based on the feedback from @MasterSkepticista and @teoparvanov , the review comments have been addressed and incorporated accordingly.
Summary of changes:
openfl/component/aggregator
directory.openfl/component/aggregator/straggler_handling.py
CutoffTimeBasedStragglerHandling
toCutoffPolicy
andPercentageBasedStragglerHandling
toPercentagePolicy
CutoffPolicy
PR is currently in draft