flwr-nightly 1.18.0.dev20250424__py3-none-any.whl → 1.19.0.dev20250428__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/common/record/__init__.py +2 -1
- flwr/common/record/array.py +250 -0
- flwr/common/record/arrayrecord.py +3 -223
- flwr/common/record/conversion_utils.py +1 -1
- {flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/METADATA +1 -1
- {flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/RECORD +8 -7
- {flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/entry_points.txt +0 -0
flwr/common/record/__init__.py
CHANGED
@@ -15,7 +15,8 @@
|
|
15
15
|
"""Record APIs."""
|
16
16
|
|
17
17
|
|
18
|
-
from .
|
18
|
+
from .array import Array
|
19
|
+
from .arrayrecord import ArrayRecord, ParametersRecord
|
19
20
|
from .configrecord import ConfigRecord, ConfigsRecord
|
20
21
|
from .conversion_utils import array_from_numpy
|
21
22
|
from .metricrecord import MetricRecord, MetricsRecord
|
@@ -0,0 +1,250 @@
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
# ==============================================================================
|
15
|
+
"""Array."""
|
16
|
+
|
17
|
+
|
18
|
+
from __future__ import annotations
|
19
|
+
|
20
|
+
import sys
|
21
|
+
from dataclasses import dataclass
|
22
|
+
from io import BytesIO
|
23
|
+
from typing import TYPE_CHECKING, Any, cast, overload
|
24
|
+
|
25
|
+
import numpy as np
|
26
|
+
|
27
|
+
from ..constant import SType
|
28
|
+
from ..typing import NDArray
|
29
|
+
|
30
|
+
if TYPE_CHECKING:
|
31
|
+
import torch
|
32
|
+
|
33
|
+
|
34
|
+
def _raise_array_init_error() -> None:
|
35
|
+
raise TypeError(
|
36
|
+
f"Invalid arguments for {Array.__qualname__}. Expected either a "
|
37
|
+
"PyTorch tensor, a NumPy ndarray, or explicit"
|
38
|
+
" dtype/shape/stype/data values."
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class Array:
|
44
|
+
"""Array type.
|
45
|
+
|
46
|
+
A dataclass containing serialized data from an array-like or tensor-like object
|
47
|
+
along with metadata about it. The class can be initialized in one of three ways:
|
48
|
+
|
49
|
+
1. By specifying explicit values for `dtype`, `shape`, `stype`, and `data`.
|
50
|
+
2. By providing a NumPy ndarray (via the `ndarray` argument).
|
51
|
+
3. By providing a PyTorch tensor (via the `torch_tensor` argument).
|
52
|
+
|
53
|
+
In scenarios (2)-(3), the `dtype`, `shape`, `stype`, and `data` are automatically
|
54
|
+
derived from the input. In scenario (1), these fields must be specified manually.
|
55
|
+
|
56
|
+
Parameters
|
57
|
+
----------
|
58
|
+
dtype : Optional[str] (default: None)
|
59
|
+
A string representing the data type of the serialized object (e.g. `"float32"`).
|
60
|
+
Only required if you are not passing in a ndarray or a tensor.
|
61
|
+
|
62
|
+
shape : Optional[list[int]] (default: None)
|
63
|
+
A list representing the shape of the unserialized array-like object. Only
|
64
|
+
required if you are not passing in a ndarray or a tensor.
|
65
|
+
|
66
|
+
stype : Optional[str] (default: None)
|
67
|
+
A string indicating the serialization mechanism used to generate the bytes in
|
68
|
+
`data` from an array-like or tensor-like object. Only required if you are not
|
69
|
+
passing in a ndarray or a tensor.
|
70
|
+
|
71
|
+
data : Optional[bytes] (default: None)
|
72
|
+
A buffer of bytes containing the data. Only required if you are not passing in
|
73
|
+
a ndarray or a tensor.
|
74
|
+
|
75
|
+
ndarray : Optional[NDArray] (default: None)
|
76
|
+
A NumPy ndarray. If provided, the `dtype`, `shape`, `stype`, and `data`
|
77
|
+
fields are derived automatically from it.
|
78
|
+
|
79
|
+
torch_tensor : Optional[torch.Tensor] (default: None)
|
80
|
+
A PyTorch tensor. If provided, it will be **detached and moved to CPU**
|
81
|
+
before conversion, and the `dtype`, `shape`, `stype`, and `data` fields
|
82
|
+
will be derived automatically from it.
|
83
|
+
|
84
|
+
Examples
|
85
|
+
--------
|
86
|
+
Initializing by specifying all fields directly::
|
87
|
+
|
88
|
+
arr1 = Array(
|
89
|
+
dtype="float32",
|
90
|
+
shape=[3, 3],
|
91
|
+
stype="numpy.ndarray",
|
92
|
+
data=b"serialized_data...",
|
93
|
+
)
|
94
|
+
|
95
|
+
Initializing with a NumPy ndarray::
|
96
|
+
|
97
|
+
import numpy as np
|
98
|
+
arr2 = Array(np.random.randn(3, 3))
|
99
|
+
|
100
|
+
Initializing with a PyTorch tensor::
|
101
|
+
|
102
|
+
import torch
|
103
|
+
arr3 = Array(torch.randn(3, 3))
|
104
|
+
"""
|
105
|
+
|
106
|
+
dtype: str
|
107
|
+
shape: list[int]
|
108
|
+
stype: str
|
109
|
+
data: bytes
|
110
|
+
|
111
|
+
@overload
|
112
|
+
def __init__( # noqa: E704
|
113
|
+
self, dtype: str, shape: list[int], stype: str, data: bytes
|
114
|
+
) -> None: ...
|
115
|
+
|
116
|
+
@overload
|
117
|
+
def __init__(self, ndarray: NDArray) -> None: ... # noqa: E704
|
118
|
+
|
119
|
+
@overload
|
120
|
+
def __init__(self, torch_tensor: torch.Tensor) -> None: ... # noqa: E704
|
121
|
+
|
122
|
+
def __init__( # pylint: disable=too-many-arguments, too-many-locals
|
123
|
+
self,
|
124
|
+
*args: Any,
|
125
|
+
dtype: str | None = None,
|
126
|
+
shape: list[int] | None = None,
|
127
|
+
stype: str | None = None,
|
128
|
+
data: bytes | None = None,
|
129
|
+
ndarray: NDArray | None = None,
|
130
|
+
torch_tensor: torch.Tensor | None = None,
|
131
|
+
) -> None:
|
132
|
+
# Determine the initialization method and validate input arguments.
|
133
|
+
# Support three initialization formats:
|
134
|
+
# 1. Array(dtype: str, shape: list[int], stype: str, data: bytes)
|
135
|
+
# 2. Array(ndarray: NDArray)
|
136
|
+
# 3. Array(torch_tensor: torch.Tensor)
|
137
|
+
|
138
|
+
# Initialize all arguments
|
139
|
+
# If more than 4 positional arguments are provided, raise an error.
|
140
|
+
if len(args) > 4:
|
141
|
+
_raise_array_init_error()
|
142
|
+
all_args = [None] * 4
|
143
|
+
for i, arg in enumerate(args):
|
144
|
+
all_args[i] = arg
|
145
|
+
init_method: str | None = None # Track which init method is being used
|
146
|
+
|
147
|
+
# Try to assign a value to all_args[index] if it's not already set.
|
148
|
+
# If an initialization method is provided, update init_method.
|
149
|
+
def _try_set_arg(index: int, arg: Any, method: str) -> None:
|
150
|
+
# Skip if arg is None
|
151
|
+
if arg is None:
|
152
|
+
return
|
153
|
+
# Raise an error if all_args[index] is already set
|
154
|
+
if all_args[index] is not None:
|
155
|
+
_raise_array_init_error()
|
156
|
+
# Raise an error if a different initialization method is already set
|
157
|
+
nonlocal init_method
|
158
|
+
if init_method is not None and init_method != method:
|
159
|
+
_raise_array_init_error()
|
160
|
+
# Set init_method and all_args[index]
|
161
|
+
if init_method is None:
|
162
|
+
init_method = method
|
163
|
+
all_args[index] = arg
|
164
|
+
|
165
|
+
# Try to set keyword arguments in all_args
|
166
|
+
_try_set_arg(0, dtype, "direct")
|
167
|
+
_try_set_arg(1, shape, "direct")
|
168
|
+
_try_set_arg(2, stype, "direct")
|
169
|
+
_try_set_arg(3, data, "direct")
|
170
|
+
_try_set_arg(0, ndarray, "ndarray")
|
171
|
+
_try_set_arg(0, torch_tensor, "torch_tensor")
|
172
|
+
|
173
|
+
# Check if all arguments are correctly set
|
174
|
+
all_args = [arg for arg in all_args if arg is not None]
|
175
|
+
|
176
|
+
# Handle direct field initialization
|
177
|
+
if not init_method or init_method == "direct":
|
178
|
+
if (
|
179
|
+
len(all_args) == 4 # pylint: disable=too-many-boolean-expressions
|
180
|
+
and isinstance(all_args[0], str)
|
181
|
+
and isinstance(all_args[1], list)
|
182
|
+
and all(isinstance(i, int) for i in all_args[1])
|
183
|
+
and isinstance(all_args[2], str)
|
184
|
+
and isinstance(all_args[3], bytes)
|
185
|
+
):
|
186
|
+
self.dtype, self.shape, self.stype, self.data = all_args
|
187
|
+
return
|
188
|
+
|
189
|
+
# Handle NumPy array
|
190
|
+
if not init_method or init_method == "ndarray":
|
191
|
+
if len(all_args) == 1 and isinstance(all_args[0], np.ndarray):
|
192
|
+
self.__dict__.update(self.from_numpy_ndarray(all_args[0]).__dict__)
|
193
|
+
return
|
194
|
+
|
195
|
+
# Handle PyTorch tensor
|
196
|
+
if not init_method or init_method == "torch_tensor":
|
197
|
+
if (
|
198
|
+
len(all_args) == 1
|
199
|
+
and "torch" in sys.modules
|
200
|
+
and isinstance(all_args[0], sys.modules["torch"].Tensor)
|
201
|
+
):
|
202
|
+
self.__dict__.update(self.from_torch_tensor(all_args[0]).__dict__)
|
203
|
+
return
|
204
|
+
|
205
|
+
_raise_array_init_error()
|
206
|
+
|
207
|
+
@classmethod
|
208
|
+
def from_numpy_ndarray(cls, ndarray: NDArray) -> Array:
|
209
|
+
"""Create Array from NumPy ndarray."""
|
210
|
+
assert isinstance(
|
211
|
+
ndarray, np.ndarray
|
212
|
+
), f"Expected NumPy ndarray, got {type(ndarray)}"
|
213
|
+
buffer = BytesIO()
|
214
|
+
# WARNING: NEVER set allow_pickle to true.
|
215
|
+
# Reason: loading pickled data can execute arbitrary code
|
216
|
+
# Source: https://numpy.org/doc/stable/reference/generated/numpy.save.html
|
217
|
+
np.save(buffer, ndarray, allow_pickle=False)
|
218
|
+
data = buffer.getvalue()
|
219
|
+
return Array(
|
220
|
+
dtype=str(ndarray.dtype),
|
221
|
+
shape=list(ndarray.shape),
|
222
|
+
stype=SType.NUMPY,
|
223
|
+
data=data,
|
224
|
+
)
|
225
|
+
|
226
|
+
@classmethod
|
227
|
+
def from_torch_tensor(cls, tensor: torch.Tensor) -> Array:
|
228
|
+
"""Create Array from PyTorch tensor."""
|
229
|
+
if not (torch := sys.modules.get("torch")):
|
230
|
+
raise RuntimeError(
|
231
|
+
f"PyTorch is required to use {cls.from_torch_tensor.__name__}"
|
232
|
+
)
|
233
|
+
|
234
|
+
assert isinstance(
|
235
|
+
tensor, torch.Tensor
|
236
|
+
), f"Expected PyTorch Tensor, got {type(tensor)}"
|
237
|
+
return cls.from_numpy_ndarray(tensor.detach().cpu().numpy())
|
238
|
+
|
239
|
+
def numpy(self) -> NDArray:
|
240
|
+
"""Return the array as a NumPy array."""
|
241
|
+
if self.stype != SType.NUMPY:
|
242
|
+
raise TypeError(
|
243
|
+
f"Unsupported serialization type for numpy conversion: '{self.stype}'"
|
244
|
+
)
|
245
|
+
bytes_io = BytesIO(self.data)
|
246
|
+
# WARNING: NEVER set allow_pickle to true.
|
247
|
+
# Reason: loading pickled data can execute arbitrary code
|
248
|
+
# Source: https://numpy.org/doc/stable/reference/generated/numpy.load.html
|
249
|
+
ndarray_deserialized = np.load(bytes_io, allow_pickle=False)
|
250
|
+
return cast(NDArray, ndarray_deserialized)
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""ArrayRecord
|
15
|
+
"""ArrayRecord."""
|
16
16
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
@@ -20,30 +20,21 @@ from __future__ import annotations
|
|
20
20
|
import gc
|
21
21
|
import sys
|
22
22
|
from collections import OrderedDict
|
23
|
-
from dataclasses import dataclass
|
24
|
-
from io import BytesIO
|
25
23
|
from logging import WARN
|
26
24
|
from typing import TYPE_CHECKING, Any, cast, overload
|
27
25
|
|
28
26
|
import numpy as np
|
29
27
|
|
30
|
-
from ..constant import GC_THRESHOLD
|
28
|
+
from ..constant import GC_THRESHOLD
|
31
29
|
from ..logger import log
|
32
30
|
from ..typing import NDArray
|
31
|
+
from .array import Array
|
33
32
|
from .typeddict import TypedDict
|
34
33
|
|
35
34
|
if TYPE_CHECKING:
|
36
35
|
import torch
|
37
36
|
|
38
37
|
|
39
|
-
def _raise_array_init_error() -> None:
|
40
|
-
raise TypeError(
|
41
|
-
f"Invalid arguments for {Array.__qualname__}. Expected either a "
|
42
|
-
"PyTorch tensor, a NumPy ndarray, or explicit"
|
43
|
-
" dtype/shape/stype/data values."
|
44
|
-
)
|
45
|
-
|
46
|
-
|
47
38
|
def _raise_array_record_init_error() -> None:
|
48
39
|
raise TypeError(
|
49
40
|
f"Invalid arguments for {ArrayRecord.__qualname__}. Expected either "
|
@@ -52,217 +43,6 @@ def _raise_array_record_init_error() -> None:
|
|
52
43
|
)
|
53
44
|
|
54
45
|
|
55
|
-
@dataclass
|
56
|
-
class Array:
|
57
|
-
"""Array type.
|
58
|
-
|
59
|
-
A dataclass containing serialized data from an array-like or tensor-like object
|
60
|
-
along with metadata about it. The class can be initialized in one of three ways:
|
61
|
-
|
62
|
-
1. By specifying explicit values for `dtype`, `shape`, `stype`, and `data`.
|
63
|
-
2. By providing a NumPy ndarray (via the `ndarray` argument).
|
64
|
-
3. By providing a PyTorch tensor (via the `torch_tensor` argument).
|
65
|
-
|
66
|
-
In scenarios (2)-(3), the `dtype`, `shape`, `stype`, and `data` are automatically
|
67
|
-
derived from the input. In scenario (1), these fields must be specified manually.
|
68
|
-
|
69
|
-
Parameters
|
70
|
-
----------
|
71
|
-
dtype : Optional[str] (default: None)
|
72
|
-
A string representing the data type of the serialized object (e.g. `"float32"`).
|
73
|
-
Only required if you are not passing in a ndarray or a tensor.
|
74
|
-
|
75
|
-
shape : Optional[list[int]] (default: None)
|
76
|
-
A list representing the shape of the unserialized array-like object. Only
|
77
|
-
required if you are not passing in a ndarray or a tensor.
|
78
|
-
|
79
|
-
stype : Optional[str] (default: None)
|
80
|
-
A string indicating the serialization mechanism used to generate the bytes in
|
81
|
-
`data` from an array-like or tensor-like object. Only required if you are not
|
82
|
-
passing in a ndarray or a tensor.
|
83
|
-
|
84
|
-
data : Optional[bytes] (default: None)
|
85
|
-
A buffer of bytes containing the data. Only required if you are not passing in
|
86
|
-
a ndarray or a tensor.
|
87
|
-
|
88
|
-
ndarray : Optional[NDArray] (default: None)
|
89
|
-
A NumPy ndarray. If provided, the `dtype`, `shape`, `stype`, and `data`
|
90
|
-
fields are derived automatically from it.
|
91
|
-
|
92
|
-
torch_tensor : Optional[torch.Tensor] (default: None)
|
93
|
-
A PyTorch tensor. If provided, it will be **detached and moved to CPU**
|
94
|
-
before conversion, and the `dtype`, `shape`, `stype`, and `data` fields
|
95
|
-
will be derived automatically from it.
|
96
|
-
|
97
|
-
Examples
|
98
|
-
--------
|
99
|
-
Initializing by specifying all fields directly::
|
100
|
-
|
101
|
-
arr1 = Array(
|
102
|
-
dtype="float32",
|
103
|
-
shape=[3, 3],
|
104
|
-
stype="numpy.ndarray",
|
105
|
-
data=b"serialized_data...",
|
106
|
-
)
|
107
|
-
|
108
|
-
Initializing with a NumPy ndarray::
|
109
|
-
|
110
|
-
import numpy as np
|
111
|
-
arr2 = Array(np.random.randn(3, 3))
|
112
|
-
|
113
|
-
Initializing with a PyTorch tensor::
|
114
|
-
|
115
|
-
import torch
|
116
|
-
arr3 = Array(torch.randn(3, 3))
|
117
|
-
"""
|
118
|
-
|
119
|
-
dtype: str
|
120
|
-
shape: list[int]
|
121
|
-
stype: str
|
122
|
-
data: bytes
|
123
|
-
|
124
|
-
@overload
|
125
|
-
def __init__( # noqa: E704
|
126
|
-
self, dtype: str, shape: list[int], stype: str, data: bytes
|
127
|
-
) -> None: ...
|
128
|
-
|
129
|
-
@overload
|
130
|
-
def __init__(self, ndarray: NDArray) -> None: ... # noqa: E704
|
131
|
-
|
132
|
-
@overload
|
133
|
-
def __init__(self, torch_tensor: torch.Tensor) -> None: ... # noqa: E704
|
134
|
-
|
135
|
-
def __init__( # pylint: disable=too-many-arguments, too-many-locals
|
136
|
-
self,
|
137
|
-
*args: Any,
|
138
|
-
dtype: str | None = None,
|
139
|
-
shape: list[int] | None = None,
|
140
|
-
stype: str | None = None,
|
141
|
-
data: bytes | None = None,
|
142
|
-
ndarray: NDArray | None = None,
|
143
|
-
torch_tensor: torch.Tensor | None = None,
|
144
|
-
) -> None:
|
145
|
-
# Determine the initialization method and validate input arguments.
|
146
|
-
# Support three initialization formats:
|
147
|
-
# 1. Array(dtype: str, shape: list[int], stype: str, data: bytes)
|
148
|
-
# 2. Array(ndarray: NDArray)
|
149
|
-
# 3. Array(torch_tensor: torch.Tensor)
|
150
|
-
|
151
|
-
# Initialize all arguments
|
152
|
-
# If more than 4 positional arguments are provided, raise an error.
|
153
|
-
if len(args) > 4:
|
154
|
-
_raise_array_init_error()
|
155
|
-
all_args = [None] * 4
|
156
|
-
for i, arg in enumerate(args):
|
157
|
-
all_args[i] = arg
|
158
|
-
init_method: str | None = None # Track which init method is being used
|
159
|
-
|
160
|
-
# Try to assign a value to all_args[index] if it's not already set.
|
161
|
-
# If an initialization method is provided, update init_method.
|
162
|
-
def _try_set_arg(index: int, arg: Any, method: str) -> None:
|
163
|
-
# Skip if arg is None
|
164
|
-
if arg is None:
|
165
|
-
return
|
166
|
-
# Raise an error if all_args[index] is already set
|
167
|
-
if all_args[index] is not None:
|
168
|
-
_raise_array_init_error()
|
169
|
-
# Raise an error if a different initialization method is already set
|
170
|
-
nonlocal init_method
|
171
|
-
if init_method is not None and init_method != method:
|
172
|
-
_raise_array_init_error()
|
173
|
-
# Set init_method and all_args[index]
|
174
|
-
if init_method is None:
|
175
|
-
init_method = method
|
176
|
-
all_args[index] = arg
|
177
|
-
|
178
|
-
# Try to set keyword arguments in all_args
|
179
|
-
_try_set_arg(0, dtype, "direct")
|
180
|
-
_try_set_arg(1, shape, "direct")
|
181
|
-
_try_set_arg(2, stype, "direct")
|
182
|
-
_try_set_arg(3, data, "direct")
|
183
|
-
_try_set_arg(0, ndarray, "ndarray")
|
184
|
-
_try_set_arg(0, torch_tensor, "torch_tensor")
|
185
|
-
|
186
|
-
# Check if all arguments are correctly set
|
187
|
-
all_args = [arg for arg in all_args if arg is not None]
|
188
|
-
|
189
|
-
# Handle direct field initialization
|
190
|
-
if not init_method or init_method == "direct":
|
191
|
-
if (
|
192
|
-
len(all_args) == 4 # pylint: disable=too-many-boolean-expressions
|
193
|
-
and isinstance(all_args[0], str)
|
194
|
-
and isinstance(all_args[1], list)
|
195
|
-
and all(isinstance(i, int) for i in all_args[1])
|
196
|
-
and isinstance(all_args[2], str)
|
197
|
-
and isinstance(all_args[3], bytes)
|
198
|
-
):
|
199
|
-
self.dtype, self.shape, self.stype, self.data = all_args
|
200
|
-
return
|
201
|
-
|
202
|
-
# Handle NumPy array
|
203
|
-
if not init_method or init_method == "ndarray":
|
204
|
-
if len(all_args) == 1 and isinstance(all_args[0], np.ndarray):
|
205
|
-
self.__dict__.update(self.from_numpy_ndarray(all_args[0]).__dict__)
|
206
|
-
return
|
207
|
-
|
208
|
-
# Handle PyTorch tensor
|
209
|
-
if not init_method or init_method == "torch_tensor":
|
210
|
-
if (
|
211
|
-
len(all_args) == 1
|
212
|
-
and "torch" in sys.modules
|
213
|
-
and isinstance(all_args[0], sys.modules["torch"].Tensor)
|
214
|
-
):
|
215
|
-
self.__dict__.update(self.from_torch_tensor(all_args[0]).__dict__)
|
216
|
-
return
|
217
|
-
|
218
|
-
_raise_array_init_error()
|
219
|
-
|
220
|
-
@classmethod
|
221
|
-
def from_numpy_ndarray(cls, ndarray: NDArray) -> Array:
|
222
|
-
"""Create Array from NumPy ndarray."""
|
223
|
-
assert isinstance(
|
224
|
-
ndarray, np.ndarray
|
225
|
-
), f"Expected NumPy ndarray, got {type(ndarray)}"
|
226
|
-
buffer = BytesIO()
|
227
|
-
# WARNING: NEVER set allow_pickle to true.
|
228
|
-
# Reason: loading pickled data can execute arbitrary code
|
229
|
-
# Source: https://numpy.org/doc/stable/reference/generated/numpy.save.html
|
230
|
-
np.save(buffer, ndarray, allow_pickle=False)
|
231
|
-
data = buffer.getvalue()
|
232
|
-
return Array(
|
233
|
-
dtype=str(ndarray.dtype),
|
234
|
-
shape=list(ndarray.shape),
|
235
|
-
stype=SType.NUMPY,
|
236
|
-
data=data,
|
237
|
-
)
|
238
|
-
|
239
|
-
@classmethod
|
240
|
-
def from_torch_tensor(cls, tensor: torch.Tensor) -> Array:
|
241
|
-
"""Create Array from PyTorch tensor."""
|
242
|
-
if not (torch := sys.modules.get("torch")):
|
243
|
-
raise RuntimeError(
|
244
|
-
f"PyTorch is required to use {cls.from_torch_tensor.__name__}"
|
245
|
-
)
|
246
|
-
|
247
|
-
assert isinstance(
|
248
|
-
tensor, torch.Tensor
|
249
|
-
), f"Expected PyTorch Tensor, got {type(tensor)}"
|
250
|
-
return cls.from_numpy_ndarray(tensor.detach().cpu().numpy())
|
251
|
-
|
252
|
-
def numpy(self) -> NDArray:
|
253
|
-
"""Return the array as a NumPy array."""
|
254
|
-
if self.stype != SType.NUMPY:
|
255
|
-
raise TypeError(
|
256
|
-
f"Unsupported serialization type for numpy conversion: '{self.stype}'"
|
257
|
-
)
|
258
|
-
bytes_io = BytesIO(self.data)
|
259
|
-
# WARNING: NEVER set allow_pickle to true.
|
260
|
-
# Reason: loading pickled data can execute arbitrary code
|
261
|
-
# Source: https://numpy.org/doc/stable/reference/generated/numpy.load.html
|
262
|
-
ndarray_deserialized = np.load(bytes_io, allow_pickle=False)
|
263
|
-
return cast(NDArray, ndarray_deserialized)
|
264
|
-
|
265
|
-
|
266
46
|
def _check_key(key: str) -> None:
|
267
47
|
"""Check if key is of expected type."""
|
268
48
|
if not isinstance(key, str):
|
{flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/RECORD
RENAMED
@@ -134,10 +134,11 @@ flwr/common/message.py,sha256=znr205Erq2hkxwFbvNNCsQTRS2UKv_Qsyu0sFNEhEAw,23721
|
|
134
134
|
flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
|
135
135
|
flwr/common/parameter.py,sha256=UVw6sOgehEFhFs4uUCMl2kfVq1PD6ncmWgPLMsZPKPE,2095
|
136
136
|
flwr/common/pyproject.py,sha256=2SU6yJW7059SbMXgzjOdK1GZRWO6AixDH7BmdxbMvHI,1386
|
137
|
-
flwr/common/record/__init__.py,sha256=
|
138
|
-
flwr/common/record/
|
137
|
+
flwr/common/record/__init__.py,sha256=cNGccdDoxttqgnUgyKRIqLWULjW-NaSmOufVxtXq-sw,1197
|
138
|
+
flwr/common/record/array.py,sha256=eRyAGyIN5UiUY85l4nxOGgaMvUaClkvg814wluBeIKY,9291
|
139
|
+
flwr/common/record/arrayrecord.py,sha256=KbehV2yXJ_6ZWcHPPrC-MNkE00DRCObxgyrVLwBQ5OY,14389
|
139
140
|
flwr/common/record/configrecord.py,sha256=U9Jsuc5TWxYKaVQvaXiKn2mrqZxeVixsnyRqOnmWsWM,7743
|
140
|
-
flwr/common/record/conversion_utils.py,sha256=
|
141
|
+
flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
|
141
142
|
flwr/common/record/metricrecord.py,sha256=9mMaphD4W5aWL2IYt2DjzWM_uFGCYAcTSzdgWKfLGqs,7008
|
142
143
|
flwr/common/record/recorddict.py,sha256=zo7TiVZCH_LB9gwUP7-Jo-jLpFLrvxYSryovwZANQiw,12386
|
143
144
|
flwr/common/record/typeddict.py,sha256=dDKgUThs2BscYUNcgP82KP8-qfAYXYftDrf2LszAC_o,3599
|
@@ -326,7 +327,7 @@ flwr/superexec/exec_servicer.py,sha256=Z0YYfs6eNPhqn8rY0x_R04XgR2mKFpggt07IH0EhU
|
|
326
327
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=iqygALkOMBUu_s_R9G0mFThZA7HTUzuXCLgxLCefiwI,4440
|
327
328
|
flwr/superexec/executor.py,sha256=M5ucqSE53jfRtuCNf59WFLqQvA1Mln4741TySeZE7qQ,3112
|
328
329
|
flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,4088
|
329
|
-
flwr_nightly-1.
|
330
|
-
flwr_nightly-1.
|
331
|
-
flwr_nightly-1.
|
332
|
-
flwr_nightly-1.
|
330
|
+
flwr_nightly-1.19.0.dev20250428.dist-info/METADATA,sha256=z7jxJvqtebWZqo4CHr9YOqjqRRJYddFi7-RkyIwJ5p8,15868
|
331
|
+
flwr_nightly-1.19.0.dev20250428.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
332
|
+
flwr_nightly-1.19.0.dev20250428.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
|
333
|
+
flwr_nightly-1.19.0.dev20250428.dist-info/RECORD,,
|
{flwr_nightly-1.18.0.dev20250424.dist-info → flwr_nightly-1.19.0.dev20250428.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|