shared-tensor 0.2.13__tar.gz → 0.2.15__tar.gz
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.
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/PKG-INFO +51 -3
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/README.md +50 -1
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/pyproject.toml +1 -2
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/__init__.py +1 -1
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/utils.py +129 -6
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/LICENSE +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/MANIFEST.in +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/setup.cfg +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/async_client.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/async_task.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/client.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/errors.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/managed_object.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/provider.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/runtime.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/server.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor/transport.py +0 -0
- {shared_tensor-0.2.13 → shared_tensor-0.2.15}/shared_tensor.egg-info/SOURCES.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shared-tensor
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.15
|
|
4
4
|
Summary: Native PyTorch CUDA IPC over Unix Domain Socket for same-host process separation
|
|
5
5
|
Author-email: Athena Team <contact@world-sim-dev.org>
|
|
6
6
|
Maintainer-email: Athena Team <contact@world-sim-dev.org>
|
|
@@ -30,7 +30,6 @@ Description-Content-Type: text/markdown
|
|
|
30
30
|
License-File: LICENSE
|
|
31
31
|
Requires-Dist: cloudpickle>=3.0.0
|
|
32
32
|
Requires-Dist: numpy<2
|
|
33
|
-
Requires-Dist: torch>=2.1
|
|
34
33
|
Provides-Extra: dev
|
|
35
34
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
36
35
|
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
@@ -78,9 +77,10 @@ Not supported:
|
|
|
78
77
|
|
|
79
78
|
## Install
|
|
80
79
|
|
|
81
|
-
Use Python `3.9
|
|
80
|
+
Use Python `3.9+`. Install a compatible PyTorch build first, then install `shared-tensor`.
|
|
82
81
|
|
|
83
82
|
```bash
|
|
83
|
+
pip install torch
|
|
84
84
|
pip install shared-tensor
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -92,6 +92,8 @@ conda activate shared-tensor-dev
|
|
|
92
92
|
pip install -e ".[dev,test]"
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
If you want to share Hugging Face `transformers` models, install both `torch` and `transformers` in the server and client environments. `shared-tensor` no longer installs `torch` for you.
|
|
96
|
+
|
|
95
97
|
## Docs
|
|
96
98
|
|
|
97
99
|
Read the examples first, then the design notes:
|
|
@@ -150,6 +152,34 @@ executes endpoint functions reopens CUDA objects via torch IPC
|
|
|
150
152
|
manages cache and refcounts releases managed handles explicitly
|
|
151
153
|
```
|
|
152
154
|
|
|
155
|
+
## Example: Transformers Models
|
|
156
|
+
|
|
157
|
+
`shared_tensor` also supports CUDA `transformers.PreTrainedModel` instances.
|
|
158
|
+
|
|
159
|
+
See:
|
|
160
|
+
- `examples/transformers_two_proc_demo.py`: minimal same-code two-process demo using `AutoModel`-style loading
|
|
161
|
+
- `examples/transformers_mutation_check.py`: proves client-side in-place parameter mutation is visible on the server
|
|
162
|
+
- `examples/transformers_ipc_benchmark.py`: measures reopen latency and client GPU memory delta
|
|
163
|
+
|
|
164
|
+
Usage:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
TRANSFORMERS_MODEL_ROOT=/path/to/model-or-hf-cache/models--bert-base-uncased \
|
|
168
|
+
SHARED_TENSOR_ENABLED=1 SHARED_TENSOR_ROLE=server \
|
|
169
|
+
python examples/transformers_two_proc_demo.py
|
|
170
|
+
|
|
171
|
+
TRANSFORMERS_MODEL_ROOT=/path/to/model-or-hf-cache/models--bert-base-uncased \
|
|
172
|
+
SHARED_TENSOR_ENABLED=1 \
|
|
173
|
+
python examples/transformers_two_proc_demo.py
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Notes:
|
|
177
|
+
- `TRANSFORMERS_MODEL_ROOT` may point either to a resolved local model directory or to a Hugging Face cache root like `models--...`; the example resolves the newest snapshot automatically
|
|
178
|
+
- `TRANSFORMERS_AUTO_CLASS` defaults to `AutoModel` and can be overridden to another `Auto*` class that exposes `from_pretrained`
|
|
179
|
+
- for custom `transformers` code paths, the library stages the required module source files before reopening the shared module on the client
|
|
180
|
+
- transport remains same-host same-GPU torch CUDA IPC; the client should not allocate a second full model copy just to reconstruct parameters
|
|
181
|
+
- in a fresh client Python process, the first reopen may still look slow because `transformers` import/module resolution is often much slower than the shared-tensor IPC restore path itself; a second reopen in the same process should be much faster
|
|
182
|
+
|
|
153
183
|
## Lifetime And Failure Contract
|
|
154
184
|
|
|
155
185
|
`shared_tensor` follows native PyTorch CUDA IPC semantics. It does not virtualize or harden producer lifetime.
|
|
@@ -346,6 +376,8 @@ Use call-level invalidation when you want to evict one cache key.
|
|
|
346
376
|
Use endpoint-level invalidation when you want to drop all cached variants for the endpoint.
|
|
347
377
|
Invalidation removes cache lookup entries; it does not guarantee that already-issued client handles remain valid after producer death.
|
|
348
378
|
|
|
379
|
+
For cached `transformers` model endpoints, keep `cache=True` unless you explicitly want every request to rebuild and re-share the model.
|
|
380
|
+
|
|
349
381
|
|
|
350
382
|
## Handle Health Checks
|
|
351
383
|
|
|
@@ -371,6 +403,22 @@ info = provider.get_runtime_info()
|
|
|
371
403
|
# execution_mode, server_socket_path, server_running, server_ready, server_info...
|
|
372
404
|
```
|
|
373
405
|
|
|
406
|
+
## Client Retry And Timeout Defaults
|
|
407
|
+
|
|
408
|
+
The client now retries initial connection setup for up to `60s` when the server socket is not ready yet, covering the common server-startup race where the client starts slightly earlier.
|
|
409
|
+
|
|
410
|
+
Default request timeout is now `600s` for:
|
|
411
|
+
- `SharedTensorClient`
|
|
412
|
+
- `AsyncSharedTensorClient`
|
|
413
|
+
- `SharedTensorProvider`
|
|
414
|
+
|
|
415
|
+
You can still override these per instance:
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
client = SharedTensorClient(timeout=120.0)
|
|
419
|
+
provider = SharedTensorProvider(timeout=120.0)
|
|
420
|
+
```
|
|
421
|
+
|
|
374
422
|
## Testing
|
|
375
423
|
|
|
376
424
|
Default suite:
|
|
@@ -25,9 +25,10 @@ Not supported:
|
|
|
25
25
|
|
|
26
26
|
## Install
|
|
27
27
|
|
|
28
|
-
Use Python `3.9
|
|
28
|
+
Use Python `3.9+`. Install a compatible PyTorch build first, then install `shared-tensor`.
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
+
pip install torch
|
|
31
32
|
pip install shared-tensor
|
|
32
33
|
```
|
|
33
34
|
|
|
@@ -39,6 +40,8 @@ conda activate shared-tensor-dev
|
|
|
39
40
|
pip install -e ".[dev,test]"
|
|
40
41
|
```
|
|
41
42
|
|
|
43
|
+
If you want to share Hugging Face `transformers` models, install both `torch` and `transformers` in the server and client environments. `shared-tensor` no longer installs `torch` for you.
|
|
44
|
+
|
|
42
45
|
## Docs
|
|
43
46
|
|
|
44
47
|
Read the examples first, then the design notes:
|
|
@@ -97,6 +100,34 @@ executes endpoint functions reopens CUDA objects via torch IPC
|
|
|
97
100
|
manages cache and refcounts releases managed handles explicitly
|
|
98
101
|
```
|
|
99
102
|
|
|
103
|
+
## Example: Transformers Models
|
|
104
|
+
|
|
105
|
+
`shared_tensor` also supports CUDA `transformers.PreTrainedModel` instances.
|
|
106
|
+
|
|
107
|
+
See:
|
|
108
|
+
- `examples/transformers_two_proc_demo.py`: minimal same-code two-process demo using `AutoModel`-style loading
|
|
109
|
+
- `examples/transformers_mutation_check.py`: proves client-side in-place parameter mutation is visible on the server
|
|
110
|
+
- `examples/transformers_ipc_benchmark.py`: measures reopen latency and client GPU memory delta
|
|
111
|
+
|
|
112
|
+
Usage:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
TRANSFORMERS_MODEL_ROOT=/path/to/model-or-hf-cache/models--bert-base-uncased \
|
|
116
|
+
SHARED_TENSOR_ENABLED=1 SHARED_TENSOR_ROLE=server \
|
|
117
|
+
python examples/transformers_two_proc_demo.py
|
|
118
|
+
|
|
119
|
+
TRANSFORMERS_MODEL_ROOT=/path/to/model-or-hf-cache/models--bert-base-uncased \
|
|
120
|
+
SHARED_TENSOR_ENABLED=1 \
|
|
121
|
+
python examples/transformers_two_proc_demo.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Notes:
|
|
125
|
+
- `TRANSFORMERS_MODEL_ROOT` may point either to a resolved local model directory or to a Hugging Face cache root like `models--...`; the example resolves the newest snapshot automatically
|
|
126
|
+
- `TRANSFORMERS_AUTO_CLASS` defaults to `AutoModel` and can be overridden to another `Auto*` class that exposes `from_pretrained`
|
|
127
|
+
- for custom `transformers` code paths, the library stages the required module source files before reopening the shared module on the client
|
|
128
|
+
- transport remains same-host same-GPU torch CUDA IPC; the client should not allocate a second full model copy just to reconstruct parameters
|
|
129
|
+
- in a fresh client Python process, the first reopen may still look slow because `transformers` import/module resolution is often much slower than the shared-tensor IPC restore path itself; a second reopen in the same process should be much faster
|
|
130
|
+
|
|
100
131
|
## Lifetime And Failure Contract
|
|
101
132
|
|
|
102
133
|
`shared_tensor` follows native PyTorch CUDA IPC semantics. It does not virtualize or harden producer lifetime.
|
|
@@ -293,6 +324,8 @@ Use call-level invalidation when you want to evict one cache key.
|
|
|
293
324
|
Use endpoint-level invalidation when you want to drop all cached variants for the endpoint.
|
|
294
325
|
Invalidation removes cache lookup entries; it does not guarantee that already-issued client handles remain valid after producer death.
|
|
295
326
|
|
|
327
|
+
For cached `transformers` model endpoints, keep `cache=True` unless you explicitly want every request to rebuild and re-share the model.
|
|
328
|
+
|
|
296
329
|
|
|
297
330
|
## Handle Health Checks
|
|
298
331
|
|
|
@@ -318,6 +351,22 @@ info = provider.get_runtime_info()
|
|
|
318
351
|
# execution_mode, server_socket_path, server_running, server_ready, server_info...
|
|
319
352
|
```
|
|
320
353
|
|
|
354
|
+
## Client Retry And Timeout Defaults
|
|
355
|
+
|
|
356
|
+
The client now retries initial connection setup for up to `60s` when the server socket is not ready yet, covering the common server-startup race where the client starts slightly earlier.
|
|
357
|
+
|
|
358
|
+
Default request timeout is now `600s` for:
|
|
359
|
+
- `SharedTensorClient`
|
|
360
|
+
- `AsyncSharedTensorClient`
|
|
361
|
+
- `SharedTensorProvider`
|
|
362
|
+
|
|
363
|
+
You can still override these per instance:
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
client = SharedTensorClient(timeout=120.0)
|
|
367
|
+
provider = SharedTensorProvider(timeout=120.0)
|
|
368
|
+
```
|
|
369
|
+
|
|
321
370
|
## Testing
|
|
322
371
|
|
|
323
372
|
Default suite:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shared-tensor"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.15"
|
|
8
8
|
description = "Native PyTorch CUDA IPC over Unix Domain Socket for same-host process separation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -47,7 +47,6 @@ requires-python = ">=3.9"
|
|
|
47
47
|
dependencies = [
|
|
48
48
|
"cloudpickle>=3.0.0",
|
|
49
49
|
"numpy<2",
|
|
50
|
-
"torch>=2.1",
|
|
51
50
|
]
|
|
52
51
|
|
|
53
52
|
[project.optional-dependencies]
|
|
@@ -34,6 +34,7 @@ except ImportError: # pragma: no cover - exercised when transformers is not ins
|
|
|
34
34
|
|
|
35
35
|
TORCH_MODULE: Any | None = _torch
|
|
36
36
|
TRANSFORMERS_PRETRAINED_MODEL: Any | None = _transformers_pretrained_model
|
|
37
|
+
_TRANSFORMERS_CLASS_CACHE: dict[tuple[str, str], Any] = {}
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
CONTROL_ENCODING = "control_pickle"
|
|
@@ -177,9 +178,20 @@ def _serialize_transformers_model(module: Any) -> bytes:
|
|
|
177
178
|
if config is None:
|
|
178
179
|
raise SharedTensorSerializationError("transformers model is missing a config")
|
|
179
180
|
module_sources = _collect_transformers_module_sources(type(module).__module__, type(config).__module__)
|
|
181
|
+
parameters = dict(module.named_parameters(remove_duplicate=False))
|
|
182
|
+
buffers = dict(module.named_buffers(remove_duplicate=False))
|
|
180
183
|
payload = {
|
|
181
184
|
"module_sources": module_sources,
|
|
182
|
-
"
|
|
185
|
+
"config_bytes": pickle.dumps(config, protocol=pickle.HIGHEST_PROTOCOL),
|
|
186
|
+
"model_module": type(module).__module__,
|
|
187
|
+
"model_qualname": type(module).__qualname__,
|
|
188
|
+
"state_bytes": _torch_serialize(
|
|
189
|
+
{
|
|
190
|
+
"parameters": parameters,
|
|
191
|
+
"buffers": buffers,
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
"training": bool(getattr(module, "training", False)),
|
|
183
195
|
}
|
|
184
196
|
return pickle.dumps(payload, protocol=pickle.HIGHEST_PROTOCOL)
|
|
185
197
|
|
|
@@ -307,17 +319,128 @@ def _import_transformers_module(module_name: str, module_sources: dict[str, dict
|
|
|
307
319
|
return importlib.import_module(module_name)
|
|
308
320
|
|
|
309
321
|
|
|
322
|
+
def _resolve_module_qualname(module_name: str, qualname: str) -> Any:
|
|
323
|
+
cache_key = (module_name, qualname)
|
|
324
|
+
cached = _TRANSFORMERS_CLASS_CACHE.get(cache_key)
|
|
325
|
+
if cached is not None:
|
|
326
|
+
return cached
|
|
327
|
+
module = importlib.import_module(module_name)
|
|
328
|
+
current: Any = module
|
|
329
|
+
for part in qualname.split("."):
|
|
330
|
+
current = getattr(current, part)
|
|
331
|
+
_TRANSFORMERS_CLASS_CACHE[cache_key] = current
|
|
332
|
+
return current
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _build_transformers_meta_shell(model_cls: Any, config: Any) -> Any:
|
|
336
|
+
if TORCH_MODULE is None:
|
|
337
|
+
raise SharedTensorSerializationError("PyTorch is required for transformers deserialization")
|
|
338
|
+
try:
|
|
339
|
+
with TORCH_MODULE.device("meta"):
|
|
340
|
+
model = model_cls(config)
|
|
341
|
+
except Exception as exc:
|
|
342
|
+
raise SharedTensorSerializationError(
|
|
343
|
+
f"Failed to construct transformers model shell on meta device: {exc}"
|
|
344
|
+
) from exc
|
|
345
|
+
return model
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _resolve_parent_module(root: Any, parent_name: str) -> Any:
|
|
349
|
+
if not parent_name:
|
|
350
|
+
return root
|
|
351
|
+
get_submodule = getattr(root, "get_submodule", None)
|
|
352
|
+
if callable(get_submodule):
|
|
353
|
+
return get_submodule(parent_name)
|
|
354
|
+
current = root
|
|
355
|
+
for part in parent_name.split("."):
|
|
356
|
+
current = getattr(current, part)
|
|
357
|
+
return current
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _rebind_named_parameter(module: Any, name: str, value: Any) -> None:
|
|
361
|
+
parent_name, _, local_name = name.rpartition(".")
|
|
362
|
+
parent = _resolve_parent_module(module, parent_name)
|
|
363
|
+
parent._parameters[local_name] = value
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _rebind_named_buffer(module: Any, name: str, value: Any) -> None:
|
|
367
|
+
parent_name, _, local_name = name.rpartition(".")
|
|
368
|
+
parent = _resolve_parent_module(module, parent_name)
|
|
369
|
+
parent._buffers[local_name] = value
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _validate_transformers_state_layout(module: Any, parameters: dict[str, Any], buffers: dict[str, Any]) -> None:
|
|
373
|
+
expected_parameters = dict(module.named_parameters(remove_duplicate=False))
|
|
374
|
+
expected_buffers = dict(module.named_buffers(remove_duplicate=False))
|
|
375
|
+
if set(expected_parameters) != set(parameters):
|
|
376
|
+
raise SharedTensorSerializationError(
|
|
377
|
+
"Transformers parameter layout mismatch between serialized model and client shell"
|
|
378
|
+
)
|
|
379
|
+
if set(expected_buffers) != set(buffers):
|
|
380
|
+
raise SharedTensorSerializationError(
|
|
381
|
+
"Transformers buffer layout mismatch between serialized model and client shell"
|
|
382
|
+
)
|
|
383
|
+
for name, expected in expected_parameters.items():
|
|
384
|
+
actual = parameters[name]
|
|
385
|
+
if not isinstance(actual, TORCH_MODULE.nn.Parameter):
|
|
386
|
+
raise SharedTensorSerializationError(
|
|
387
|
+
f"Transformers parameter '{name}' payload is not a torch.nn.Parameter"
|
|
388
|
+
)
|
|
389
|
+
if actual.shape != expected.shape or actual.dtype != expected.dtype:
|
|
390
|
+
raise SharedTensorSerializationError(
|
|
391
|
+
f"Transformers parameter '{name}' shape or dtype does not match the client shell"
|
|
392
|
+
)
|
|
393
|
+
for name, expected in expected_buffers.items():
|
|
394
|
+
actual = buffers[name]
|
|
395
|
+
if not isinstance(actual, TORCH_MODULE.Tensor):
|
|
396
|
+
raise SharedTensorSerializationError(
|
|
397
|
+
f"Transformers buffer '{name}' payload is not a torch.Tensor"
|
|
398
|
+
)
|
|
399
|
+
if actual.shape != expected.shape or actual.dtype != expected.dtype:
|
|
400
|
+
raise SharedTensorSerializationError(
|
|
401
|
+
f"Transformers buffer '{name}' shape or dtype does not match the client shell"
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def _restore_transformers_state(module: Any, state: dict[str, Any]) -> Any:
|
|
406
|
+
parameters = cast(dict[str, Any], state.get("parameters", {}))
|
|
407
|
+
buffers = cast(dict[str, Any], state.get("buffers", {}))
|
|
408
|
+
_validate_transformers_state_layout(module, parameters, buffers)
|
|
409
|
+
for name, value in parameters.items():
|
|
410
|
+
_rebind_named_parameter(module, name, value)
|
|
411
|
+
for name, value in buffers.items():
|
|
412
|
+
_rebind_named_buffer(module, name, value)
|
|
413
|
+
return module
|
|
414
|
+
|
|
415
|
+
|
|
310
416
|
def _deserialize_transformers_model(payload: bytes) -> Any:
|
|
311
417
|
encoded = pickle.loads(payload)
|
|
312
418
|
module_sources = cast(dict[str, dict[str, str]], encoded.get("module_sources", {}))
|
|
313
419
|
for module_name in module_sources:
|
|
314
420
|
_import_transformers_module(module_name, module_sources)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
421
|
+
config_bytes = encoded.get("config_bytes")
|
|
422
|
+
state_bytes = encoded.get("state_bytes")
|
|
423
|
+
model_module = encoded.get("model_module")
|
|
424
|
+
model_qualname = encoded.get("model_qualname")
|
|
425
|
+
if not isinstance(config_bytes, (bytes, bytearray)):
|
|
426
|
+
raise SharedTensorSerializationError("transformers config payload is invalid")
|
|
427
|
+
if not isinstance(state_bytes, (bytes, bytearray)):
|
|
428
|
+
raise SharedTensorSerializationError("transformers state payload is invalid")
|
|
429
|
+
if not isinstance(model_module, str) or not model_module:
|
|
430
|
+
raise SharedTensorSerializationError("transformers model module is invalid")
|
|
431
|
+
if not isinstance(model_qualname, str) or not model_qualname:
|
|
432
|
+
raise SharedTensorSerializationError("transformers model qualname is invalid")
|
|
433
|
+
config = pickle.loads(config_bytes)
|
|
434
|
+
model_cls = _resolve_module_qualname(model_module, model_qualname)
|
|
435
|
+
model = _build_transformers_meta_shell(model_cls, config)
|
|
436
|
+
state = pickle.loads(state_bytes)
|
|
437
|
+
model = _restore_transformers_state(model, cast(dict[str, Any], state))
|
|
438
|
+
train_fn = getattr(model, "train", None)
|
|
439
|
+
training = bool(encoded.get("training", False))
|
|
440
|
+
if callable(train_fn):
|
|
441
|
+
train_fn(training)
|
|
319
442
|
eval_fn = getattr(model, "eval", None)
|
|
320
|
-
if callable(eval_fn):
|
|
443
|
+
if callable(eval_fn) and not training:
|
|
321
444
|
eval_fn()
|
|
322
445
|
_validate_module_device(model)
|
|
323
446
|
return model
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|