USN 0.1.0__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.
Files changed (76) hide show
  1. usn/__init__.py +145 -0
  2. usn/__init__.pyi +39 -0
  3. usn/backends/__init__.py +25 -0
  4. usn/backends/acceleration.py +236 -0
  5. usn/backends/detection.py +92 -0
  6. usn/backends/fallbacks.py +102 -0
  7. usn/backends/triton_kernels.py +421 -0
  8. usn/cli/__init__.py +5 -0
  9. usn/cli/main.py +212 -0
  10. usn/config/__init__.py +11 -0
  11. usn/config/generation_config.py +53 -0
  12. usn/config/model_config.py +296 -0
  13. usn/config/training_config.py +106 -0
  14. usn/core/__init__.py +31 -0
  15. usn/core/activations.py +94 -0
  16. usn/core/base.py +52 -0
  17. usn/core/interfaces.py +94 -0
  18. usn/core/types.py +83 -0
  19. usn/datasets/__init__.py +7 -0
  20. usn/datasets/collate.py +48 -0
  21. usn/datasets/math_dataset.py +102 -0
  22. usn/datasets/usn_dataset.py +145 -0
  23. usn/exceptions.py +131 -0
  24. usn/inference/__init__.py +5 -0
  25. usn/inference/generator.py +587 -0
  26. usn/layers/__init__.py +28 -0
  27. usn/layers/block.py +224 -0
  28. usn/layers/chunked_scan.py +133 -0
  29. usn/layers/norm.py +98 -0
  30. usn/layers/parallel_scan.py +147 -0
  31. usn/losses/__init__.py +5 -0
  32. usn/losses/cross_entropy.py +72 -0
  33. usn/models/__init__.py +87 -0
  34. usn/models/embedding.py +124 -0
  35. usn/models/usn_model.py +253 -0
  36. usn/modules/__init__.py +31 -0
  37. usn/modules/channel_mixing.py +84 -0
  38. usn/modules/exponential_gating.py +111 -0
  39. usn/modules/input_projection.py +66 -0
  40. usn/modules/selective_writing.py +146 -0
  41. usn/modules/state_readout.py +107 -0
  42. usn/modules/state_update.py +211 -0
  43. usn/modules/temporal_mixing.py +100 -0
  44. usn/optim/__init__.py +21 -0
  45. usn/optim/factory.py +154 -0
  46. usn/optim/schedulers.py +254 -0
  47. usn/py.typed +0 -0
  48. usn/serialization/__init__.py +33 -0
  49. usn/serialization/export.py +126 -0
  50. usn/serialization/format_spec.py +129 -0
  51. usn/serialization/migration.py +145 -0
  52. usn/serialization/reader.py +461 -0
  53. usn/serialization/validator.py +187 -0
  54. usn/serialization/writer.py +405 -0
  55. usn/tokenizers/__init__.py +14 -0
  56. usn/tokenizers/bpe_tokenizer.py +241 -0
  57. usn/tokenizers/char_tokenizer.py +150 -0
  58. usn/tokenizers/word_tokenizer.py +158 -0
  59. usn/training/__init__.py +7 -0
  60. usn/training/curriculum.py +91 -0
  61. usn/training/distributed.py +99 -0
  62. usn/training/stability.py +113 -0
  63. usn/training/trainer.py +566 -0
  64. usn/utils/__init__.py +52 -0
  65. usn/utils/counting.py +206 -0
  66. usn/utils/diagnostics.py +373 -0
  67. usn/utils/profiling.py +249 -0
  68. usn/utils/seed.py +60 -0
  69. usn/utils/timing.py +144 -0
  70. usn/utils/visualization.py +207 -0
  71. usn-0.1.0.dist-info/METADATA +96 -0
  72. usn-0.1.0.dist-info/RECORD +76 -0
  73. usn-0.1.0.dist-info/WHEEL +5 -0
  74. usn-0.1.0.dist-info/entry_points.txt +2 -0
  75. usn-0.1.0.dist-info/licenses/LICENSE +21 -0
  76. usn-0.1.0.dist-info/top_level.txt +1 -0
usn/__init__.py ADDED
@@ -0,0 +1,145 @@
1
+ """USN - Unified State Network Architecture Library.
2
+
3
+ A production-grade Python package implementing the Unified State Network (USN)
4
+ architecture for autoregressive sequence modeling with O(n) training complexity
5
+ via associative parallel scan and O(1) inference memory via constant-size state.
6
+
7
+ Quick Start:
8
+ >>> import usn
9
+ >>> model = usn.create_model("tiny")
10
+ >>> print(model.summary())
11
+
12
+ Author: BUEORM
13
+ License: MIT
14
+ """
15
+
16
+ __version__ = "0.1.0"
17
+ __author__ = "BUEORM"
18
+
19
+ # Core classes
20
+ # Backends
21
+ from usn.backends import AccelerationLevel, AccelerationManager, DeviceDetector
22
+ from usn.config import USNConfig, USNGenerationConfig, USNTrainingConfig
23
+ from usn.inference import USNGenerator
24
+ from usn.models import create_model
25
+ from usn.models.usn_model import USNModel
26
+ from usn.serialization.export import export_model
27
+ from usn.serialization.reader import USNReader
28
+
29
+ # Serialization
30
+ from usn.serialization.writer import USNWriter
31
+ from usn.training import USNTrainer
32
+ from usn.utils.counting import count_parameters, estimate_flops, estimate_memory
33
+
34
+ # Utilities
35
+ from usn.utils.seed import set_seed
36
+
37
+
38
+ # High-level API functions
39
+ def save(model, path: str, **kwargs) -> None:
40
+ """Save a model to .usn format."""
41
+ writer = USNWriter()
42
+ config = getattr(model, "config", None)
43
+ writer.save(path, model, config=config, **kwargs)
44
+
45
+
46
+ def load(path: str, map_location=None):
47
+ """Load a model from .usn format."""
48
+ reader = USNReader()
49
+ data = reader.load(path, map_location=map_location)
50
+ config = data.get("config")
51
+ if config is None:
52
+ raise ValueError("No config found in .usn file")
53
+ model = USNModel(config)
54
+ weights = data.get("weights", {})
55
+ if weights:
56
+ # Filter buffer keys for state_dict loading
57
+ state_dict = {k: v for k, v in weights.items() if not k.startswith("__buffer__.")}
58
+ model.load_state_dict(state_dict, strict=False)
59
+ return model
60
+
61
+
62
+ def export(model, format: str, path: str, **kwargs) -> None:
63
+ """Export model to standard format (onnx, safetensors, state_dict, torchscript)."""
64
+ config = getattr(model, "config", None)
65
+ export_model(model, format, path, config=config, **kwargs)
66
+
67
+
68
+ def generate(model, prompt: str, max_tokens: int = 256, tokenizer=None, **kwargs) -> str:
69
+ """Generate text from a model (convenience function)."""
70
+ if tokenizer is None:
71
+ raise ValueError("tokenizer is required for generate()")
72
+ gen = USNGenerator(model, tokenizer)
73
+ output = gen.generate(prompt, max_new_tokens=max_tokens, **kwargs)
74
+ return tokenizer.decode(output.token_ids[0].tolist())
75
+
76
+
77
+ def train(model, dataset, config=None, **kwargs):
78
+ """Train a model (convenience function)."""
79
+ if config is None:
80
+ config = USNTrainingConfig()
81
+ trainer = USNTrainer(model, dataset, config, **kwargs)
82
+ return trainer.train()
83
+
84
+
85
+ def summary(model) -> str:
86
+ """Get model summary string."""
87
+ if hasattr(model, "summary"):
88
+ return model.summary()
89
+ return f"Model with {count_parameters(model):,} parameters"
90
+
91
+
92
+ def from_pretrained(path_or_id: str):
93
+ """Load a pretrained model from path."""
94
+ return load(path_or_id)
95
+
96
+
97
+ def device_info() -> dict:
98
+ """Get available device information."""
99
+ return DeviceDetector.detect()
100
+
101
+
102
+ def set_acceleration_level(level: int) -> None:
103
+ """Set the acceleration level manually."""
104
+ AccelerationManager.set_level(level)
105
+
106
+
107
+ def benchmark_acceleration() -> dict:
108
+ """Compare throughput across acceleration levels."""
109
+ return {"current_level": AccelerationManager.get_level().name}
110
+
111
+
112
+ __all__ = [
113
+ # Version
114
+ "__version__",
115
+ "__author__",
116
+ # Core classes
117
+ "USNModel",
118
+ "USNConfig",
119
+ "USNTrainingConfig",
120
+ "USNGenerationConfig",
121
+ "USNTrainer",
122
+ "USNGenerator",
123
+ # Factory
124
+ "create_model",
125
+ # High-level API
126
+ "save",
127
+ "load",
128
+ "export",
129
+ "generate",
130
+ "train",
131
+ "summary",
132
+ "from_pretrained",
133
+ # Utilities
134
+ "set_seed",
135
+ "count_parameters",
136
+ "estimate_memory",
137
+ "estimate_flops",
138
+ "device_info",
139
+ "set_acceleration_level",
140
+ "benchmark_acceleration",
141
+ # Backend
142
+ "AccelerationLevel",
143
+ "AccelerationManager",
144
+ "DeviceDetector",
145
+ ]
usn/__init__.pyi ADDED
@@ -0,0 +1,39 @@
1
+ """Type stubs for the USN public API."""
2
+
3
+ from typing import Any
4
+
5
+ import torch.nn as nn
6
+ from torch import Tensor
7
+
8
+ from usn.backends.acceleration import AccelerationLevel as AccelerationLevel
9
+ from usn.backends.acceleration import AccelerationManager as AccelerationManager
10
+ from usn.backends.detection import DeviceDetector as DeviceDetector
11
+ from usn.config.generation_config import USNGenerationConfig as USNGenerationConfig
12
+ from usn.config.model_config import USNConfig as USNConfig
13
+ from usn.config.training_config import USNTrainingConfig as USNTrainingConfig
14
+ from usn.inference.generator import USNGenerator as USNGenerator
15
+ from usn.models import create_model as create_model
16
+ from usn.models.usn_model import USNModel as USNModel
17
+ from usn.training.trainer import USNTrainer as USNTrainer
18
+ from usn.utils.counting import count_parameters as count_parameters
19
+ from usn.utils.counting import estimate_flops as estimate_flops
20
+ from usn.utils.counting import estimate_memory as estimate_memory
21
+ from usn.utils.seed import set_seed as set_seed
22
+
23
+ __version__: str
24
+ __author__: str
25
+
26
+ def save(model: nn.Module, path: str, **kwargs: Any) -> None: ...
27
+ def load(path: str, map_location: str | None = None) -> USNModel: ...
28
+ def export(model: nn.Module, format: str, path: str, **kwargs: Any) -> None: ...
29
+ def generate(
30
+ model: nn.Module, prompt: str, max_tokens: int = 256, tokenizer: Any = None, **kwargs: Any
31
+ ) -> str: ...
32
+ def train(
33
+ model: nn.Module, dataset: Any, config: USNTrainingConfig | None = None, **kwargs: Any
34
+ ) -> dict[str, Any]: ...
35
+ def summary(model: nn.Module) -> str: ...
36
+ def from_pretrained(path_or_id: str) -> USNModel: ...
37
+ def device_info() -> dict[str, Any]: ...
38
+ def set_acceleration_level(level: int) -> None: ...
39
+ def benchmark_acceleration() -> dict[str, Any]: ...
@@ -0,0 +1,25 @@
1
+ """Backend acceleration: device detection, Triton kernels, and fallbacks.
2
+
3
+ Public API:
4
+ - DeviceDetector: Hardware auto-detection (detect(), best_device())
5
+ - AccelerationLevel: Enum of 4 acceleration tiers
6
+ - AccelerationManager: Manages acceleration level with graceful fallback
7
+
8
+ Importing this package triggers kernel registration at all acceleration levels:
9
+ - triton_kernels: Registers Level 1 (TRITON), Level 3 (AUTOGRAD), Level 4 (EAGER)
10
+ - fallbacks: Registers Level 2 (COMPILE) via torch.compile wrappers
11
+ """
12
+
13
+ # Import fallbacks to register Level 2 (COMPILE) kernels
14
+ import usn.backends.fallbacks as _fallbacks # noqa: F401
15
+
16
+ # Import triton_kernels to register Level 1, 3, 4 kernels
17
+ import usn.backends.triton_kernels as _triton_kernels # noqa: F401
18
+ from usn.backends.acceleration import AccelerationLevel, AccelerationManager
19
+ from usn.backends.detection import DeviceDetector
20
+
21
+ __all__ = [
22
+ "AccelerationLevel",
23
+ "AccelerationManager",
24
+ "DeviceDetector",
25
+ ]
@@ -0,0 +1,236 @@
1
+ """Acceleration level management for the USN library.
2
+
3
+ Implements a 4-level acceleration hierarchy with automatic detection and
4
+ graceful fallback. The levels are:
5
+
6
+ 1. TRITON — Custom Triton fused kernels (fastest, requires triton + CUDA)
7
+ 2. COMPILE — torch.compile with inductor backend (requires PyTorch 2.0+ CUDA)
8
+ 3. AUTOGRAD — Custom autograd functions (requires CUDA)
9
+ 4. EAGER — Standard PyTorch eager mode (always available, baseline)
10
+
11
+ The system auto-detects the best level at import time and NEVER fails due to
12
+ unavailable acceleration — it always falls back to EAGER as the last resort.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from collections.abc import Callable
19
+ from enum import IntEnum
20
+
21
+ import torch
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class AccelerationLevel(IntEnum):
27
+ """4-level acceleration hierarchy for USN kernels.
28
+
29
+ Lower numeric value = faster / more specialized.
30
+ Higher numeric value = more compatible / always available.
31
+ """
32
+
33
+ TRITON = 1
34
+ """Custom Triton fused kernels — maximum performance."""
35
+
36
+ COMPILE = 2
37
+ """torch.compile with inductor — good performance, no Triton needed."""
38
+
39
+ AUTOGRAD = 3
40
+ """Custom autograd functions — CUDA required, no JIT compilation."""
41
+
42
+ EAGER = 4
43
+ """Standard PyTorch eager mode — always available, baseline performance."""
44
+
45
+
46
+ def _detect_best_level() -> AccelerationLevel:
47
+ """Detect the best available acceleration level.
48
+
49
+ Decision tree:
50
+ 1. Is Triton installed AND CUDA available? → TRITON
51
+ 2. Is torch.compile available (PyTorch ≥ 2.0) AND CUDA available? → COMPILE
52
+ 3. Is CUDA available? → AUTOGRAD
53
+ 4. Otherwise → EAGER
54
+
55
+ This function NEVER raises — it always returns a valid level.
56
+ """
57
+ # Check Level 1: Triton
58
+ if torch.cuda.is_available():
59
+ try:
60
+ import triton # noqa: F401
61
+ import triton.language # noqa: F401
62
+
63
+ return AccelerationLevel.TRITON
64
+ except (ImportError, RuntimeError, OSError):
65
+ pass
66
+
67
+ # Check Level 2: torch.compile with inductor
68
+ if torch.cuda.is_available() and hasattr(torch, "compile"):
69
+ try:
70
+
71
+ @torch.compile(backend="inductor")
72
+ def _test_fn(x: torch.Tensor) -> torch.Tensor:
73
+ return x + 1
74
+
75
+ _test_fn(torch.zeros(1, device="cuda"))
76
+ return AccelerationLevel.COMPILE
77
+ except Exception:
78
+ pass
79
+
80
+ # Check Level 3: Custom autograd (CUDA available but no compile)
81
+ if torch.cuda.is_available():
82
+ return AccelerationLevel.AUTOGRAD
83
+
84
+ # Level 4: Eager (CPU or unsupported hardware)
85
+ return AccelerationLevel.EAGER
86
+
87
+
88
+ class AccelerationManager:
89
+ """Manages the 4-level acceleration hierarchy with graceful fallback.
90
+
91
+ This is a class-level (singleton-style) manager. All methods are classmethods
92
+ that operate on shared state. The acceleration level is auto-detected at
93
+ import time but can be overridden manually.
94
+
95
+ Usage:
96
+ # Auto-detected at import
97
+ level = AccelerationManager.get_level()
98
+
99
+ # Manual override
100
+ AccelerationManager.set_level(AccelerationLevel.EAGER)
101
+
102
+ # Get kernel for current level
103
+ kernel = AccelerationManager.get_kernel("projections")
104
+ """
105
+
106
+ _current_level: AccelerationLevel = AccelerationLevel.EAGER
107
+ _detected_level: AccelerationLevel = AccelerationLevel.EAGER
108
+ _initialized: bool = False
109
+ _kernel_registry: dict[str, dict[AccelerationLevel, Callable]] = {}
110
+
111
+ @classmethod
112
+ def _ensure_initialized(cls) -> None:
113
+ """Lazily initialize by detecting the best level."""
114
+ if not cls._initialized:
115
+ cls._detected_level = _detect_best_level()
116
+ cls._current_level = cls._detected_level
117
+ cls._initialized = True
118
+ logger.info(
119
+ "USN acceleration level auto-detected: %s",
120
+ cls._current_level.name,
121
+ )
122
+
123
+ @classmethod
124
+ def detect_best_level(cls) -> AccelerationLevel:
125
+ """Detect and return the best available acceleration level.
126
+
127
+ This re-runs detection (useful if hardware state has changed).
128
+
129
+ Returns:
130
+ The best AccelerationLevel available on this system.
131
+ """
132
+ cls._detected_level = _detect_best_level()
133
+ cls._current_level = cls._detected_level
134
+ cls._initialized = True
135
+ return cls._detected_level
136
+
137
+ @classmethod
138
+ def set_level(cls, level: int | AccelerationLevel) -> None:
139
+ """Manually set the acceleration level.
140
+
141
+ Use this to override auto-detection, e.g., for debugging or
142
+ benchmarking different backends.
143
+
144
+ Args:
145
+ level: The desired acceleration level (int 1-4 or AccelerationLevel).
146
+
147
+ Raises:
148
+ ValueError: If level is not a valid AccelerationLevel value.
149
+ """
150
+ cls._ensure_initialized()
151
+ try:
152
+ cls._current_level = AccelerationLevel(level)
153
+ except ValueError:
154
+ valid = [f"{l.name}={l.value}" for l in AccelerationLevel]
155
+ raise ValueError(
156
+ f"Invalid acceleration level: {level!r}. Valid levels: {', '.join(valid)}"
157
+ ) from None
158
+ logger.info("USN acceleration level set to: %s", cls._current_level.name)
159
+
160
+ @classmethod
161
+ def get_level(cls) -> AccelerationLevel:
162
+ """Get the current acceleration level.
163
+
164
+ Returns:
165
+ The currently active AccelerationLevel.
166
+ """
167
+ cls._ensure_initialized()
168
+ return cls._current_level
169
+
170
+ @classmethod
171
+ def get_kernel(cls, kernel_name: str) -> Callable:
172
+ """Get the appropriate kernel implementation for the current level.
173
+
174
+ Looks up the kernel in the registry for the current acceleration level.
175
+ If the kernel is not available at the current level, falls back to the
176
+ next available level (higher number = more compatible).
177
+
178
+ Args:
179
+ kernel_name: Name of the kernel to retrieve (e.g., "projections",
180
+ "temporal_gate", "state_core", "channel_mlp").
181
+
182
+ Returns:
183
+ Callable implementing the requested kernel at the best available level.
184
+
185
+ Raises:
186
+ KeyError: If kernel_name is not registered at any level.
187
+ """
188
+ cls._ensure_initialized()
189
+
190
+ if kernel_name not in cls._kernel_registry:
191
+ raise KeyError(
192
+ f"Unknown kernel '{kernel_name}'. "
193
+ f"Registered kernels: {list(cls._kernel_registry.keys())}"
194
+ )
195
+
196
+ level_map = cls._kernel_registry[kernel_name]
197
+
198
+ # Try current level, then fall back to higher (more compatible) levels
199
+ for level in sorted(AccelerationLevel, key=lambda l: l.value):
200
+ if level.value >= cls._current_level.value and level in level_map:
201
+ return level_map[level]
202
+
203
+ # Should not reach here if EAGER is always registered
204
+ raise KeyError(
205
+ f"No implementation found for kernel '{kernel_name}' "
206
+ f"at level {cls._current_level.name} or below."
207
+ )
208
+
209
+ @classmethod
210
+ def register_kernel(
211
+ cls,
212
+ kernel_name: str,
213
+ level: AccelerationLevel,
214
+ implementation: Callable,
215
+ ) -> None:
216
+ """Register a kernel implementation at a specific acceleration level.
217
+
218
+ This is used by the backend modules (triton_kernels, fallbacks) to
219
+ populate the registry.
220
+
221
+ Args:
222
+ kernel_name: Name of the kernel (e.g., "projections").
223
+ level: The acceleration level this implementation targets.
224
+ implementation: The callable implementing the kernel.
225
+ """
226
+ if kernel_name not in cls._kernel_registry:
227
+ cls._kernel_registry[kernel_name] = {}
228
+ cls._kernel_registry[kernel_name][level] = implementation
229
+
230
+ @classmethod
231
+ def reset(cls) -> None:
232
+ """Reset manager to uninitialized state. Useful for testing."""
233
+ cls._current_level = AccelerationLevel.EAGER
234
+ cls._detected_level = AccelerationLevel.EAGER
235
+ cls._initialized = False
236
+ cls._kernel_registry = {}
@@ -0,0 +1,92 @@
1
+ """Hardware device detection for the USN library.
2
+
3
+ Provides automatic detection of available compute hardware (CUDA GPUs, Apple MPS,
4
+ CPU) and selection of the optimal device for model execution.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ import torch
12
+
13
+
14
+ class DeviceDetector:
15
+ """Auto-detect available hardware and capabilities.
16
+
17
+ Provides static methods for querying the runtime environment's compute
18
+ resources. Used by AccelerationManager to determine the best acceleration
19
+ level and by model initialization to select the target device.
20
+ """
21
+
22
+ @staticmethod
23
+ def detect() -> dict[str, Any]:
24
+ """Detect available hardware and return a capabilities dictionary.
25
+
26
+ Returns:
27
+ Dictionary containing:
28
+ - device: str — best available device name ("cuda", "mps", "cpu")
29
+ - cuda_available: bool — whether CUDA is available
30
+ - mps_available: bool — whether Apple MPS is available
31
+ - gpu_name: str | None — name of the CUDA GPU (if available)
32
+ - gpu_memory: int | None — total GPU memory in bytes (if available)
33
+ - compute_capability: tuple[int, int] | None — CUDA compute cap
34
+ - cuda_version: str | None — CUDA toolkit version string
35
+ - device_count: int — number of CUDA devices
36
+ """
37
+ cuda_available = torch.cuda.is_available()
38
+ mps_available = hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
39
+
40
+ gpu_name: str | None = None
41
+ gpu_memory: int | None = None
42
+ compute_capability: tuple[int, int] | None = None
43
+ cuda_version: str | None = None
44
+ device_count = 0
45
+
46
+ if cuda_available:
47
+ device_count = torch.cuda.device_count()
48
+ try:
49
+ gpu_name = torch.cuda.get_device_name(0)
50
+ except Exception:
51
+ gpu_name = None
52
+ try:
53
+ props = torch.cuda.get_device_properties(0)
54
+ gpu_memory = props.total_mem
55
+ compute_capability = (props.major, props.minor)
56
+ except Exception:
57
+ pass
58
+ cuda_version = torch.version.cuda
59
+
60
+ # Determine best device string
61
+ if cuda_available:
62
+ device = "cuda"
63
+ elif mps_available:
64
+ device = "mps"
65
+ else:
66
+ device = "cpu"
67
+
68
+ return {
69
+ "device": device,
70
+ "cuda_available": cuda_available,
71
+ "mps_available": mps_available,
72
+ "gpu_name": gpu_name,
73
+ "gpu_memory": gpu_memory,
74
+ "compute_capability": compute_capability,
75
+ "cuda_version": cuda_version,
76
+ "device_count": device_count,
77
+ }
78
+
79
+ @staticmethod
80
+ def best_device() -> torch.device:
81
+ """Return the best available torch.device.
82
+
83
+ Priority: CUDA > MPS > CPU.
84
+
85
+ Returns:
86
+ torch.device for the best available hardware.
87
+ """
88
+ if torch.cuda.is_available():
89
+ return torch.device("cuda")
90
+ if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
91
+ return torch.device("mps")
92
+ return torch.device("cpu")
@@ -0,0 +1,102 @@
1
+ """PyTorch fallback implementations for all USN kernels.
2
+
3
+ Provides Level 2 (torch.compile) wrappers and registers them with
4
+ AccelerationManager. When torch.compile is available, these are
5
+ JIT-compiled for better performance. When unavailable, they delegate
6
+ directly to the Level 4 (eager) implementations.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+
13
+ import torch
14
+
15
+ from usn.backends.acceleration import AccelerationLevel, AccelerationManager
16
+ from usn.backends.triton_kernels import (
17
+ eager_channel_mlp,
18
+ eager_fused_projections,
19
+ eager_state_core,
20
+ eager_temporal_gate,
21
+ )
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Check if torch.compile is available
26
+ _HAS_COMPILE = hasattr(torch, "compile")
27
+
28
+
29
+ def _try_compile(fn):
30
+ """Attempt to wrap a function with torch.compile.
31
+
32
+ Uses 'reduce-overhead' mode which is optimized for repeated calls
33
+ with the same shapes (common in autoregressive generation and
34
+ fixed-length training batches).
35
+
36
+ If torch.compile is unavailable or compilation fails for any reason,
37
+ returns the original function unchanged — ensuring graceful fallback
38
+ to eager execution.
39
+
40
+ Note: torch.compile is lazy — errors may occur at first invocation
41
+ rather than at wrap time. The wrapper catches these runtime compilation
42
+ failures and falls back to the original function transparently.
43
+
44
+ Args:
45
+ fn: The function to compile.
46
+
47
+ Returns:
48
+ Compiled function if torch.compile is available and succeeds,
49
+ otherwise the original function unchanged.
50
+ """
51
+ if _HAS_COMPILE:
52
+ try:
53
+ compiled = torch.compile(fn, mode="reduce-overhead")
54
+ except Exception:
55
+ logger.debug(
56
+ "torch.compile wrapping failed for %s, using eager",
57
+ getattr(fn, "__name__", str(fn)),
58
+ )
59
+ return fn
60
+
61
+ # Wrap to catch lazy compilation failures at first call
62
+ def _safe_compiled(*args, **kwargs):
63
+ try:
64
+ return compiled(*args, **kwargs)
65
+ except Exception:
66
+ logger.debug(
67
+ "torch.compile execution failed for %s, falling back to eager",
68
+ getattr(fn, "__name__", str(fn)),
69
+ )
70
+ # Replace ourselves with the original to avoid repeated failures
71
+ _safe_compiled.__wrapped_fallback__ = True
72
+ return fn(*args, **kwargs)
73
+
74
+ # Preserve metadata for introspection
75
+ _safe_compiled.__name__ = getattr(fn, "__name__", "compiled_fn")
76
+ _safe_compiled.__qualname__ = getattr(fn, "__qualname__", "compiled_fn")
77
+ _safe_compiled.__doc__ = fn.__doc__
78
+ _safe_compiled.__wrapped__ = fn
79
+ _safe_compiled.__wrapped_fallback__ = False
80
+ return _safe_compiled
81
+
82
+ return fn
83
+
84
+
85
+ # Compiled versions (Level 2)
86
+ compiled_projections = _try_compile(eager_fused_projections)
87
+ compiled_temporal_gate = _try_compile(eager_temporal_gate)
88
+ compiled_state_core = _try_compile(eager_state_core)
89
+ compiled_channel_mlp = _try_compile(eager_channel_mlp)
90
+
91
+ # Register Level 2 (COMPILE) kernels
92
+ AccelerationManager.register_kernel("projections", AccelerationLevel.COMPILE, compiled_projections)
93
+ AccelerationManager.register_kernel(
94
+ "temporal_gate", AccelerationLevel.COMPILE, compiled_temporal_gate
95
+ )
96
+ AccelerationManager.register_kernel("state_core", AccelerationLevel.COMPILE, compiled_state_core)
97
+ AccelerationManager.register_kernel("channel_mlp", AccelerationLevel.COMPILE, compiled_channel_mlp)
98
+
99
+ logger.debug(
100
+ "Registered Level 2 (COMPILE) fallback kernels (torch.compile %s)",
101
+ "available" if _HAS_COMPILE else "NOT available — using eager",
102
+ )