A scoped, CPU-testable realization of design_v3.md — the architecture where the atomic unit is a typed (recipe, runtime) ModelCard, the model owns loop semantics while the runtime owns loop lifecycle, one resident instance runs many loops, and training records behavior on the same loops it serves. Implements: - card/ loop/ runtime/ cache/ memory/ parallel/ parity/ extend/ program/ request/ training/ spanning design_v3 §4-§13: ModelCard + validate(); driven loops (init/next/advance/finalize); step-interleaving Engine with reservation-before-admission + per-class caches keyed by CacheKey; the C0-C4 consistency ladder + the non-negotiable batch-of-N interleave parity gate. - Inference: Wan2.1-1.3B (T2V), LTX2.3 (two-stage distilled, shared transformer), Wan-causal (chunk rollout + slab-KV streaming). - Training (Wan2.1-1.3B), each driving the SAME loops the engine serves: finetune (flow-match), DMD2 (teacher/critic distribution matching), DiffusionNFT (likelihood-free C2, samples from the decay-blended old policy, group-relative advantages, shared-prompt cache reuse), self-forcing (causal chunk loop). The engine never imports training (the §10 dependency rule, grep-verified). numpy-only core (no torch/GPU here); heavy Wan/LTX forwards are deterministic toy stand-ins with lazy torch-adapter seams (ComponentSpec.load_id/factory) for a GPU box. 49 tests pass via pytest and a zero-dependency runner; interleave parity verified (and a buggy module-global interceptor provably breaks it). Omni-ready spine (ar_decode/chunk_step loop kinds, multi-loop instances, LoopState.extension) for the phase-2 Cosmos3 + vllm-omni omni ports. Run: python3 -m pytest mini_fastvideo/tests/ -q ; python3 -m mini_fastvideo.examples
61 lines
2.7 KiB
Python
61 lines
2.7 KiB
Python
"""Per-class cache pools (design_v3 §7.2): feature partition/invalidation, slab-KV window/training."""
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from mini_fastvideo.cache import CacheKey, CacheManager, CachePolicy
|
|
from mini_fastvideo.cache.classes import FeatureCache, Slab, SlabKVCache
|
|
from mini_fastvideo.models.wan_causal import build_wan_causal_card
|
|
|
|
|
|
def test_feature_cache_reuse_and_adapter_partition():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=1 << 20))
|
|
k1 = CacheKey(model_id="m", component_id="te", weights_version="v0", adapter_versions=(("l", "1"),))
|
|
v = np.ones((4,), dtype="float32")
|
|
assert fc.get(k1) is None # miss
|
|
fc.put(k1, v)
|
|
assert np.array_equal(fc.get(k1), v) # hit
|
|
k2 = CacheKey(model_id="m", component_id="te", weights_version="v0", adapter_versions=(("l", "2"),))
|
|
assert fc.get(k2) is None # different te-LoRA stack => partitioned, no stale serve
|
|
|
|
|
|
def test_feature_cache_weight_invalidation_is_wholesale():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=1 << 20))
|
|
k = CacheKey(model_id="m", component_id="te", weights_version="v0")
|
|
fc.put(k, np.ones((2,), dtype="float32"))
|
|
fc.invalidate_weights("v1") # RL update_weights bump
|
|
assert fc.get(k) is None
|
|
|
|
|
|
def test_feature_cache_budget_eviction():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=8)) # 8 bytes = one (2,)-float32
|
|
for i in range(5):
|
|
fc.put(CacheKey(model_id="m", component_id="c", step_index=i),
|
|
np.zeros((2,), dtype="float32"))
|
|
assert fc.used_bytes <= 8
|
|
|
|
|
|
def test_slab_kv_inference_window_vs_training_mode():
|
|
inf = SlabKVCache(CachePolicy("slab_kv", reuse_across_requests=False, per_component={"window": 2}))
|
|
for i in range(4):
|
|
inf.append("r", Slab(i, np.zeros((3,), dtype="float32"), None))
|
|
assert len(inf.get("r")) == 2 # sliding window recycles (inference)
|
|
|
|
tr = SlabKVCache(CachePolicy("slab_kv", training_mode_disables_recycle=True,
|
|
per_component={"window": 2}))
|
|
for i in range(4):
|
|
tr.append("r", Slab(i, np.zeros((3,), dtype="float32"), None))
|
|
assert len(tr.get("r")) == 4 # no mid-rollout recycle in training mode (self-forcing)
|
|
assert tr.used_bytes > 0
|
|
tr.clear_namespace("r")
|
|
assert tr.used_bytes == 0
|
|
|
|
|
|
def test_cache_manager_materializes_only_declared_classes():
|
|
cm = CacheManager.from_card(build_wan_causal_card())
|
|
assert cm.has("feature") and cm.has("slab_kv")
|
|
# a pure bidirectional card declares no KV class
|
|
from mini_fastvideo.models.wan21 import build_wan21_card
|
|
cm2 = CacheManager.from_card(build_wan21_card())
|
|
assert cm2.has("feature") and not cm2.has("slab_kv") # KV is the minority case
|