Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to `ml4t-models` will be documented in this file.

## 0.1.0a5

- Added Apple Silicon MPS device resolution and seeding support for Torch-backed models.
- Added a non-skipping macOS arm64 CI smoke test that proves PyTorch MPS tensor execution.
- Updated the NumPy requirement to allow NumPy 2.5 releases.
- Fixed CUDA device normalization for whitespace or case variants such as `CUDA:0`.

## 0.1.0a4

- Aligned conditional autoencoder training with shuffled mini-batches, BatchNorm hidden layers,
Expand Down
2 changes: 1 addition & 1 deletion src/ml4t/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from importlib import import_module

__version__ = "0.1.0a4"
__version__ = "0.1.0a5"

from ml4t.models.api import (
AssetMapper,
Expand Down
2 changes: 1 addition & 1 deletion src/ml4t/models/_internal/torch_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def import_torch() -> Any:
def resolve_device(torch: Any, requested: str) -> Any:
requested_device = requested.strip().lower()
if requested_device.startswith("cuda") and torch.cuda.is_available():
return torch.device(requested)
return torch.device(requested_device)
mps_backend = getattr(torch.backends, "mps", None)
if requested_device == "mps" and mps_backend is not None and mps_backend.is_available():
return torch.device("mps")
Expand Down
8 changes: 8 additions & 0 deletions tests/test_torch_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def __init__(self, *, cuda_available: bool = False, mps_available: bool = False)
self.seeds: list[int] = []

def device(self, requested: str) -> _FakeDevice:
if requested != requested.strip().lower():
raise ValueError("fake torch expects normalized device strings")
return _FakeDevice(requested.split(":", maxsplit=1)[0])

def manual_seed(self, seed: int) -> None:
Expand All @@ -64,6 +66,12 @@ def test_resolve_device_cuda_when_available() -> None:
assert resolve_device(torch, "cuda:0").type == "cuda"


def test_resolve_device_normalizes_cuda_request() -> None:
torch = _FakeTorch(cuda_available=True)

assert resolve_device(torch, " CUDA:0 ").type == "cuda"


def test_resolve_device_cuda_falls_back_to_cpu() -> None:
torch = _FakeTorch(cuda_available=False)

Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading