fedbiomed.researcher.strategies
Module:fedbiomed.researcher.strategies
Classes
DefaultStrategy
DefaultStrategy(data)
Bases: Strategy
Default strategy to be used when sampling/selecting nodes and checking whether nodes have responded or not
Strategy is: - select all node for each round - raise an error if one node does not answer - raise an error is one node returns an error
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data | FederatedDataSet | Object that includes all active nodes and the meta-data of the dataset that is going to be used for federated training. Should be passed to | required |
Source code in fedbiomed/researcher/strategies/default_strategy.py
def __init__(self, data: FederatedDataSet):
""" Constructor of Default Strategy
Args:
data: Object that includes all active nodes and the meta-data of the dataset that is going to be
used for federated training. Should be passed to `super().__init__` to initialize parent class
"""
super().__init__(data)
Functions
refine(training_replies, round_i)
refine(training_replies, round_i)
The method where node selection is completed by extracting parameters and length from the training replies
Parameters:
Name | Type | Description | Default |
---|---|---|---|
training_replies | Responses | is a list of elements of type Response( { 'success': m['success'], 'msg': m['msg'], 'dataset_id': m['dataset_id'], 'node_id': m['node_id'], 'params_path': params_path, 'params': params } ) | required |
round_i | int | Current round of experiment | required |
Returns:
Name | Type | Description |
---|---|---|
weights | List | Proportions list, each element of this list represents a dictionary with its only key as the node_id and its value the proportion of lines the node has with respect to the whole, |
model_params | List | list with each element representing a dictionary. Its only key represents the node_id and the corresponding value is a dictionary containing list of weight matrices of every node : [{"n1":{"layer1":m1,"layer2":m2},{"layer3":"m3"}},{"n2": ...}] Including the node_id is useful for the proper functioning of some strategies like Scaffold : At each round, local model params are linked to a certain correction. The correction is updated every round. The computation of correction states at round i is dependant to client states and correction states of round i-1. Since training_replies can potentially order the node replies differently from round to round, the bridge between all these parameters is represented by the node_id. |
Raises:
Type | Description |
---|---|
FedbiomedStrategyError |
|
Source code in fedbiomed/researcher/strategies/default_strategy.py
def refine(self, training_replies: Responses, round_i: int) -> Tuple[List, List]:
"""
The method where node selection is completed by extracting parameters and length from the training replies
Args:
training_replies: is a list of elements of type
Response( { 'success': m['success'],
'msg': m['msg'],
'dataset_id': m['dataset_id'],
'node_id': m['node_id'],
'params_path': params_path,
'params': params } )
round_i: Current round of experiment
Returns:
weights: Proportions list, each element of this list represents a dictionary with its only key as
the node_id and its value the proportion of lines the node has with respect to the whole,
model_params: list with each element representing a dictionary. Its only key represents the node_id
and the corresponding value is a dictionary containing list of weight matrices of every node : [{"n1":{"layer1":m1,"layer2":m2},{"layer3":"m3"}},{"n2": ...}]
Including the node_id is useful for the proper functioning of some strategies like Scaffold :
At each round, local model params are linked to a certain correction. The correction is updated every round.
The computation of correction states at round i is dependant to client states and correction states of round i-1.
Since training_replies can potentially order the node replies differently from round to round, the bridge between
all these parameters is represented by the node_id.
Raises:
FedbiomedStrategyError: - Miss-matched in answered nodes and existing nodes
- If not all nodes successfully completes training
"""
models_params = []
weights = []
# check that all nodes answered
cl_answered = [val['node_id'] for val in training_replies.data()]
answers_count = 0
for cl in self.sample_nodes(round_i):
if cl in cl_answered:
answers_count += 1
else:
# this node did not answer
logger.error(ErrorNumbers.FB408.value +
" (node = " +
cl +
")"
)
if len(self.sample_nodes(round_i)) != answers_count:
if answers_count == 0:
# none of the nodes answered
msg = ErrorNumbers.FB407.value
else:
msg = ErrorNumbers.FB408.value
logger.critical(msg)
raise FedbiomedStrategyError(msg)
# check that all nodes that answer could successfully train
self._success_node_history[round_i] = []
all_success = True
for tr in training_replies:
if tr['success'] is True:
model_params = {tr['node_id']: tr['params']}
models_params.append(model_params)
self._success_node_history[round_i].append(tr['node_id'])
else:
# node did not succeed
all_success = False
logger.error(ErrorNumbers.FB409.value +
" (node = " +
tr['node_id'] +
")"
)
if not all_success:
raise FedbiomedStrategyError(ErrorNumbers.FB402.value)
# so far, everything is OK
totalrows = sum([val[0]["shape"][0] for (key, val) in self._fds.data().items()])
weights = [{key: val[0]["shape"][0] / totalrows} for (key, val) in self._fds.data().items()]
logger.info('Nodes that successfully reply in round ' +
str(round_i) + ' ' +
str(self._success_node_history[round_i]))
return models_params, weights
sample_nodes(round_i)
sample_nodes(round_i)
Samples and selects nodes on which to train local model. In this strategy we will consider all existing nodes
Parameters:
Name | Type | Description | Default |
---|---|---|---|
round_i | int | number of round. | required |
Returns:
Name | Type | Description |
---|---|---|
node_ids | List[uuid.UUID] | list of all node ids considered for training during this round |
Source code in fedbiomed/researcher/strategies/default_strategy.py
def sample_nodes(self, round_i: int) -> List[uuid.UUID]:
""" Samples and selects nodes on which to train local model. In this strategy we will consider all existing
nodes
Args:
round_i: number of round.
Returns:
node_ids: list of all node ids considered for training during
this round `round_i`.
"""
self._sampling_node_history[round_i] = self._fds.node_ids()
return self._fds.node_ids()
Strategy
Strategy(data)
Default Strategy as Parent class. Custom strategy classes must inherit from this parent class.
used for federated training.
Source code in fedbiomed/researcher/strategies/strategy.py
def __init__(self, data: FederatedDataSet):
"""
Args:
data: Object that includes all active nodes and the meta-data of the dataset that is going to be
used for federated training.
"""
self._fds = data
self._sampling_node_history = {}
self._success_node_history = {}
self._parameters = None
Functions
load_state(state=None, kwargs)
load_state(state=None, kwargs)
Method for loading strategy state from breakpoint state
Parameters:
Name | Type | Description | Default |
---|---|---|---|
state | Dict[str, Any] | The state that will be loaded | None |
Source code in fedbiomed/researcher/strategies/strategy.py
def load_state(self, state: Dict[str, Any] = None, **kwargs):
"""
Method for loading strategy state from breakpoint state
Args:
state: The state that will be loaded
"""
# fds may be modified and diverge from Experiment
self._fds = FederatedDataSet(state.get('fds'))
self._parameters = state['parameters']
refine(training_replies, round_i)
refine(training_replies, round_i)
Abstract method that must be implemented by child class
Parameters:
Name | Type | Description | Default |
---|---|---|---|
training_replies | Responses | is a list of elements of type Response( { 'success': m['success'], 'msg': m['msg'], 'dataset_id': m['dataset_id'], 'node_id': m['node_id'], 'params_path': params_path, 'params': params } ) | required |
round_i | int | Current round of experiment | required |
Raises:
Type | Description |
---|---|
FedbiomedStrategyError | If method is not implemented by child class |
Source code in fedbiomed/researcher/strategies/strategy.py
def refine(self, training_replies: Responses, round_i: int) -> tuple[list, list]:
"""
Abstract method that must be implemented by child class
Args:
training_replies: is a list of elements of type
Response( { 'success': m['success'],
'msg': m['msg'],
'dataset_id': m['dataset_id'],
'node_id': m['node_id'],
'params_path': params_path,
'params': params } )
round_i: Current round of experiment
Raises:
FedbiomedStrategyError: If method is not implemented by child class
"""
msg = ErrorNumbers.FB402.value + \
": refine method should be overloaded by the provided strategy"
logger.critical(msg)
raise FedbiomedStrategyError(msg)
sample_nodes(round_i)
sample_nodes(round_i)
Abstract method that must be implemented by child class
Parameters:
Name | Type | Description | Default |
---|---|---|---|
round_i | int | Current round of experiment | required |
Source code in fedbiomed/researcher/strategies/strategy.py
def sample_nodes(self, round_i: int):
"""
Abstract method that must be implemented by child class
Args:
round_i: Current round of experiment
"""
msg = ErrorNumbers.FB402.value + \
": sample nodes method should be overloaded by the provided strategy"
logger.critical(msg)
raise FedbiomedStrategyError(msg)
save_state()
save_state()
Method for saving strategy state for saving breakpoints
Returns:
Type | Description |
---|---|
Dict[str, Any] | The state of the strategy |
Source code in fedbiomed/researcher/strategies/strategy.py
def save_state(self) -> Dict[str, Any]:
"""
Method for saving strategy state for saving breakpoints
Returns:
The state of the strategy
"""
state = {
"class": type(self).__name__,
"module": self.__module__,
"parameters": self._parameters,
"fds": self._fds.data()
}
return state