ZibinDong's picture
Publish audited ActionCodec2 release files
1bfc3f0 verified
Raw History Blame Contribute Delete
4.89 kB
"""Profile-level ActionCodec2Sparse fitting and default profile derivation."""
from __future__ import annotations
import time
from collections.abc import Iterable, Sequence
import numpy as np
from ..configuration import ActionCodec2Config, ConfigError
from ..physical_codec import PhysicalCodec
from ..primitives import PrimitiveStore
from ..training import _quantize_trajectories, build_primitives
from ..trajectory import TrajectoryLike
from .layout import SparseLayout, training_chunks
from .processor import ActionCodec2SparseProcessor
from .training import fit_sparse_vocabulary
DEFAULT_VOCAB_SIZE = 4096
DEFAULT_CHUNK_HORIZON = 32
DEFAULT_STATIC_RUN_CAP = 8
def sparse_profile_config(
config: ActionCodec2Config,
*,
vocab_size: int = DEFAULT_VOCAB_SIZE,
chunk_horizon: int = DEFAULT_CHUNK_HORIZON,
static_run_cap: int = DEFAULT_STATIC_RUN_CAP,
) -> ActionCodec2Config:
"""Derive an ActionCodec2Sparse profile from a first- or second-order ActionCodec2 profile."""
if config.train is None:
raise ConfigError("a sparse profile is derived from a config with a train section")
payload = config.to_dict()
payload["set_bpe"]["scheme"] = "sparse_set_bpe"
for component in payload["physical"]["components"].values():
if component["space"] == "so3" and component["primitive_order"] == 1:
component["primitive_selection"] = "momentum_lazy"
layout = SparseLayout.from_config(config, build_primitives(config))
payload["train"]["bpe"] = {
"spatial_vocab_size": sum(layout.sparse_bins),
"vocab_size": int(vocab_size),
}
payload["train"]["sparse"] = {
"chunk_horizon": int(chunk_horizon),
"static_run_cap": int(static_run_cap),
}
return ActionCodec2Config.from_dict(payload)
class SparseProfileTrainer:
"""Fit one ActionCodec2Sparse profile on complete canonical trajectories."""
def __init__(self, config: ActionCodec2Config) -> None:
if config.set_bpe.scheme != "sparse_set_bpe" or config.train is None:
raise ConfigError("SparseProfileTrainer needs a sparse_set_bpe config with train")
self.config = config
def fit(
self,
trajectories: Iterable[TrajectoryLike],
*,
backend: str = "auto",
threads: int = 0,
batch_size: int = 256,
progress: bool = False,
max_cell_bytes: int | None = None,
) -> tuple[ActionCodec2SparseProcessor, dict]:
"""Quantize then fit; see :meth:`fit_cells` for the token-layer stage."""
started = time.perf_counter()
primitives = build_primitives(self.config)
cells, actions, active_values, arities = _quantize_trajectories(
trajectories,
PhysicalCodec(self.config, primitives),
batch_size=batch_size,
max_cell_bytes=max_cell_bytes,
)
quantized = time.perf_counter()
processor, report = self.fit_cells(
cells, primitives=primitives, backend=backend, threads=threads, progress=progress
)
report.update(
trajectories=len(cells),
actions=actions,
active_values=active_values,
trajectory_arities={str(k): v for k, v in arities.items()},
)
report["seconds"]["quantize"] = quantized - started
return processor, report
def fit_cells(
self,
cells: Sequence[np.ndarray],
*,
primitives: PrimitiveStore | None = None,
backend: str = "auto",
threads: int = 0,
progress: bool = False,
) -> tuple[ActionCodec2SparseProcessor, dict]:
"""Fit the token layer on quantized cell trajectories ``[(T_i, D)]`` (``-1`` inactive)."""
config = self.config
primitives = build_primitives(config) if primitives is None else primitives
layout = SparseLayout.from_config(config, primitives)
options = config.train.sparse
chunks = training_chunks(
cells, layout, horizon=options.chunk_horizon, static_run_cap=options.static_run_cap
)
vocabulary, report = fit_sparse_vocabulary(
layout,
chunks,
spatial_vocab_size=config.train.bpe.spatial_vocab_size,
vocab_size=config.train.bpe.vocab_size,
lookahead=config.set_bpe.lookahead,
backend=backend,
threads=threads,
progress=progress,
)
report["corpus"] = {
"trajectories": len(cells),
"source_frames": int(sum(len(c) for c in cells)),
"training_frames": report["frames"],
"chunk_horizon": options.chunk_horizon,
"static_run_cap": options.static_run_cap,
}
report["tokenization_scheme"] = "sparse_set_bpe"
return ActionCodec2SparseProcessor(config, primitives, vocabulary), report