test(stream): skip the two NF4 training-step tests when MPS is the accelerator

CI was red on macOS only (3/11 jobs); ubuntu and windows were green across
3.10/3.11/3.12, as were lint and type-check.

Cause is not bitsandbytes availability but device disagreement: on an
Apple-Silicon runner with no CUDA, TrainingArguments picks `mps`, while this
suite builds the streamed model on `cpu`. The batch is then moved to MPS and
the step raises "Placeholder storage has not been allocated on MPS device!".
Only the two tests that actually call trainer.train() were affected;
test_setup_builds_a_real_trl_trainer_under_nf4 passed, because building the
trainer never touches a device.

v0.72.0 hit exactly this and guards test_one_training_step_actually_runs the
same way; this mirrors that helper rather than inventing a second one. NF4
streaming is measured on CUDA and CPU only, and bitsandbytes' 4-bit kernels
have no MPS support, so skipping is the honest outcome — not a claim that it
works there.

Verified on the CUDA dev box: 88 passed, zero skipped, i.e. the guard does not
over-skip where the tests are meaningful.
This commit is contained in:
Alpamys 2026-07-28 15:32:56 +05:00
parent 08343f8f35
commit 7c398ccdfd
1 changed files with 30 additions and 0 deletions

View File

@ -40,6 +40,34 @@ def _cuda() -> bool:
requires_cuda = pytest.mark.skipif(not _cuda(), reason="needs a CUDA device")
def _mps_is_the_accelerator() -> bool:
"""True on an Apple-Silicon runner with no CUDA.
``TrainingArguments`` picks ``mps`` as its device there, while this suite
builds the streamed model on ``cpu``; a real training step then moves the
batch to MPS and hits "Placeholder storage has not been allocated on MPS
device". NF4 streaming is measured on CUDA and CPU only — bitsandbytes'
4-bit kernels are not supported on MPS at all so the step is skipped
rather than making an unverified claim about it. Mirrors the identical
guard in tests/test_v07200.py.
"""
try:
import torch
if torch.cuda.is_available():
return False
backend = getattr(torch.backends, "mps", None)
return bool(backend is not None and backend.is_available())
except Exception:
return False
skip_on_mps = pytest.mark.skipif(
_mps_is_the_accelerator(),
reason="MPS is untested for NF4 streaming (measured on CUDA + CPU only)",
)
# ==========================================================================
# fixtures
# ==========================================================================
@ -1628,6 +1656,7 @@ class TestNF4EndToEndSetup:
assert wrapper.trainer is not None
assert wrapper.model.is_loaded_in_4bit is True
@skip_on_mps
def test_one_nf4_training_step_actually_runs(self, tmp_path, monkeypatch):
wrapper, dataset = self._wrapper(tmp_path, monkeypatch)
wrapper.setup(dataset)
@ -1635,6 +1664,7 @@ class TestNF4EndToEndSetup:
wrapper.trainer.train()
assert wrapper._stream_runtime.pool.loads > 0, "no layer was ever streamed"
@skip_on_mps
def test_the_saved_adapter_is_canonical(self, tmp_path, monkeypatch):
"""v0.72.1's fix has to survive NF4 all the way through TRL's save."""
from safetensors.torch import load_file