You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Enable GPU acceleration of the natural-gradient EM backend (AMICATorchNG) on Apple
Silicon. The research in #72 (.context/mps_pathways.md) established the governing
constraint and a sequenced set of pathways; this epic executes them.
Governing constraint (why this is not a one-liner)
Apple-Silicon GPUs have no FP64 hardware. Neither PyTorch MPS nor MLX exposes
float64 on the GPU (float64 is CPU-only on both). AMICATorchNG computes in float64
for Fortran parity, so the parity path can never run on an Apple GPU. Every
Apple-GPU pathway is therefore gated on a numerically stable float32 (mixed-precision)
AMICA.
Phases (sequenced A -> C -> B)
Phase A - float32 stabilization (the enabler). Kahan/compensated summation +
mixed precision on the sufficient-stat accumulation and density/LL. Reopens and
supersedes the parked Stabilize float32 AMICATorchNG for the GPU fast path #70 technical work. Unblocks everything else.
Phase C - MLX backend port. Apple-native array framework (2-3x over PyTorch MPS,
fused lazy graph). float32-only on GPU, so it depends on Phase A. Higher ceiling,
higher cost; a v2 backend, kept optional.
Phase B - dimension-sweep benchmark. Measure MPS/MLX-float32 vs CPU across
channel count / block size / n_models to find the crossover. The 32-channel test in Optimize AMICATorchNG per-iteration cost (pow hot spot + CPU threading) #63 was the wrong regime: MPS dispatch overhead is fixed per op and amortizes on
large tensors. Runs last so it can benchmark A (and C) together.
Non-goals / ruled out
FP64 emulation on Apple GPUs (metal-float64): dead end - custom-Metal-only (not
callable from PyTorch), no transcendentals (AMICA needs exp/log/pow), 18-32x
penalty. Ruled out in the research.
Changing the production default: float64-CUDA (4.5x, bit-safe, auto-selected)
stays the production GPU path. MPS/MLX stay experimental until Phase B validates them.
Acceptance (epic-level)
Phase A: float32 (mixed) fit converges on the full sample data across seeds, LL within
parity tolerance of float64, no seed-flaky NaN; float64 default stays bit-identical.
Phase C: MLX backend equivalent to the PyTorch float32 backend on the same data.
Phase B: documented crossover curve (where Apple GPU beats CPU) in the perf notes +
a single-flag sweep in benchmarks/benchmark_gpu.py.
Goal
Enable GPU acceleration of the natural-gradient EM backend (
AMICATorchNG) on AppleSilicon. The research in #72 (
.context/mps_pathways.md) established the governingconstraint and a sequenced set of pathways; this epic executes them.
Governing constraint (why this is not a one-liner)
Apple-Silicon GPUs have no FP64 hardware. Neither PyTorch MPS nor MLX exposes
float64 on the GPU (float64 is CPU-only on both).
AMICATorchNGcomputes in float64for Fortran parity, so the parity path can never run on an Apple GPU. Every
Apple-GPU pathway is therefore gated on a numerically stable float32 (mixed-precision)
AMICA.
Phases (sequenced A -> C -> B)
mixed precision on the sufficient-stat accumulation and density/LL. Reopens and
supersedes the parked Stabilize float32 AMICATorchNG for the GPU fast path #70 technical work. Unblocks everything else.
fused lazy graph). float32-only on GPU, so it depends on Phase A. Higher ceiling,
higher cost; a v2 backend, kept optional.
channel count / block size / n_models to find the crossover. The 32-channel test in
Optimize AMICATorchNG per-iteration cost (pow hot spot + CPU threading) #63 was the wrong regime: MPS dispatch overhead is fixed per op and amortizes on
large tensors. Runs last so it can benchmark A (and C) together.
Non-goals / ruled out
metal-float64): dead end - custom-Metal-only (notcallable from PyTorch), no transcendentals (AMICA needs
exp/log/pow), 18-32xpenalty. Ruled out in the research.
stays the production GPU path. MPS/MLX stay experimental until Phase B validates them.
Acceptance (epic-level)
parity tolerance of float64, no seed-flaky NaN; float64 default stays bit-identical.
a single-flag sweep in
benchmarks/benchmark_gpu.py.References
.context/mps_pathways.md(MPS / Apple-Silicon GPU acceleration pathway (gated on float32 stability) #72), perf baseline.context/issue-63/perf_findings.md(Optimize AMICATorchNG per-iteration cost (pow hot spot + CPU threading) #63).