Environment: tabfm 1.0.1 (d8678b6), PyTorch backend, torch 2.13.0, Python 3.13, macOS on Apple Silicon (device="mps").
Repro
import numpy as np
from tabfm import TabFMRegressor, tabfm_v1_0_0_pytorch
model = tabfm_v1_0_0_pytorch.load("regression", device="mps")
rng = np.random.default_rng(0)
X = rng.random((100, 5), dtype=np.float32)
y = rng.random(100) # float64 — numpy's default float dtype
reg = TabFMRegressor(model=model)
reg.fit(X[:80], y[:80])
reg.predict(X[80:])
# TypeError: Cannot convert a MPS Tensor to float64 dtype as the MPS framework
# doesn't support float64. Please use float32 instead.
Cause — _predict_step_pytorch in src/classifier_and_regressor.py (~L1801):
y_t = torch.from_numpy(y_batch).to(device) # raises on MPS when y_batch is float64
if y_t.dtype == torch.float64:
y_t = y_t.to(torch.float32) # guard never reached
The float64→float32 guard sits after the .to(device), but MPS rejects float64 tensors at transfer time — so any float64 y (numpy's default) crashes before the guard runs. CUDA/CPU are unaffected, which is presumably why it hasn't surfaced.
Suggested fix — convert before moving:
y_t = torch.from_numpy(y_batch)
if y_t.dtype == torch.float64:
y_t = y_t.to(torch.float32)
y_t = y_t.to(device)
Notes
- Workaround: pass
y.astype(np.float32) to fit().
- With that workaround, both
TabFMClassifier and TabFMRegressor run end-to-end on MPS with the default bfloat16 weights — this guard ordering appears to be the only blocker for Apple Silicon.
Environment: tabfm 1.0.1 (
d8678b6), PyTorch backend, torch 2.13.0, Python 3.13, macOS on Apple Silicon (device="mps").Repro
Cause —
_predict_step_pytorchinsrc/classifier_and_regressor.py(~L1801):The float64→float32 guard sits after the
.to(device), but MPS rejects float64 tensors at transfer time — so any float64y(numpy's default) crashes before the guard runs. CUDA/CPU are unaffected, which is presumably why it hasn't surfaced.Suggested fix — convert before moving:
Notes
y.astype(np.float32)tofit().TabFMClassifierandTabFMRegressorrun end-to-end on MPS with the default bfloat16 weights — this guard ordering appears to be the only blocker for Apple Silicon.