Phase D: Multi-model support for AMICAMLXNG - #82
Merged
neuromechanist merged 2 commits intoJul 8, 2026
Merged
Conversation
Epic #74 Phase D: extend the MLX Apple-GPU backend to n_models > 1, porting the multi-model machinery from AMICATorchNG -- comp_list indirection, per-model W=inv(A[:,comp_list]) + slogdet (CPU stream), cross-model responsibilities v=softmax(logV), the per-model exact-EM bias c update, and the gm-weighted A-update scattered through comp_list. Single-model (#76) stays byte-for-byte unchanged (the loop runs once, gm=1, identity comp_list). Component sharing remains a fast-follow. Validated on real sample EEG: multi-model (n_models=2) one-iteration sufficient stats match AMICATorchNG float32 to float32 precision, and the converged LL matches to ~1e-5. New tests/mlx_tests test_multimodel_matches_torch_float32; the single-model byte-identity and torch-float32 tests still pass. Benchmark (benchmark_dimsweep.py) now runs MLX in the multi-model configs: MLX wins multi-model too -- ~38-45 ms/it, ~5x over torch-CPU (MPS still loses), matching the ~7x single-model win. Findings updated (.context/issue-77).
Silent-failure review: - Port the dead-model warning to the multi-model c update (a zero-responsibility model kept its prior c but was surfaced-free; matches AMICATorchNG). - Add gm and c to the per-iteration mx.eval and the params_finite guard: they are new multi-model state that feeds the next E-step, so a last-iteration blow-up must be caught (nan_params) and c's cross-iteration dependency must be materialized each iteration rather than growing the lazy graph unbounded. Comment/doc review: - Fix two wrong AMICATorchNG citations (c-update 1083-1092, A-update 1231-1247) and the stale _lgamma_table shape comment ((n_mix, n_comps)). - Drop the leftover "MVP"/"v1" framing that contradicted the new multi-model scope (module/class docstrings, transform(), the module title now #76/#81). Test review: - Expand the multi-model one-iteration stat comparison to every accumulator, including dWtmp (the gm-weighted A-update input, transposed to align the (n_models,n,n) vs (n,n,n_models) layouts) and the scattered mixture stats. - Add a direct multi-model c-update check (responsibility-weighted data mean, and the two models' c must differ) and a single-model c==0 regression guard. mlx suite green (5 passed); the port is unchanged (code reviewer verified single-model byte-identity independently).
Member
Author
Review summary (4 Sonnet reviewers, worktree-isolated)The code reviewer independently verified byte-identity (single-model Silent-failure
Tests
Comments/docs
Not changed (with rationale)
mlx suite green (5 passed). |
neuromechanist
merged commit Jul 8, 2026
e4433aa
into
feature/issue-74-epic-apple-gpu
7 checks passed
This was referenced Jul 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Epic #74 Phase D (final phase): extend the MLX Apple-GPU backend (
AMICAMLXNG) ton_models > 1. The Phase B benchmark showed multi-model had no GPU path (MLX was single-model, MPS loses); this closes that gap so the ~7x single-model MLX win extends to multi-model AMICA.Ports the multi-model machinery from
AMICATorchNG:comp_listindirection (params go(n_mix, n_channels)->(n_mix, n_comps)), per-modelW = inv(A[:, comp_list[:,h]])+slogdeton the CPU stream (hoisted per iteration).logV (batch, n_models), cross-model responsibilitiesv = softmax(logV),u = v_h * z.gm, the per-model exact-EM biascupdate, and the gm-weighted A-update scattered throughcomp_list.Single-model (#76) stays byte-for-byte unchanged (the loop runs once,
gm=1, identitycomp_list-> the A-update collapses to the oldA - lrate*(dA.T@A)). Component sharing remains a fast-follow.Validation (real sample EEG; Apple GPU)
test_multimodel_matches_torch_float32.Benchmark
MLX now runs in the multi-model configs (dropped the single-model gate). MLX wins multi-model too: ~38 ms/it (32ch) / 45 ms/it (70ch) -- ~5x over torch-CPU, MPS still loses. Findings updated (
.context/issue-77/benchmark_findings.md).Scope note
The comprehensive native-Fortran + CPU-core-scaling (4/6/8/12) + CUDA cross-platform benchmark is intentionally NOT in this PR -- it is being split into its own epic (native x86 Linux + CUDA host, since Apple's Fortran binary is x86-under-Rosetta and Mac CPU timing is unreliable).
Test plan
uv run pytest pyAMICA/tests/mlx_tests/(Apple Silicon; self-skips in CI). Full torch suite unaffected (mlx_impl is isolated + optional). ruff clean;mlx_implomitted from the coverage gate (Apple-only).Closes #81
Part of epic #74