# Copyright 2025 Flower Labs GmbH. All Rights Reserved.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.# =============================================================================="""Strategy results."""importpprintfromdataclassesimportdataclass,fieldfromflwr.commonimportArrayRecord,MetricRecordfromflwr.common.typingimportMetricRecordValues
[docs]@dataclassclassResult:"""Data class carrying records generated during the execution of a strategy. This class encapsulates the results of a federated learning strategy execution, including the final global model parameters and metrics collected throughout the federated training and evaluation (both federated and centralized) stages. Attributes ---------- arrays : ArrayRecord The final global model parameters. Contains the aggregated model weights/parameters that resulted from the federated learning process. train_metrics_clientapp : dict[int, MetricRecord] Training metrics collected from ClientApps, indexed by round number. Contains aggregated metrics (e.g., loss, accuracy) from the training phase of each federated learning round. evaluate_metrics_clientapp : dict[int, MetricRecord] Evaluation metrics collected from ClientApps, indexed by round number. Contains aggregated metrics (e.g. validation loss) from the evaluation phase where ClientApps evaluate the global model on their local validation/test data. evaluate_metrics_serverapp : dict[int, MetricRecord] Evaluation metrics generated at the ServerApp, indexed by round number. Contains metrics from centralized evaluation performed by the ServerApp (e.g., when the server evaluates the global model on a held-out dataset). """arrays:ArrayRecord=field(default_factory=ArrayRecord)train_metrics_clientapp:dict[int,MetricRecord]=field(default_factory=dict)evaluate_metrics_clientapp:dict[int,MetricRecord]=field(default_factory=dict)evaluate_metrics_serverapp:dict[int,MetricRecord]=field(default_factory=dict)def__repr__(self)->str:"""Create a representation of the Result instance."""rep=""arr_size=sum(len(array.data)forarrayinself.arrays.values())/(1024**2)rep+="Global Arrays:\n"+f"\tArrayRecord ({arr_size:.3f} MB)\n"+"\n"rep+=("Aggregated Client-side Train Metrics:\n"+pprint.pformat(stringify_dict(self.train_metrics_clientapp),indent=2)+"\n\n")rep+=("Aggregated Client-side Evaluate Metrics:\n"+pprint.pformat(stringify_dict(self.evaluate_metrics_clientapp),indent=2)+"\n\n")rep+=("Server-side Evaluate Metrics:\n"+pprint.pformat(stringify_dict(self.evaluate_metrics_serverapp),indent=2)+"\n")returnrep
defformat_value(val:MetricRecordValues)->str:"""Format a value as string, applying scientific notation for floats."""ifisinstance(val,float):returnf"{val:.4e}"ifisinstance(val,int):returnstr(val)ifisinstance(val,list):returnstr([f"{x:.4e}"ifisinstance(x,float)elsestr(x)forxinval])returnstr(val)defstringify_dict(d:dict[int,MetricRecord])->dict[int,dict[str,str]]:"""Return a copy results metrics but with values converted to string and formatted accordingtly."""new_metrics_dict={}fork,innerind.items():new_inner={}forik,ivininner.items():new_inner[ik]=format_value(iv)new_metrics_dict[k]=new_innerreturnnew_metrics_dict