continuousintelligence 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.
- continuousintelligence/__init__.py +9 -0
- continuousintelligence/_data/NOTICE +16 -0
- continuousintelligence/_data/bike_sharing.csv +145 -0
- continuousintelligence/_example.py +20 -0
- continuousintelligence/_loader.py +140 -0
- continuousintelligence/_plot.py +158 -0
- continuousintelligence/_vendor/__init__.py +1 -0
- continuousintelligence/_vendor/mamba3/LICENSE +201 -0
- continuousintelligence/_vendor/mamba3/__init__.py +6 -0
- continuousintelligence/_vendor/mamba3/angle_dt.py +213 -0
- continuousintelligence/_vendor/mamba3/layernorm_gated.py +115 -0
- continuousintelligence/_vendor/mamba3/mamba3_mimo_fwd.py +483 -0
- continuousintelligence/_vendor/mamba3/mamba3_mimo_utils.py +112 -0
- continuousintelligence/_vendor/mamba3/utils.py +25 -0
- continuousintelligence/ci_proto/__init__.py +5 -0
- continuousintelligence/ci_proto/_calendar.py +153 -0
- continuousintelligence/ci_proto/_checkpoint.py +106 -0
- continuousintelligence/ci_proto/_cuda.py +135 -0
- continuousintelligence/ci_proto/_forecast.py +708 -0
- continuousintelligence/ci_proto/_groups.py +198 -0
- continuousintelligence/ci_proto/_mamba.py +190 -0
- continuousintelligence/ci_proto/_model.py +489 -0
- continuousintelligence-0.1.0.dist-info/METADATA +29 -0
- continuousintelligence-0.1.0.dist-info/RECORD +30 -0
- continuousintelligence-0.1.0.dist-info/WHEEL +5 -0
- continuousintelligence-0.1.0.dist-info/licenses/LICENCE +95 -0
- continuousintelligence-0.1.0.dist-info/licenses/NOTICE +33 -0
- continuousintelligence-0.1.0.dist-info/licenses/src/continuousintelligence/_data/NOTICE +16 -0
- continuousintelligence-0.1.0.dist-info/licenses/src/continuousintelligence/_vendor/mamba3/LICENSE +201 -0
- continuousintelligence-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""The calendar covariates used by ci-proto training and inference."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
_DAY_NS = 86_400 * 10**9
|
|
12
|
+
_HOUR_NS = 3_600 * 10**9
|
|
13
|
+
_HOLIDAY_DATES = ((1, 1), (12, 24), (12, 25), (12, 26), (12, 31))
|
|
14
|
+
_LEGACY_ALIASES = {
|
|
15
|
+
"T": "min",
|
|
16
|
+
"H": "h",
|
|
17
|
+
"S": "s",
|
|
18
|
+
"L": "ms",
|
|
19
|
+
"U": "us",
|
|
20
|
+
"N": "ns",
|
|
21
|
+
"M": "ME",
|
|
22
|
+
"Q": "QE",
|
|
23
|
+
"A": "YE",
|
|
24
|
+
"Y": "YE",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def frequency_step_ns(freq: str | None) -> int:
|
|
29
|
+
"""Return the step of a pandas frequency in nanoseconds, or ``0`` for none or an irregular one.
|
|
30
|
+
|
|
31
|
+
A month counts 30 days and a quarter 91, so they select the monthly and quarterly calendar
|
|
32
|
+
rows. A step of several weeks, months or quarters returns ``0``.
|
|
33
|
+
"""
|
|
34
|
+
if not freq:
|
|
35
|
+
return 0
|
|
36
|
+
try:
|
|
37
|
+
offset = pd.tseries.frequencies.to_offset(freq)
|
|
38
|
+
except ValueError:
|
|
39
|
+
match = re.fullmatch(r"(\d*)([A-Za-z]+)(-.*)?", freq)
|
|
40
|
+
if match is None or match[2] not in _LEGACY_ALIASES:
|
|
41
|
+
return 0
|
|
42
|
+
offset = pd.tseries.frequencies.to_offset(
|
|
43
|
+
match[1] + _LEGACY_ALIASES[match[2]] + (match[3] or "")
|
|
44
|
+
)
|
|
45
|
+
if isinstance(offset, pd.offsets.Day):
|
|
46
|
+
return int(offset.n) * _DAY_NS
|
|
47
|
+
for kind, days in (
|
|
48
|
+
(pd.offsets.Week, 7),
|
|
49
|
+
(pd.offsets.MonthBegin, 30),
|
|
50
|
+
(pd.offsets.MonthEnd, 30),
|
|
51
|
+
(pd.offsets.QuarterBegin, 91),
|
|
52
|
+
(pd.offsets.QuarterEnd, 91),
|
|
53
|
+
):
|
|
54
|
+
if isinstance(offset, kind):
|
|
55
|
+
return days * _DAY_NS if offset.n == 1 else 0
|
|
56
|
+
if isinstance(offset, pd.offsets.Tick):
|
|
57
|
+
return int(pd.Timedelta(offset).value)
|
|
58
|
+
return 0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _easter_day(year: int) -> int:
|
|
62
|
+
"""Days since 1970-01-01 of Easter Sunday, by the anonymous Gregorian algorithm."""
|
|
63
|
+
a, b, c = year % 19, year // 100, year % 100
|
|
64
|
+
d, e = b // 4, b % 4
|
|
65
|
+
g = (b - (b + 8) // 25 + 1) // 3
|
|
66
|
+
h = (19 * a + b - d - g + 15) % 30
|
|
67
|
+
i, k = c // 4, c % 4
|
|
68
|
+
w = (32 + 2 * e + 2 * i - h - k) % 7
|
|
69
|
+
m = (a + 11 * h + 22 * w) // 451
|
|
70
|
+
month, day = divmod(h + w - 7 * m + 114, 31)
|
|
71
|
+
return int(np.datetime64(f"{year:04d}-{month:02d}-{day + 1:02d}").astype(np.int64))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _holiday_flags(days: NDArray[np.int64]) -> NDArray[np.bool_]:
|
|
75
|
+
"""Whether each day (days since 1970-01-01) is a holiday.
|
|
76
|
+
|
|
77
|
+
The holidays are New Year's Day, Christmas Eve to Boxing Day, New Year's Eve, Good Friday,
|
|
78
|
+
Easter Monday and US Thanksgiving; the movable ones only for years 1800 to 2300.
|
|
79
|
+
"""
|
|
80
|
+
dates = days.astype("datetime64[D]")
|
|
81
|
+
months = dates.astype("datetime64[M]").astype(np.int64) % 12 + 1
|
|
82
|
+
day_of_month = (dates - dates.astype("datetime64[M]")).astype(np.int64) + 1
|
|
83
|
+
flags = np.zeros(days.shape, dtype=bool)
|
|
84
|
+
for month, day in _HOLIDAY_DATES:
|
|
85
|
+
flags |= (months == month) & (day_of_month == day)
|
|
86
|
+
years = dates.astype("datetime64[Y]").astype(np.int64) + 1970
|
|
87
|
+
for year in np.unique(years).tolist():
|
|
88
|
+
if not 1800 <= year <= 2300:
|
|
89
|
+
continue
|
|
90
|
+
easter = _easter_day(year)
|
|
91
|
+
november = int(np.datetime64(f"{year:04d}-11-01").astype(np.int64))
|
|
92
|
+
# The fourth Thursday; 1970-01-01, day 0, was a Thursday.
|
|
93
|
+
thanksgiving = november + (3 - (november + 3) % 7) % 7 + 21
|
|
94
|
+
flags |= np.isin(days, (easter - 2, easter + 1, thanksgiving))
|
|
95
|
+
return flags
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _business_days(timestamps: NDArray[np.int64], step_ns: int) -> NDArray[np.float32] | None:
|
|
99
|
+
"""Return the weekdays that are not holidays in each step's month or quarter.
|
|
100
|
+
|
|
101
|
+
Monthly steps (28 to 31 days) count their calendar month and quarterly steps (89 to 92
|
|
102
|
+
days) their calendar quarter; any other step returns ``None``.
|
|
103
|
+
"""
|
|
104
|
+
months = (timestamps // _DAY_NS).astype("datetime64[D]").astype("datetime64[M]")
|
|
105
|
+
if 28 * _DAY_NS <= step_ns <= 31 * _DAY_NS:
|
|
106
|
+
starts = months
|
|
107
|
+
ends = months + np.timedelta64(1, "M")
|
|
108
|
+
elif 89 * _DAY_NS <= step_ns <= 92 * _DAY_NS:
|
|
109
|
+
starts = months - (months.astype(np.int64) % 3).astype("timedelta64[M]")
|
|
110
|
+
ends = starts + np.timedelta64(3, "M")
|
|
111
|
+
else:
|
|
112
|
+
return None
|
|
113
|
+
first, last = starts.astype("datetime64[D]"), ends.astype("datetime64[D]")
|
|
114
|
+
span = np.arange(first.min(), last.max(), dtype="datetime64[D]")
|
|
115
|
+
holidays = span[_holiday_flags(span.astype(np.int64))]
|
|
116
|
+
return np.busday_count(first, last, holidays=holidays).astype(np.float32)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def calendar_channels(timestamps: NDArray[np.int64], step_ns: int) -> NDArray[np.float32]:
|
|
120
|
+
"""``[channels, time]`` calendar features of a series sampled every ``step_ns``.
|
|
121
|
+
|
|
122
|
+
Steps that divide the day give hour of day (sub-daily steps only), day of week (Monday
|
|
123
|
+
``0``), day of year (``0``-``365``) and a holiday flag; weekly steps give week of year
|
|
124
|
+
(``0``-``52``) and whether a holiday falls within three days; monthly steps (28 to 31 days)
|
|
125
|
+
give month of year (``0``-``11``); quarterly steps (89 to 92 days) give the quarter
|
|
126
|
+
(``0``-``3``). Both also include the period's business-day count. Any other step gives
|
|
127
|
+
no channels.
|
|
128
|
+
"""
|
|
129
|
+
days = timestamps // _DAY_NS
|
|
130
|
+
dates = days.astype("datetime64[D]")
|
|
131
|
+
day_of_year = (dates - dates.astype("datetime64[Y]")).astype(np.int64)
|
|
132
|
+
rows: list[NDArray[np.int64] | NDArray[np.bool_]]
|
|
133
|
+
if 0 < step_ns <= _DAY_NS and _DAY_NS % step_ns == 0:
|
|
134
|
+
# 1970-01-01, day 0, was a Thursday.
|
|
135
|
+
rows = [(days + 3) % 7, day_of_year, _holiday_flags(days)]
|
|
136
|
+
if step_ns < _DAY_NS:
|
|
137
|
+
rows.insert(0, (timestamps % _DAY_NS) // _HOUR_NS)
|
|
138
|
+
elif step_ns == 7 * _DAY_NS:
|
|
139
|
+
window = (days[:, None] + np.arange(-3, 4)).ravel()
|
|
140
|
+
rows = [day_of_year // 7, _holiday_flags(window).reshape(days.shape[0], 7).any(axis=1)]
|
|
141
|
+
elif 28 * _DAY_NS <= step_ns <= 31 * _DAY_NS:
|
|
142
|
+
rows = [
|
|
143
|
+
dates.astype("datetime64[M]").astype(np.int64) % 12,
|
|
144
|
+
_business_days(timestamps, step_ns),
|
|
145
|
+
]
|
|
146
|
+
elif 89 * _DAY_NS <= step_ns <= 92 * _DAY_NS:
|
|
147
|
+
rows = [
|
|
148
|
+
(dates.astype("datetime64[M]").astype(np.int64) % 12) // 3,
|
|
149
|
+
_business_days(timestamps, step_ns),
|
|
150
|
+
]
|
|
151
|
+
else:
|
|
152
|
+
return np.empty((0, timestamps.shape[0]), dtype=np.float32)
|
|
153
|
+
return np.stack([row.astype(np.float32) for row in rows])
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Reconstruct ci-proto weights, calibration and inference backend."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import math
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import torch
|
|
8
|
+
|
|
9
|
+
from ._forecast import Forecaster
|
|
10
|
+
from ._model import Model
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _load_tta(path: str | Path) -> dict[str, float]:
|
|
14
|
+
booleans = {
|
|
15
|
+
"postprocess",
|
|
16
|
+
"tta_diff",
|
|
17
|
+
"tta_sign_flip",
|
|
18
|
+
"tta_running_totals",
|
|
19
|
+
"target_encode_categoricals",
|
|
20
|
+
"clip_nonnegative",
|
|
21
|
+
"integer_round",
|
|
22
|
+
"bfloat16",
|
|
23
|
+
"calendar_covariates",
|
|
24
|
+
}
|
|
25
|
+
constants = {
|
|
26
|
+
"trend_threshold",
|
|
27
|
+
"trend_min_r2",
|
|
28
|
+
"trend_window",
|
|
29
|
+
"diff_band_exponent",
|
|
30
|
+
"diff_band_scale",
|
|
31
|
+
"raw_band_exponent",
|
|
32
|
+
"raw_band_scale",
|
|
33
|
+
"differencing_max_horizon",
|
|
34
|
+
"static_groups",
|
|
35
|
+
"joint_neighbours",
|
|
36
|
+
"chunk_joint",
|
|
37
|
+
}
|
|
38
|
+
required = booleans | constants
|
|
39
|
+
raw = json.loads(Path(path).read_text())
|
|
40
|
+
if not isinstance(raw, dict):
|
|
41
|
+
raise ValueError("tta config must contain a JSON object")
|
|
42
|
+
missing = required - raw.keys()
|
|
43
|
+
unknown = raw.keys() - required
|
|
44
|
+
if missing or unknown:
|
|
45
|
+
raise ValueError(
|
|
46
|
+
f"invalid tta fields: missing={sorted(missing)}, unknown={sorted(unknown)}"
|
|
47
|
+
)
|
|
48
|
+
result = {}
|
|
49
|
+
for key in booleans:
|
|
50
|
+
if type(raw[key]) is not bool:
|
|
51
|
+
raise ValueError(f"{key} must be a boolean")
|
|
52
|
+
result[key] = raw[key]
|
|
53
|
+
for key in constants:
|
|
54
|
+
value = raw[key]
|
|
55
|
+
if key in ("differencing_max_horizon", "static_groups", "joint_neighbours", "chunk_joint"):
|
|
56
|
+
valid = (
|
|
57
|
+
type(value) is int
|
|
58
|
+
and value >= (1 if key == "differencing_max_horizon" else 0)
|
|
59
|
+
and not (key in ("joint_neighbours", "chunk_joint") and value == 1)
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
if type(value) not in (int, float) or not math.isfinite(value):
|
|
63
|
+
raise ValueError(f"{key} must be a finite number")
|
|
64
|
+
valid = value >= 0 if key.endswith("exponent") else value > 0
|
|
65
|
+
if key in ("trend_min_r2", "trend_window"):
|
|
66
|
+
valid = 0 < value <= 1
|
|
67
|
+
value = float(value)
|
|
68
|
+
if not valid:
|
|
69
|
+
raise ValueError(f"invalid {key}: {value}")
|
|
70
|
+
result[key] = value
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def from_checkpoint(payload: object, tta_config: str | Path, device: torch.device) -> Forecaster:
|
|
75
|
+
"""Build ci-proto from a loaded checkpoint and its calibration."""
|
|
76
|
+
tta = _load_tta(tta_config)
|
|
77
|
+
metadata = payload.get("hyper_parameters") if isinstance(payload, dict) else None
|
|
78
|
+
if not isinstance(metadata, dict) or not isinstance(metadata.get("model"), dict):
|
|
79
|
+
raise ValueError("checkpoint must contain a hyper_parameters.model mapping")
|
|
80
|
+
try:
|
|
81
|
+
model = Model(metadata["model"])
|
|
82
|
+
except (KeyError, AttributeError, TypeError, ZeroDivisionError, OverflowError) as error:
|
|
83
|
+
raise ValueError(f"invalid checkpoint model configuration: {error}") from error
|
|
84
|
+
state = payload.get("state_dict")
|
|
85
|
+
if not isinstance(state, dict) or not state or any(not isinstance(key, str) for key in state):
|
|
86
|
+
raise ValueError("checkpoint must contain a nonempty state_dict with string keys")
|
|
87
|
+
if all(key.startswith("model.") for key in state):
|
|
88
|
+
state = {key.removeprefix("model."): value for key, value in state.items()}
|
|
89
|
+
model.load_state_dict(state, strict=True)
|
|
90
|
+
levels = model.quantiles
|
|
91
|
+
if (
|
|
92
|
+
len(levels) % 2 == 0
|
|
93
|
+
or not torch.isclose(levels[len(levels) // 2], torch.tensor(0.5), atol=1e-6, rtol=0)
|
|
94
|
+
or not torch.allclose(
|
|
95
|
+
levels,
|
|
96
|
+
1 - levels.flip(0),
|
|
97
|
+
atol=1e-6,
|
|
98
|
+
rtol=0,
|
|
99
|
+
)
|
|
100
|
+
):
|
|
101
|
+
raise ValueError("ci-proto TTA requires symmetric quantiles centred on the median")
|
|
102
|
+
model = model.to(device).eval()
|
|
103
|
+
from ._cuda import configure_backend
|
|
104
|
+
|
|
105
|
+
configure_backend(model)
|
|
106
|
+
return Forecaster(model, tta)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Automatic selection and inference wrapper for the bundled Mamba-3 MIMO kernels.
|
|
2
|
+
|
|
3
|
+
Includes Mamba-3 forward integration adapted by Continuous Intelligence:
|
|
4
|
+
https://github.com/state-spaces/mamba/tree/a14b1dff0454a3bc27d9eb31355dc01e4b2490ec
|
|
5
|
+
|
|
6
|
+
Copyright (c) 2026, Dao AI Lab, Goombalab.
|
|
7
|
+
Upstream portions are licensed under Apache-2.0; see NOTICE.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import warnings
|
|
13
|
+
|
|
14
|
+
import torch
|
|
15
|
+
import torch.nn.functional as F
|
|
16
|
+
from einops import rearrange
|
|
17
|
+
from torch import Tensor, nn
|
|
18
|
+
|
|
19
|
+
from ._mamba import Mamba3
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def configure_backend(model: nn.Module) -> None:
|
|
23
|
+
"""Enable fused inference only for supported hardware and cell geometry."""
|
|
24
|
+
model.backend = "torch"
|
|
25
|
+
device = next(model.parameters()).device
|
|
26
|
+
if device.type != "cuda" or torch.version.hip is not None:
|
|
27
|
+
return
|
|
28
|
+
cells = [cell for cell in model.modules() if isinstance(cell, Mamba3)]
|
|
29
|
+
if torch.cuda.get_device_capability(device)[0] < 8 or not cells:
|
|
30
|
+
return
|
|
31
|
+
# Float32 tiles need more shared memory than bf16. Use smaller chunks on
|
|
32
|
+
# Ampere and consumer GPUs.
|
|
33
|
+
chunk_budget = (
|
|
34
|
+
64
|
|
35
|
+
if torch.cuda.get_device_properties(device).shared_memory_per_block_optin >= 196608
|
|
36
|
+
else 32
|
|
37
|
+
)
|
|
38
|
+
if any(
|
|
39
|
+
not cell.is_mimo
|
|
40
|
+
or cell.mimo_rank not in (1, 2, 4, 8)
|
|
41
|
+
or cell.d_state not in (32, 64, 128)
|
|
42
|
+
or cell.headdim not in (32, 64, 128)
|
|
43
|
+
or max(8, chunk_budget // cell.mimo_rank) * cell.mimo_rank > chunk_budget
|
|
44
|
+
for cell in cells
|
|
45
|
+
):
|
|
46
|
+
return
|
|
47
|
+
try:
|
|
48
|
+
from .._vendor.mamba3.mamba3_mimo_fwd import mamba_mimo_forward # noqa: F401
|
|
49
|
+
except (ImportError, OSError) as error:
|
|
50
|
+
warnings.warn(
|
|
51
|
+
f"Fused Mamba-3 is unavailable; using portable PyTorch on CUDA: {error}",
|
|
52
|
+
RuntimeWarning,
|
|
53
|
+
stacklevel=2,
|
|
54
|
+
)
|
|
55
|
+
return
|
|
56
|
+
for cell in cells:
|
|
57
|
+
cell.chunk_size = max(8, chunk_budget // cell.mimo_rank)
|
|
58
|
+
cell.fused = True
|
|
59
|
+
model.backend = "mamba3"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def mamba3_forward(cell: Mamba3, u: Tensor) -> Tensor:
|
|
63
|
+
"""Run the forward path, including rank-scaled chunk padding."""
|
|
64
|
+
from .._vendor.mamba3.angle_dt import angle_dt_fwd
|
|
65
|
+
from .._vendor.mamba3.layernorm_gated import _layer_norm_fwd
|
|
66
|
+
from .._vendor.mamba3.mamba3_mimo_fwd import mamba_mimo_forward
|
|
67
|
+
from .._vendor.mamba3.mamba3_mimo_utils import compute_dacs_segsum_triton
|
|
68
|
+
|
|
69
|
+
seq = u.shape[1]
|
|
70
|
+
chunk = cell.chunk_size
|
|
71
|
+
u = F.pad(u, (0, 0, 0, (-seq) % chunk))
|
|
72
|
+
bc = cell.d_state * cell.mimo_rank
|
|
73
|
+
z, x, B, C, dd_dt, dd_A, trap, angles = torch.split(
|
|
74
|
+
cell.in_proj(u),
|
|
75
|
+
[
|
|
76
|
+
cell.d_inner,
|
|
77
|
+
cell.d_inner,
|
|
78
|
+
bc,
|
|
79
|
+
bc,
|
|
80
|
+
cell.nheads,
|
|
81
|
+
cell.nheads,
|
|
82
|
+
cell.nheads,
|
|
83
|
+
cell.num_rope_angles,
|
|
84
|
+
],
|
|
85
|
+
dim=-1,
|
|
86
|
+
)
|
|
87
|
+
x = rearrange(x, "b l (h p) -> b l h p", p=cell.headdim)
|
|
88
|
+
z = rearrange(z, "b l (h p) -> b l h p", p=cell.headdim)
|
|
89
|
+
B = rearrange(B, "b l (r g n) -> b l r g n", r=cell.mimo_rank, g=1)
|
|
90
|
+
C = rearrange(C, "b l (r g n) -> b l r g n", r=cell.mimo_rank, g=1)
|
|
91
|
+
# Keep the kernel's reduction and rounding order, including 1 / sqrt.
|
|
92
|
+
B = _layer_norm_fwd(
|
|
93
|
+
B.reshape(-1, cell.d_state),
|
|
94
|
+
cell.B_norm.weight,
|
|
95
|
+
None,
|
|
96
|
+
cell.B_norm.eps,
|
|
97
|
+
is_rms_norm=True,
|
|
98
|
+
)[0].view_as(B)
|
|
99
|
+
C = _layer_norm_fwd(
|
|
100
|
+
C.reshape(-1, cell.d_state),
|
|
101
|
+
cell.C_norm.weight,
|
|
102
|
+
None,
|
|
103
|
+
cell.C_norm.eps,
|
|
104
|
+
is_rms_norm=True,
|
|
105
|
+
)[0].view_as(C)
|
|
106
|
+
A = (-F.softplus(dd_A.float())).clamp(max=-1e-4)
|
|
107
|
+
dt = F.softplus(dd_dt + cell.dt_bias)
|
|
108
|
+
adt = rearrange(A * dt, "b l h -> b h l").contiguous()
|
|
109
|
+
dt = rearrange(dt, "b l h -> b h l").contiguous()
|
|
110
|
+
angles = angles[:, :, None].expand(-1, -1, cell.nheads, -1).float().contiguous()
|
|
111
|
+
with torch.cuda.device(u.device):
|
|
112
|
+
cumulative, _ = angle_dt_fwd(angles, dt, chunk_size=chunk, return_output_state=True)
|
|
113
|
+
da_cs, da_cs_rev, segsum = compute_dacs_segsum_triton(adt, chunk)
|
|
114
|
+
y, _, _ = mamba_mimo_forward(
|
|
115
|
+
C.contiguous(),
|
|
116
|
+
B.contiguous(),
|
|
117
|
+
x.contiguous(),
|
|
118
|
+
cell.C_bias,
|
|
119
|
+
cell.B_bias,
|
|
120
|
+
cell.mimo_x,
|
|
121
|
+
cell.mimo_o,
|
|
122
|
+
z.contiguous(),
|
|
123
|
+
cell.D,
|
|
124
|
+
cell.mimo_z,
|
|
125
|
+
cumulative,
|
|
126
|
+
da_cs,
|
|
127
|
+
da_cs_rev,
|
|
128
|
+
dt,
|
|
129
|
+
rearrange(trap, "b l h -> b h l").contiguous(),
|
|
130
|
+
segsum,
|
|
131
|
+
chunk_size=chunk,
|
|
132
|
+
rotary_dim_divisor=4,
|
|
133
|
+
dtype=x.dtype,
|
|
134
|
+
)
|
|
135
|
+
return cell.out_proj(rearrange(y, "b l h p -> b l (h p)").to(u.dtype))[:, :seq]
|