mirror of
https://github.com/ruvnet/RuView
synced 2026-07-22 17:23:19 +00:00
65da488add
Closes the ADR-185 §13.a follow-up (the tractable, data-independent one of
the three §6.7 gaps): the bound EmbeddingExtractor was random-Xavier-init
only, with NO way to load real weights — so it was structurally untrained.
This adds the *capability* to load weights whenever a trained checkpoint
exists. It does NOT itself produce trained/SOTA embeddings and does NOT
close §6.7 (still no trained checkpoint, no labeled data, no eval harness).
Serialization: not greenfield — EmbeddingExtractor already had
flatten_weights()/unflatten_weights() (flat Vec<f32>). wifi-densepose-aether
is a deliberately dependency-free std-only leaf crate (ADR-185 §13), so
rather than add safetensors/serde/bincode (which would undo the zero-dep
property), the on-disk format is raw little-endian f32 with a 12-byte header
(magic "AETHERW1" + u32 param count) — zero new deps.
Native (v2/crates/wifi-densepose-aether/src/embedding.rs):
- EmbeddingExtractor::save_weights(path) / load_weights(path). load_weights
never panics: errors on unreadable file, short/oversized payload, bad
magic, or a param-count mismatch (delegated to unflatten_weights).
- Default (no weights) construction is UNCHANGED — still random init,
clearly labeled untrained. Purely additive.
Python binding (python/src/bindings/aether.rs, .pyi):
- EmbeddingExtractor.load_weights(path) / save_weights(path) / param_count,
GIL-released, ValueError on bad input.
Tests (both Rust and Python, per the task):
- Rust unit (embedding.rs): load_weights_actually_replaces_weights_and_
round_trips proves the loaded weights MOVE the embedding away from the
random-init baseline (not a silent no-op), match the source extractor
(round-trip), and are bit-identical after the file round-trip; plus a
bad-magic/wrong-count rejection test.
- Cross-language golden (aether_weights_parity.rs + test_aether.py): a
shared deterministic weight formula (w[i]=k/65536-0.5, exact in f32+f64)
written to the AETHER format; both native Rust and the Python binding load
it and must produce the byte-identical embedding SHA-256
(tests/golden/aether_loaded_embedding.sha256) — proving the binding's
load path is bit-identical to native, and (vs the random baseline) that
the loaded weights are actually used.
Verified:
cargo test -p wifi-densepose-aether 98 passed, 0 failed
cargo test --features aether --test aether_parity
--test aether_weights_parity 3 passed, 0 failed
maturin develop --features aether + pytest test_aether.py 13/13 pass
default cargo build (no aether feature) clean
59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""Type stubs for the AETHER bindings (ADR-185 P1).
|
|
|
|
Present only when the wheel is built with the ``[aether]`` extra. The
|
|
top-level ``wifi_densepose`` package does not re-export these names, so
|
|
``mypy --strict`` sees them only via ``from wifi_densepose.aether import ...``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
class AetherConfig:
|
|
def __init__(
|
|
self,
|
|
d_model: int = ...,
|
|
d_proj: int = ...,
|
|
temperature: float = ...,
|
|
normalize: bool = ...,
|
|
) -> None: ...
|
|
@property
|
|
def d_model(self) -> int: ...
|
|
@property
|
|
def d_proj(self) -> int: ...
|
|
@property
|
|
def temperature(self) -> float: ...
|
|
@property
|
|
def normalize(self) -> bool: ...
|
|
def __repr__(self) -> str: ...
|
|
|
|
class CsiAugmenter:
|
|
def __init__(self) -> None: ...
|
|
def augment_pair(
|
|
self, window: list[list[float]], seed: int
|
|
) -> tuple[list[list[float]], list[list[float]]]: ...
|
|
def __repr__(self) -> str: ...
|
|
|
|
class EmbeddingExtractor:
|
|
def __init__(
|
|
self,
|
|
n_subcarriers: int,
|
|
config: AetherConfig,
|
|
n_keypoints: int = ...,
|
|
n_heads: int = ...,
|
|
n_gnn_layers: int = ...,
|
|
) -> None: ...
|
|
def embed(self, csi_features: list[list[float]]) -> list[float]: ...
|
|
@property
|
|
def embedding_dim(self) -> int: ...
|
|
@property
|
|
def param_count(self) -> int: ...
|
|
def load_weights(self, path: str) -> None: ...
|
|
def save_weights(self, path: str) -> None: ...
|
|
def __repr__(self) -> str: ...
|
|
|
|
def info_nce_loss(
|
|
embeddings_a: list[list[float]],
|
|
embeddings_b: list[list[float]],
|
|
temperature: float = ...,
|
|
) -> float: ...
|
|
def cosine_similarity(a: list[float], b: list[float]) -> float: ...
|