perf(training): halve seeded RFF model state with verified float32 inference

This commit is contained in:
rUv committed 2026-10-12 16:00:45 -07:00
1 parent 1f3039ef26
commit d8c4ff9032
4 files changed
+92 -11

No files matched your search

+35
View File
@@ -333,3 +333,38 @@ or with the prior float32 spectral deployment artifact.
The earlier security workflow fails on preexisting Rust dependency alerts in
unchanged `v2/Cargo.lock`; the Python checks pass. That remains a release gate,
alongside independent room/person confirmation. No SOTA or promotion claim.
## Measured float32 seeded inference
The optional float32 export converts the fitted tensors and regenerated map
at load. The RFF normalization constant now follows the state dtype, avoiding
an unintended NumPy float64 promotion. Existing float64 metadata without a
precision field remains supported. Unsupported precision values are rejected.
```python
from csi_training.espfi_seeded import export_seeded, SeededKernelBundle
baseline = SeededKernelBundle('/private/espfi/seeded-001')
export_seeded(baseline.state, '/private/espfi/seeded-002', precision='float32')
candidate = SeededKernelBundle('/private/espfi/seeded-002')
```
MEASURED: all 70 development class predictions are unchanged. Maximum absolute
logit error is 1.119643e-6, below the predeclared 1e-4 tolerance. Reload is exact.
Weights occupy 8,220 bytes plus 1,069 metadata bytes. Retained model tensors use
247,996 bytes instead of 495,992, a 50% reduction. Feature extraction and the
temporary map generated during loading remain float64, so total process memory
and peak loading memory are not halved. This precision conversion is not
bitwise lossless and establishes no new accuracy or final-test result.
A 1,000-pair benchmark alternated call order and cycled all 70 development
records. Float64 p50/p95 were 0.401590/0.568780 ms; float32 were
0.390610/0.556713 ms. The 2.73% median difference is too small for a reliable
speed claim on a shared host. Float32 median load time across 30 loads was
1.633650 ms. Input checks, feature extraction and classification are included;
acquisition, temporal pooling and I/O are excluded. NumPy 2.4.4, Python 3.12.3,
x86_64 and one BLAS thread were used.
Decision: retain the verified precision option for smaller model state and
storage. Keep float64 for numerical comparison. Generalization weaknesses,
independent room/person evaluation and the existing Rust security gate remain.
+1 -1
View File
@@ -27,7 +27,7 @@ def transformed(state, values):
values = np.asarray(values, dtype=state['feature_mean'].dtype)
z = (values - state['feature_mean']) / state['feature_scale']
if 'projection' in state:
return np.sqrt(2. / state['phase'].size) * np.cos(z @ state['projection'] + state['phase'])
return np.asarray(np.sqrt(2. / state['phase'].size), dtype=z.dtype) * np.cos(z @ state['projection'] + state['phase'])
return z
+19 -10
View File
@@ -1,4 +1,4 @@
"""Lossless seed encoding for the fixed 128-dimensional CSI RFF candidate."""
"""Seed encoding with optional measured float32 conversion for fixed CSI RFF."""
import hashlib
import json
from pathlib import Path
@@ -18,33 +18,38 @@ def random_map():
'phase': rng.uniform(0, 2*np.pi, 128)}
def tensor_hash(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def validate(state):
def validate(state, dtype=np.float64):
if set(state) != set(SHAPES) or any(
state[k].shape != shape or state[k].dtype != np.float64 or
state[k].shape != shape or state[k].dtype != dtype or
not np.isfinite(state[k]).all() for k, shape in SHAPES.items()
) or not (state['feature_scale'] > 0).all():
raise ValueError('Invalid compact state')
def export_seeded(state, output):
def export_seeded(state, output, precision='float64'):
if precision not in ('float64', 'float32'):
raise ValueError('Unsupported precision')
dtype = np.dtype(precision)
generated = random_map()
if set(state) != set(SHAPES) | set(generated) or any(
not np.array_equal(state[k], generated[k]) for k in generated
):
raise ValueError('Projection does not match frozen seed recipe')
compact = {k: np.ascontiguousarray(state[k]) for k in SHAPES}
validate(compact)
compact = {k: np.ascontiguousarray(state[k], dtype=dtype) for k in SHAPES}
validate(compact, dtype)
root = Path(output)
root.mkdir(exist_ok=False, parents=True)
save_file(compact, str(root/'model.safetensors'))
report = {'status': 'complete', 'promotionAuthorized': False, 'spec': SPEC,
'model_sha256': digest(root/'model.safetensors'),
'precision': precision, 'model_sha256': digest(root/'model.safetensors'),
'model_bytes': (root/'model.safetensors').stat().st_size,
'random_map_sha256': {k: tensor_hash(v) for k,v in generated.items()},
'numpy_version': np.__version__, 'implementation_sha256': digest(__file__),
'feature_implementation_sha256': digest(Path(__file__).with_name('espfi_generalize.py')),
'stored_scalars': sum(v.size for v in compact.values()),
'runtime_scalars': sum(v.size for v in state.values()),
'scope': 'Lossless on-disk encoding only; projection regenerated at load, runtime memory unchanged'}
'runtime_state_bytes': sum(v.size for v in state.values()) * dtype.itemsize,
'kernel_implementation_sha256': digest(Path(__file__).with_name('espfi_kernel.py')),
'scope': 'Seed encoded map; float32 requires measured parity, float64 preserves original state'}
write_json(root/'metadata.json', report)
return report
@@ -60,12 +65,16 @@ class SeededKernelBundle:
raise ValueError('Invalid compact contract')
if digest(root/'model.safetensors') != report.get('model_sha256'):
raise ValueError('Compact model hash mismatch')
precision = report.get('precision', 'float64')
if precision not in ('float64', 'float32'):
raise ValueError('Unsupported precision')
dtype = np.dtype(precision)
state = load_file(str(root/'model.safetensors'))
validate(state)
validate(state, dtype)
generated = random_map()
if {k:tensor_hash(v) for k,v in generated.items()} != report.get('random_map_sha256'):
raise ValueError('Runtime random generator differs from export')
state.update(generated)
state.update({k: np.ascontiguousarray(v, dtype=dtype) for k, v in generated.items()})
self.state = state
def predict(self, amplitudes):
+37
View File
@@ -34,3 +34,40 @@ class SeededTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmp:
with self.assertRaisesRegex(ValueError,'seed recipe'):
export_seeded(state,Path(tmp)/'model')
def test_float32_export_uses_half_runtime_state(self):
amplitudes = np.exp(np.random.default_rng(3).normal(size=(14,52,190)))
x = features(amplitudes, SPEC['family'])
state = fit(x, np.arange(14)%7, dict(SPEC, kind='rff'))
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
report = export_seeded(state, root/'single', precision='float32')
model = SeededKernelBundle(root/'single')
self.assertEqual(model.predict(amplitudes).dtype, np.float32)
self.assertTrue(all(v.dtype == np.float32 for v in model.state.values()))
self.assertEqual(report['runtime_state_bytes'], 61999*4)
np.testing.assert_allclose(predict_features(state,x),model.predict(amplitudes),atol=1e-5,rtol=1e-5)
np.testing.assert_array_equal(predict_features(state,x).argmax(1),model.predict(amplitudes).argmax(1))
import json
p = root/'single/metadata.json'
metadata = json.loads(p.read_text())
metadata['precision'] = 'float16'
p.write_text(json.dumps(metadata))
with self.assertRaisesRegex(ValueError,'Unsupported precision'):
SeededKernelBundle(root/'single')
def test_legacy_float64_metadata_still_loads(self):
x = np.random.default_rng(4).normal(size=(14,468))
state = fit(x,np.arange(14)%7,dict(SPEC,kind='rff'))
with tempfile.TemporaryDirectory() as tmp:
path=Path(tmp)/'model'
export_seeded(state,path)
import json
p=path/'metadata.json'
metadata=json.loads(p.read_text())
del metadata['precision']
p.write_text(json.dumps(metadata))
loaded=SeededKernelBundle(path)
self.assertTrue(all(v.dtype==np.float64 for v in loaded.state.values()))
with self.assertRaisesRegex(ValueError,'Unsupported precision'):
export_seeded(state,Path(tmp)/'invalid',precision='float16')