Default to fp32 on CPU/MPS instead of bf16 (fixes #15) - #20
Conversation
Checkpoint weights are fp32, but load_miso_8b applied torch.bfloat16 unconditionally regardless of device. On CPU/MPS bf16 brings no speed/memory benefit, and because generation is autoregressive the bf16/fp32 rounding differences compound frame-over-frame into audibly divergent output (issue MisoLabsAI#15). Resolve the default dtype from the device: bf16 on CUDA, fp32 elsewhere. An explicitly passed dtype is still honored, so this is backward compatible for callers that opt into bf16.
|
❤️ I just finished a test on vast.ai (which I had to use because I don't have Nvidia hardware) and I can confirm CUDA's BF16 is identical to CPU bf16 on the edge case I could identify. |
| def _default_dtype_for_device(device: str) -> torch.dtype: | ||
| """Pick a sane default dtype for the target device. | ||
|
|
||
| Checkpoint weights are stored as fp32. bf16 is a worthwhile speed/memory |
There was a problem hiding this comment.
Apple Silicon started supporting bfloat16 (BF16) at the hardware level with the M2 family of chips. I believe that statement is true only my homelab M1's (line 201, "no such upside")
|
I can also add this in support of this pr (or at least the approach it embodies): My tests show a real numeric difference between CPU and MPF fp32 logits, but it is small fp32 backend drift. It is not a decision-level CPU/MPS fp32 disagreement. |
Problem
load_miso_8bdefaults totorch.bfloat16and_load_modelapplies it unconditionally:The checkpoint weights are stored as fp32, so on CPU (and MPS) the default silently downcasts to bf16. bf16 buys no speed/memory benefit on those devices, and because audio generation is autoregressive, small bf16/fp32 rounding differences alter the next-frame state and compound over time — CPU bf16 and CPU fp32 produce audibly different output, especially for longer generations. (See #15 for a codebook-level repro.)
Fix
Resolve the default dtype from the target device instead of hardcoding bf16:
torch.bfloat16(unchanged behavior)torch.float32dtypenow defaults toNoneand is resolved via a small_default_dtype_for_devicehelper. An explicitly passeddtypeis still honored, so callers who deliberately want bf16 on CPU can opt in — this is fully backward compatible for CUDA users.Notes
Fixes #15.