activationscope 0.1.0__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.
- activationscope-0.1.0/MANIFEST.in +5 -0
- activationscope-0.1.0/PKG-INFO +94 -0
- activationscope-0.1.0/README.md +69 -0
- activationscope-0.1.0/activationscope/_C.pyi +46 -0
- activationscope-0.1.0/activationscope/__init__.py +12 -0
- activationscope-0.1.0/activationscope/_naive.py +105 -0
- activationscope-0.1.0/activationscope/policies.py +58 -0
- activationscope-0.1.0/activationscope/tracker.py +348 -0
- activationscope-0.1.0/activationscope/utils.py +202 -0
- activationscope-0.1.0/activationscope.egg-info/PKG-INFO +94 -0
- activationscope-0.1.0/activationscope.egg-info/SOURCES.txt +45 -0
- activationscope-0.1.0/activationscope.egg-info/dependency_links.txt +1 -0
- activationscope-0.1.0/activationscope.egg-info/requires.txt +8 -0
- activationscope-0.1.0/activationscope.egg-info/top_level.txt +1 -0
- activationscope-0.1.0/csrc/accumulator.hpp +65 -0
- activationscope-0.1.0/csrc/bindings.cpp +53 -0
- activationscope-0.1.0/csrc/callback.cpp +162 -0
- activationscope-0.1.0/csrc/callback.hpp +25 -0
- activationscope-0.1.0/csrc/capture_policy.cpp +38 -0
- activationscope-0.1.0/csrc/capture_policy.hpp +38 -0
- activationscope-0.1.0/csrc/datastructures.hpp +55 -0
- activationscope-0.1.0/csrc/hook_register.cpp +115 -0
- activationscope-0.1.0/csrc/hook_register.hpp +31 -0
- activationscope-0.1.0/csrc/reduction.cpp +27 -0
- activationscope-0.1.0/csrc/reduction.hpp +35 -0
- activationscope-0.1.0/csrc/session.cpp +259 -0
- activationscope-0.1.0/csrc/session.hpp +100 -0
- activationscope-0.1.0/csrc/utils.cpp +61 -0
- activationscope-0.1.0/csrc/utils.hpp +30 -0
- activationscope-0.1.0/pyproject.toml +47 -0
- activationscope-0.1.0/setup.cfg +4 -0
- activationscope-0.1.0/setup.py +39 -0
- activationscope-0.1.0/tests/test_capture_policy_edge_cases.py +338 -0
- activationscope-0.1.0/tests/test_e2e_models.py +288 -0
- activationscope-0.1.0/tests/test_integ_capture_policies.py +119 -0
- activationscope-0.1.0/tests/test_integ_lifecycle.py +225 -0
- activationscope-0.1.0/tests/test_integ_reduction_policies.py +124 -0
- activationscope-0.1.0/tests/test_integ_storage_policies.py +75 -0
- activationscope-0.1.0/tests/test_memory_assumptions.py +182 -0
- activationscope-0.1.0/tests/test_memory_leak_detection.py +336 -0
- activationscope-0.1.0/tests/test_model_complexity.py +388 -0
- activationscope-0.1.0/tests/test_parity.py +156 -0
- activationscope-0.1.0/tests/test_pinned_memory.py +286 -0
- activationscope-0.1.0/tests/test_smoke.py +143 -0
- activationscope-0.1.0/tests/test_svd_analysis.py +671 -0
- activationscope-0.1.0/tests/test_unit_layer_selection.py +200 -0
- activationscope-0.1.0/tests/test_unit_policies.py +207 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: activationscope
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: High-performance PyTorch plugin for tracking and analyzing intermediate neural network activations
|
|
5
|
+
Author: Jan Miksa
|
|
6
|
+
Project-URL: Homepage, https://github.com/OneAndZero24/ActivationScope
|
|
7
|
+
Project-URL: Repository, https://github.com/OneAndZero24/ActivationScope
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: C++
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: torch>=2.0.1
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-benchmark; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff; extra == "dev"
|
|
24
|
+
Requires-Dist: build; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# ActivationScope
|
|
27
|
+
|
|
28
|
+
***Jan Miksa @ IDEAS Research Institute***
|
|
29
|
+
|
|
30
|
+
**High-performance PyTorch activation tracker with online reduction functionality for efficient model analysis.**
|
|
31
|
+
|
|
32
|
+
Built on Python + C++ with native `libtorch` hooks and **TorchScript** (`torch.jit.script`) reductions compiled to `.pt` files.
|
|
33
|
+
|
|
34
|
+
**Key Benefits**
|
|
35
|
+
- Zero‑copy read‑back: activation tensors are shared between C++ and Python without extra copies.
|
|
36
|
+
- Native C++ hooks: no Python compute overhead per forward pass.
|
|
37
|
+
- Flexible policy knobs (`StoragePolicy`, `ReductionPolicy`, `CapturePolicy`, `CaptureMode`) let you balance memory, compute, and I/O.
|
|
38
|
+
- Direct-to-disk streaming (`StoragePolicy.DISK`) — activations are written directly from C++ to disk. Ideal for long-running training loops with very large models. Activations are read back on demand from `.dat` files.
|
|
39
|
+
- Works with large models (e.g., diffusion) and supports streaming statistics for online use cases.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
Every tracked layer stores full activations by default — no registration needed:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import activationscope
|
|
49
|
+
|
|
50
|
+
with activationscope.ActivationScope().track(model) as tracker:
|
|
51
|
+
for x, y in dataloader:
|
|
52
|
+
out = model(x)
|
|
53
|
+
loss.backward()
|
|
54
|
+
|
|
55
|
+
acts = tracker.activations # {layer_name: [Tensor, ...]} across all batches
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Performance
|
|
59
|
+
|
|
60
|
+
### Toy model — 48 × Linear(256,256), batch=32, 200 forwards, CPU
|
|
61
|
+
|
|
62
|
+
| Approach | ms/forward | Overhead vs baseline | Data captured |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| No tracking | 2.05 | — | — |
|
|
65
|
+
| Naive Python hooks | 3.13 | +52.7% | 594 MiB |
|
|
66
|
+
| **ActivationScope** | **2.65** | **+29.2%** | **594 MiB** |
|
|
67
|
+
|
|
68
|
+
- **Peak VMS identical** — Scope 402,506 vs Naive 402,630 MiB (~0.03% diff, within ASLR noise)
|
|
69
|
+
- **1.18× faster** than naive Python hooks (3.13 → 2.65 ms/fwd)
|
|
70
|
+
- **95 layers tracked** (inputs + outputs across 48 linear layers)
|
|
71
|
+
- **Zero-copy readback**: 594 MiB in 2.4 ms
|
|
72
|
+
|
|
73
|
+
Run it yourself:
|
|
74
|
+
```bash
|
|
75
|
+
# Toy model (fast, GPU or CPU)
|
|
76
|
+
PYTHONPATH=. python -m benchmark.runner
|
|
77
|
+
|
|
78
|
+
# Pretrained ResNet-18 (requires torchvision)
|
|
79
|
+
PYTHONPATH=. python -m benchmark.runner --model resnet18
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Usage Guide
|
|
85
|
+
|
|
86
|
+
For detailed usage instructions, see the [Usage Documentation](docs/usage/README.md).
|
|
87
|
+
|
|
88
|
+
## Development Guide
|
|
89
|
+
|
|
90
|
+
Documentation and developer setup information is available in [Development Documentation](docs/development/README.md).
|
|
91
|
+
|
|
92
|
+
## Design Documentation
|
|
93
|
+
|
|
94
|
+
The design document outlining the architecture and implementation details can be found in [Design Documentation](docs/DESIGN.md).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# ActivationScope
|
|
2
|
+
|
|
3
|
+
***Jan Miksa @ IDEAS Research Institute***
|
|
4
|
+
|
|
5
|
+
**High-performance PyTorch activation tracker with online reduction functionality for efficient model analysis.**
|
|
6
|
+
|
|
7
|
+
Built on Python + C++ with native `libtorch` hooks and **TorchScript** (`torch.jit.script`) reductions compiled to `.pt` files.
|
|
8
|
+
|
|
9
|
+
**Key Benefits**
|
|
10
|
+
- Zero‑copy read‑back: activation tensors are shared between C++ and Python without extra copies.
|
|
11
|
+
- Native C++ hooks: no Python compute overhead per forward pass.
|
|
12
|
+
- Flexible policy knobs (`StoragePolicy`, `ReductionPolicy`, `CapturePolicy`, `CaptureMode`) let you balance memory, compute, and I/O.
|
|
13
|
+
- Direct-to-disk streaming (`StoragePolicy.DISK`) — activations are written directly from C++ to disk. Ideal for long-running training loops with very large models. Activations are read back on demand from `.dat` files.
|
|
14
|
+
- Works with large models (e.g., diffusion) and supports streaming statistics for online use cases.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
Every tracked layer stores full activations by default — no registration needed:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import activationscope
|
|
24
|
+
|
|
25
|
+
with activationscope.ActivationScope().track(model) as tracker:
|
|
26
|
+
for x, y in dataloader:
|
|
27
|
+
out = model(x)
|
|
28
|
+
loss.backward()
|
|
29
|
+
|
|
30
|
+
acts = tracker.activations # {layer_name: [Tensor, ...]} across all batches
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Performance
|
|
34
|
+
|
|
35
|
+
### Toy model — 48 × Linear(256,256), batch=32, 200 forwards, CPU
|
|
36
|
+
|
|
37
|
+
| Approach | ms/forward | Overhead vs baseline | Data captured |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| No tracking | 2.05 | — | — |
|
|
40
|
+
| Naive Python hooks | 3.13 | +52.7% | 594 MiB |
|
|
41
|
+
| **ActivationScope** | **2.65** | **+29.2%** | **594 MiB** |
|
|
42
|
+
|
|
43
|
+
- **Peak VMS identical** — Scope 402,506 vs Naive 402,630 MiB (~0.03% diff, within ASLR noise)
|
|
44
|
+
- **1.18× faster** than naive Python hooks (3.13 → 2.65 ms/fwd)
|
|
45
|
+
- **95 layers tracked** (inputs + outputs across 48 linear layers)
|
|
46
|
+
- **Zero-copy readback**: 594 MiB in 2.4 ms
|
|
47
|
+
|
|
48
|
+
Run it yourself:
|
|
49
|
+
```bash
|
|
50
|
+
# Toy model (fast, GPU or CPU)
|
|
51
|
+
PYTHONPATH=. python -m benchmark.runner
|
|
52
|
+
|
|
53
|
+
# Pretrained ResNet-18 (requires torchvision)
|
|
54
|
+
PYTHONPATH=. python -m benchmark.runner --model resnet18
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Usage Guide
|
|
60
|
+
|
|
61
|
+
For detailed usage instructions, see the [Usage Documentation](docs/usage/README.md).
|
|
62
|
+
|
|
63
|
+
## Development Guide
|
|
64
|
+
|
|
65
|
+
Documentation and developer setup information is available in [Development Documentation](docs/development/README.md).
|
|
66
|
+
|
|
67
|
+
## Design Documentation
|
|
68
|
+
|
|
69
|
+
The design document outlining the architecture and implementation details can be found in [Design Documentation](docs/DESIGN.md).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Type stubs for the compiled C++ extension ``activationscope._C``.
|
|
2
|
+
|
|
3
|
+
TorchScript reduction path — reductions are compiled via torch.jit.script,
|
|
4
|
+
serialised to .pt files, and loaded by the C++ backend.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List
|
|
8
|
+
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
# ── Session lifecycle ──────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
def session_create(
|
|
14
|
+
storage: int,
|
|
15
|
+
reduction: int,
|
|
16
|
+
sample_every: int,
|
|
17
|
+
max_batches: int,
|
|
18
|
+
auto_cpu_threshold_bytes: int,
|
|
19
|
+
use_pinned: bool,
|
|
20
|
+
session_dir: str = "",
|
|
21
|
+
capture_mode: int = 0,
|
|
22
|
+
) -> int: ...
|
|
23
|
+
|
|
24
|
+
def session_destroy(id: int) -> None: ...
|
|
25
|
+
|
|
26
|
+
def session_readback(
|
|
27
|
+
id: int,
|
|
28
|
+
) -> Dict[str, List[torch.Tensor]]: ...
|
|
29
|
+
|
|
30
|
+
def session_readback_disk(
|
|
31
|
+
id: int,
|
|
32
|
+
) -> Dict[str, List[str]]: ...
|
|
33
|
+
|
|
34
|
+
def session_clear(id: int) -> None: ...
|
|
35
|
+
|
|
36
|
+
def session_detach_hooks(id: int) -> None: ...
|
|
37
|
+
|
|
38
|
+
# ── Hook registration ──────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
def session_register_hooks(
|
|
41
|
+
id: int,
|
|
42
|
+
module_ptr: Any,
|
|
43
|
+
layer_key: str,
|
|
44
|
+
capture_dir_int: int,
|
|
45
|
+
reduction_path: str = "",
|
|
46
|
+
) -> None: ...
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Public API for ActivationScope — session-scoped, zero-copy, native hooks."""
|
|
2
|
+
|
|
3
|
+
from activationscope.policies import StoragePolicy, ReductionPolicy, CapturePolicy, CaptureMode
|
|
4
|
+
from activationscope.tracker import ActivationScope
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ActivationScope",
|
|
8
|
+
"StoragePolicy",
|
|
9
|
+
"ReductionPolicy",
|
|
10
|
+
"CapturePolicy",
|
|
11
|
+
"CaptureMode",
|
|
12
|
+
]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Shared naive PyTorch forward-hook tracker for benchmarking and testing.
|
|
2
|
+
|
|
3
|
+
Provides a simple reference implementation of activation accumulation using
|
|
4
|
+
Python ``register_forward_hook``. Used by the benchmark runner to compare
|
|
5
|
+
memory/throughput against ActivationScope's C++ hooks, and by parity tests
|
|
6
|
+
to verify equivalent behavior.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import contextlib
|
|
10
|
+
from fnmatch import fnmatch
|
|
11
|
+
|
|
12
|
+
import torch
|
|
13
|
+
|
|
14
|
+
from activationscope.policies import CaptureMode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class NaiveHookTracker:
|
|
18
|
+
"""Accumulate per-layer activations via Python forward hooks.
|
|
19
|
+
|
|
20
|
+
Mirrors the behavior of ``ActivationScope`` with ``STORE_ALL`` reduction
|
|
21
|
+
and ``EVERY`` capture policy, but uses pure-Python hooks. Not intended
|
|
22
|
+
for production use — exists solely as a reference for benchmarking and
|
|
23
|
+
correctness testing.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
capture_mode : CaptureMode
|
|
28
|
+
Controls copy behaviour of captured tensors:
|
|
29
|
+
* ``CaptureMode.REFERENCE`` (default) — ``.detach().cpu()``.
|
|
30
|
+
Tensors share storage with the autograd graph and may be
|
|
31
|
+
invalidated on subsequent forward passes.
|
|
32
|
+
* ``CaptureMode.SNAPSHOT`` — ``.detach().cpu().clone()``.
|
|
33
|
+
Completely independent copies, safe to keep across forwards.
|
|
34
|
+
|
|
35
|
+
Usage::
|
|
36
|
+
|
|
37
|
+
n = NaiveHookTracker(capture_mode=CaptureMode.SNAPSHOT)
|
|
38
|
+
with n.track(model):
|
|
39
|
+
for _ in range(n_batches):
|
|
40
|
+
_ = model(x)
|
|
41
|
+
acts = n.activations # dict[str, list[Tensor]]
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, capture_mode: CaptureMode = CaptureMode.REFERENCE):
|
|
45
|
+
self._handles: list = []
|
|
46
|
+
self._activations: dict[str, list[torch.Tensor]] = {}
|
|
47
|
+
self._capture_mode = capture_mode
|
|
48
|
+
|
|
49
|
+
def track(self, model, layers=None):
|
|
50
|
+
"""Context manager: attach → yield self → detach."""
|
|
51
|
+
|
|
52
|
+
@contextlib.contextmanager
|
|
53
|
+
def _ctx():
|
|
54
|
+
self._attach(model, layers=layers)
|
|
55
|
+
yield self
|
|
56
|
+
self._detach()
|
|
57
|
+
|
|
58
|
+
return _ctx()
|
|
59
|
+
|
|
60
|
+
def _attach(self, model, layers=None):
|
|
61
|
+
containers = (torch.nn.ModuleList, torch.nn.ModuleDict, torch.nn.Sequential)
|
|
62
|
+
all_modules = {
|
|
63
|
+
n: m
|
|
64
|
+
for n, m in model.named_modules()
|
|
65
|
+
if n != "" and not isinstance(m, containers)
|
|
66
|
+
}
|
|
67
|
+
targets = (
|
|
68
|
+
all_modules
|
|
69
|
+
if layers is None
|
|
70
|
+
else {
|
|
71
|
+
n: m
|
|
72
|
+
for n, m in all_modules.items()
|
|
73
|
+
if any(fnmatch(n, p) for p in layers)
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
self._activations = {name: [] for name in targets}
|
|
77
|
+
for name in targets:
|
|
78
|
+
handle = targets[name].register_forward_hook(self._make_hook(name))
|
|
79
|
+
self._handles.append(handle)
|
|
80
|
+
|
|
81
|
+
def _make_hook(self, layer_name):
|
|
82
|
+
capture_mode = self._capture_mode
|
|
83
|
+
|
|
84
|
+
def hook_fn(_module, _inp, out):
|
|
85
|
+
if isinstance(out, torch.Tensor):
|
|
86
|
+
t = out.detach().cpu()
|
|
87
|
+
self._activations[layer_name].append(
|
|
88
|
+
t.clone() if capture_mode == CaptureMode.SNAPSHOT else t
|
|
89
|
+
)
|
|
90
|
+
elif isinstance(out, (tuple, list)) and len(out) > 0:
|
|
91
|
+
t = out[0].detach().cpu()
|
|
92
|
+
self._activations[layer_name].append(
|
|
93
|
+
t.clone() if capture_mode == CaptureMode.SNAPSHOT else t
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return hook_fn
|
|
97
|
+
|
|
98
|
+
def _detach(self):
|
|
99
|
+
for h in self._handles:
|
|
100
|
+
h.remove()
|
|
101
|
+
self._handles = []
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def activations(self):
|
|
105
|
+
return self._activations
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""ActivationScope policy enumerations.
|
|
2
|
+
|
|
3
|
+
Three independently tunable policy knobs that govern every aspect of memory
|
|
4
|
+
and compute behaviour. Integer-valued to pass trivially to the C++ backend.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _PolicyMeta(type):
|
|
9
|
+
"""Metaclass that makes policy classes iterable and subscriptable."""
|
|
10
|
+
|
|
11
|
+
def __iter__(cls):
|
|
12
|
+
return iter(cls._members_)
|
|
13
|
+
|
|
14
|
+
def __class_getitem__(cls, item):
|
|
15
|
+
return cls._members_[item]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StoragePolicy(int, metaclass=_PolicyMeta):
|
|
19
|
+
"""Where tensor data lives after capture."""
|
|
20
|
+
|
|
21
|
+
AUTO = 0 # Heuristic: < threshold → CPU, >= threshold → GPU
|
|
22
|
+
CPU = 1 # Transfer to host memory
|
|
23
|
+
GPU = 2 # Stay on original device
|
|
24
|
+
DISK = 3 # Stream directly to disk; bypass in-memory accumulation
|
|
25
|
+
|
|
26
|
+
_members_ = (AUTO, CPU, GPU, DISK)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ReductionPolicy(int):
|
|
30
|
+
"""What gets kept vs. reduced across batches."""
|
|
31
|
+
|
|
32
|
+
STORE_ALL = 0 # Full tensor per batch appended
|
|
33
|
+
STREAMING = 1 # Per-batch reduction output replaces/accumulates in-place
|
|
34
|
+
FINAL_ONLY = 2 # Last-batch activation overwrites previous
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CapturePolicy(int, metaclass=_PolicyMeta):
|
|
38
|
+
"""When and how often hooks fire."""
|
|
39
|
+
|
|
40
|
+
EVERY = 0 # Every forward fires hooks
|
|
41
|
+
SAMPLE_N = 1 # Captures every Nth forward
|
|
42
|
+
MAX_K = 2 # Captures exactly K batches then stops
|
|
43
|
+
|
|
44
|
+
_members_ = (EVERY, SAMPLE_N, MAX_K)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CaptureMode(int, metaclass=_PolicyMeta):
|
|
48
|
+
"""Whether to clone captured tensors for independent storage.
|
|
49
|
+
|
|
50
|
+
Controls the copy behaviour of both the native C++ tracker
|
|
51
|
+
(``activationscope.tracker.ActivationScope``) and the pure‑Python
|
|
52
|
+
fallback (``activationscope._naive.NaiveHookTracker``).
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
REFERENCE = 0 # detach() only — shares storage with autograd graph
|
|
56
|
+
SNAPSHOT = 1 # detach() + clone() — completely independent copy
|
|
57
|
+
|
|
58
|
+
_members_ = (REFERENCE, SNAPSHOT)
|