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
Download runtime/backends/actioncodec2/bpe_vocabulary.py from ZibinDong/ActionCodec2: direct link, hf CLI and curl.
- Browser
- Download file 6.68 kB
-
https://huggingface.co/ZibinDong/ActionCodec2/resolve/main/runtime/backends/actioncodec2/bpe_vocabulary.py
- Command line
-
hf download hf://ZibinDong/ActionCodec2/runtime/backends/actioncodec2/bpe_vocabulary.py
-
curl -L -o bpe_vocabulary.py https://huggingface.co/ZibinDong/ActionCodec2/resolve/main/runtime/backends/actioncodec2/bpe_vocabulary.py
6.68 kB
| 'Runtime plain-BPE vocabulary over the row-major flattened cell stream.' | |
| 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 | |
| __all__ = ["BPEVocabulary"] | |
| class BPEVocabulary(NativeCacheMixin): | |
| """Primitive atoms plus ordered, adjacency-based merge rules.""" | |
| bins: tuple[int, ...] | |
| merges: tuple[tuple[int, int], ...] | |
| def __post_init__(self) -> None: | |
| if not self.bins or any(count < 1 for count in self.bins): | |
| raise ValueError("every dimension needs at least one bin") | |
| self.offsets = np.concatenate(([0], np.cumsum(np.asarray(self.bins, dtype=np.int64)))) | |
| self.atom_count = int(self.offsets[-1]) | |
| self.vocab_size = self.atom_count + len(self.merges) | |
| atom_dims = np.repeat( | |
| np.arange(len(self.bins), dtype=np.int64), np.asarray(self.bins, dtype=np.int64) | |
| ) | |
| expansions: list[tuple[int, ...]] = [(token,) for token in range(self.atom_count)] | |
| for rank, (left, right) in enumerate(self.merges): | |
| token = self.atom_count + rank | |
| if not 0 <= left < token or not 0 <= right < token: | |
| raise ValueError("a merge rule must reference already-created tokens") | |
| expansions.append(expansions[left] + expansions[right]) | |
| self.expansions = tuple(expansions) | |
| self.token_dims = tuple( | |
| tuple(int(atom_dims[atom]) for atom in expansion) for expansion in expansions | |
| ) | |
| self.token_cells = np.asarray([len(expansion) for expansion in expansions], dtype=np.int64) | |
| self._rules = { | |
| (int(left), int(right)): (self.atom_count + rank, rank) | |
| for rank, (left, right) in enumerate(self.merges) | |
| } | |
| def dimension(self) -> int: | |
| return len(self.bins) | |
| def atom(self, dimension: int, value: int) -> int: | |
| return int(self.offsets[dimension]) + int(value) | |
| def _flatten(self, values: np.ndarray, dimensions: tuple[int, ...]) -> list[int]: | |
| counts = np.asarray(self.bins, dtype=np.int64) | |
| if np.any(values < -1) or np.any(values >= counts[None, :]): | |
| raise ValueError("cells contain an invalid active or absent index") | |
| support = values >= 0 | |
| if np.any(support != support[:1]): | |
| raise ValueError("active dimensions must remain constant within a trajectory") | |
| present = tuple(int(dim) for dim in np.flatnonzero(support[0])) | |
| if present != dimensions: | |
| raise ValueError("cells do not activate exactly the requested dimensions") | |
| if not present: | |
| raise ValueError("every control step needs at least one active coordinate") | |
| active = values[:, list(present)] | |
| base = np.asarray([int(self.offsets[dim]) for dim in present], dtype=np.int64) | |
| return (active + base[None, :]).reshape(-1).tolist() | |
| def encode(self, cells: np.ndarray) -> list[int]: | |
| 'Apply the merges greedily in creation-rank order to one trajectory.' | |
| values = np.asarray(cells, dtype=np.int64) | |
| if values.ndim != 2 or len(values) < 1 or values.shape[1] < 1: | |
| raise ValueError("cells must have non-empty shape [T, D]") | |
| dimensions = tuple(int(dim) for dim in np.flatnonzero(values[0] >= 0)) | |
| stream = self._flatten(values, dimensions) | |
| result = encode_native(self, values[None]) | |
| if result is not None: | |
| return result[0] | |
| count = len(stream) | |
| previous = list(range(-1, count - 1)) | |
| following = list(range(1, count + 1)) | |
| following[-1] = -1 | |
| alive = [True] * count | |
| rules = self._rules | |
| heap: list[tuple[int, int]] = [] | |
| for index in range(count - 1): | |
| rule = rules.get((stream[index], stream[index + 1])) | |
| if rule is not None: | |
| heap.append((rule[1], index)) | |
| heapq.heapify(heap) | |
| while heap: | |
| rank, index = heapq.heappop(heap) | |
| if not alive[index]: | |
| continue | |
| follower = following[index] | |
| if follower < 0 or not alive[follower]: | |
| continue | |
| rule = rules.get((stream[index], stream[follower])) | |
| if rule is None or rule[1] != rank: | |
| continue | |
| stream[index] = rule[0] | |
| alive[follower] = False | |
| after = following[follower] | |
| following[index] = after | |
| if after >= 0: | |
| previous[after] = index | |
| successor = rules.get((stream[index], stream[after])) | |
| if successor is not None: | |
| heapq.heappush(heap, (successor[1], index)) | |
| before = previous[index] | |
| if before >= 0: | |
| predecessor = rules.get((stream[before], stream[index])) | |
| if predecessor is not None: | |
| heapq.heappush(heap, (predecessor[1], before)) | |
| return [stream[index] for index in range(count) if alive[index]] | |
| def decode( | |
| self, | |
| tokens: Sequence[int], | |
| *, | |
| active_dims: Sequence[int] | None = None, | |
| ) -> np.ndarray: | |
| """Expand tokens to dense cells, writing ``-1`` in absent coordinates.""" | |
| dimensions = active_dimensions(active_dims, self.dimension) | |
| result = decode_native(self, [[int(token) for token in tokens]], dimensions) | |
| if result is not None: | |
| return result[0] | |
| atoms: list[int] = [] | |
| for index, raw_token in enumerate(tokens): | |
| token = int(raw_token) | |
| if not 0 <= token < self.vocab_size: | |
| raise ValueError(f"tokens[{index}] is outside the vocabulary") | |
| atoms.extend(self.expansions[token]) | |
| width = len(dimensions) | |
| if not atoms or len(atoms) % width: | |
| raise ValueError("token stream does not cover a whole number of routed control steps") | |
| values = np.asarray(atoms, dtype=np.int64).reshape(-1, width) | |
| starts = np.asarray([int(self.offsets[dim]) for dim in dimensions], dtype=np.int64) | |
| stops = np.asarray([int(self.offsets[dim + 1]) for dim in dimensions], dtype=np.int64) | |
| if np.any(values < starts[None, :]) or np.any(values >= stops[None, :]): | |
| raise ValueError("token stream does not follow the routed dimension order") | |
| cells = np.full((len(values), self.dimension), -1, dtype=np.int64) | |
| cells[:, list(dimensions)] = values - starts[None, :] | |
| return cells | |