Instructions to use ZibinDong/ActionCodec2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ZibinDong/ActionCodec2 with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("ZibinDong/ActionCodec2", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 10,248 Bytes
895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 1bfc3f0 895e804 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | """Runtime rooted-temporal Set-BPE vocabulary and lossless serialization."""
from __future__ import annotations
import heapq
from collections.abc import Sequence
from dataclasses import dataclass
import numpy as np
from .._validation import active_dimensions
from ..native_serialization import NativeCacheMixin, decode_native, encode_native
from .spatial import SpatialVocabulary
__all__ = ["TemporalVocabulary"]
Rule = tuple[int, int, int]
Pattern = tuple[tuple[int, int], ...]
def _active_support(active_dims: Sequence[int] | None, dimension: int) -> int:
dims = active_dimensions(active_dims, dimension)
return sum(1 << value for value in dims)
def _validate_episode(values: np.ndarray, spatial: SpatialVocabulary) -> int:
if values.ndim != 2 or values.shape[1] != spatial.dimension or len(values) < 1:
raise ValueError(
f"every episode must have non-empty shape [T, {spatial.dimension}], got {values.shape}"
)
counts = np.asarray(spatial.bins, dtype=np.int64)
if np.any(values < -1) or np.any(values >= counts[None, :]):
raise ValueError("episodes must contain -1 or an in-range cell index")
support = values >= 0
if np.any(np.sum(support, axis=1) == 0):
raise ValueError("every timestep needs at least one active coordinate")
if np.any(support != support[:1]):
raise ValueError("active dimensions must remain constant within an episode")
return sum(1 << int(value) for value in np.flatnonzero(support[0]))
@dataclass
class TemporalVocabulary(NativeCacheMixin):
"""A spatial vocabulary plus rooted, forward-only temporal merge rules."""
spatial: SpatialVocabulary
lookahead: int
merges: tuple[Rule, ...]
def __post_init__(self) -> None:
if self.lookahead < 1:
raise ValueError("lookahead must be positive")
self.patterns: list[Pattern] = [((0, token),) for token in range(self.spatial.vocab_size)]
self.spans: list[int] = [1] * self.spatial.vocab_size
self.root: list[int] = list(range(self.spatial.vocab_size))
self.support_masks: list[tuple[int, ...]] = [
(int(self.spatial.support[token]),) for token in range(self.spatial.vocab_size)
]
self._rules: dict[Rule, tuple[int, int]] = {}
for rank, rule in enumerate(self.merges):
left, right, offset = (int(value) for value in rule)
child = self.spatial.vocab_size + rank
if left >= child or right >= child or left < 0 or right < 0:
raise ValueError("a temporal merge must reference already-created tokens")
pattern, masks = _merge_pattern(
self.patterns[left],
self.patterns[right],
offset,
self.lookahead,
self.spatial,
)
self.patterns.append(pattern)
self.spans.append(len(masks))
self.root.append(self.root[left])
self.support_masks.append(masks)
key = (left, right, offset)
if key in self._rules:
raise ValueError("duplicate temporal merge rule")
self._rules[key] = (child, rank)
@property
def vocab_size(self) -> int:
return self.spatial.vocab_size + len(self.merges)
def encode(self, codes: np.ndarray) -> list[int]:
"""Encode a dense episode; ``-1`` slots are semantically absent."""
values = np.asarray(codes, dtype=np.int64)
_validate_episode(values, self.spatial)
result = encode_native(self, values[None])
if result is not None:
return result[0]
at: list[dict[int, int]] = [dict() for _ in range(values.shape[0])]
tokens: list[int] = []
anchors: list[int] = []
active: list[bool] = []
for anchor, row in enumerate(values):
for token in self.spatial.encode(row):
instance = len(tokens)
tokens.append(token)
anchors.append(anchor)
active.append(True)
at[anchor][token] = instance
frontier: list[tuple[int, int, int, int, int, int]] = []
def offer(left_instance: int, right_instance: int) -> None:
left = tokens[left_instance]
right = tokens[right_instance]
offset = anchors[right_instance] - anchors[left_instance]
rule = self._rules.get((left, right, offset))
if rule is not None:
child, rank = rule
heapq.heappush(
frontier,
(
rank,
anchors[left_instance],
int(self.spatial.anchor[self.root[child]]),
left_instance,
right_instance,
child,
),
)
for anchor, left_items in enumerate(at):
for offset in range(1, min(self.lookahead, len(at) - anchor)):
for left_instance in left_items.values():
for right_instance in at[anchor + offset].values():
offer(left_instance, right_instance)
while frontier:
_, anchor, _, left_instance, right_instance, child = heapq.heappop(frontier)
if not active[left_instance] or not active[right_instance]:
continue
if anchors[left_instance] != anchor:
continue
rule = (
tokens[left_instance],
tokens[right_instance],
anchors[right_instance] - anchor,
)
resolved = self._rules.get(rule)
if resolved is None or resolved[0] != child:
continue
active[left_instance] = False
active[right_instance] = False
del at[anchor][tokens[left_instance]]
del at[anchors[right_instance]][tokens[right_instance]]
new_instance = len(tokens)
tokens.append(child)
anchors.append(anchor)
active.append(True)
at[anchor][child] = new_instance
for offset in range(1, self.lookahead):
future = anchor + offset
if future < len(at):
for other in at[future].values():
offer(new_instance, other)
past = anchor - offset
if past >= 0:
for other in at[past].values():
offer(other, new_instance)
ordered: list[tuple[int, int, int]] = []
for anchor, instances in enumerate(at):
for token, instance in instances.items():
if active[instance]:
ordered.append((anchor, int(self.spatial.anchor[self.root[token]]), token))
ordered.sort()
return [token for _, _, token in ordered]
def decode(
self,
stream: Sequence[int],
*,
active_dims: Sequence[int] | None = None,
) -> np.ndarray:
"""Decode ids using the route's requested active-dimension support."""
if not stream:
return np.empty((0, self.spatial.dimension), dtype=np.int64)
dims = active_dimensions(active_dims, self.spatial.dimension)
result = decode_native(self, [[int(token) for token in stream]], dims)
if result is not None:
return result[0]
full = _active_support(active_dims, self.spatial.dimension)
coverage: list[int] = [0]
spatial_tokens: list[list[int]] = [[]]
front = 0
for raw_token in stream:
token = int(raw_token)
if not 0 <= token < self.vocab_size:
raise ValueError(f"temporal token {token} is outside the vocabulary")
while front < len(coverage) and coverage[front] == full:
front += 1
if front == len(coverage):
coverage.append(0)
spatial_tokens.append([])
uncovered = full & ~coverage[front]
expected_anchor = int(uncovered & -uncovered).bit_length() - 1
actual_anchor = int(self.spatial.anchor[self.root[token]])
if actual_anchor != expected_anchor:
raise ValueError(
"temporal stream violates root order at the earliest incomplete step"
)
for offset, spatial_token in self.patterns[token]:
step = front + offset
while step >= len(coverage):
coverage.append(0)
spatial_tokens.append([])
support = int(self.spatial.support[spatial_token])
if coverage[step] & support:
raise ValueError("temporal stream contains overlapping spatial support")
coverage[step] |= support
spatial_tokens[step].append(spatial_token)
if any(mask != full for mask in coverage):
raise ValueError("temporal stream ended with an incomplete control step")
return np.stack(
[self.spatial.decode(tokens, active_dims=active_dims) for tokens in spatial_tokens]
)
def _merge_pattern(
left: Pattern,
right: Pattern,
offset: int,
lookahead: int,
spatial: SpatialVocabulary,
) -> tuple[Pattern, tuple[int, ...]]:
if not 1 <= offset < lookahead:
raise ValueError("a temporal merge offset must be in [1, lookahead)")
shifted = tuple((time + offset, token) for time, token in right)
pattern = tuple(sorted((*left, *shifted)))
span = 1 + max(time for time, _ in pattern)
if span > lookahead:
raise ValueError("temporal merge exceeds the lookahead horizon")
masks = [0] * span
roots = 0
for time, token in pattern:
support = int(spatial.support[token])
if masks[time] & support:
raise ValueError("temporal merge joins overlapping spatial supports")
masks[time] |= support
roots += int(time == 0)
if roots != 1:
raise ValueError("a rooted temporal token must have exactly one time-zero spatial token")
return pattern, tuple(masks)
|