[Bug已解决] torch.linalg.cross 在 MPS(Apple Silicon)上对 bool 输入报 RuntimeError 解决方案

📅 2026/7/17 4:43:45
[Bug已解决] torch.linalg.cross 在 MPS(Apple Silicon)上对 bool 输入报 RuntimeError 解决方案
[Bug已解决] torch.linalg.cross 在 MPSApple Silicon上对 bool 输入报 RuntimeError 解决方案一、现象长什么样你在 Apple SiliconM1/M2/M3/M4 Mac 上用 PyTorch 的 MPSMetal Performance Shaders后端跑torch.linalg.cross叉积时如果输入是bool布尔张量可能遇到RuntimeError: ... (MPS backend) ... for bool input也就是官方描述的torch.linalg.cross - MPS RuntimeError for bool inputtorch.linalg.cross计算两个三维向量的叉积cross product。数学上叉积定义在实数向量上。但你如果「不小心」把一个 bool 张量喂进去CPU / CUDA 上可能悄悄转成数值算或给个清晰错误而MPS 后端直接 RuntimeError因为它对 bool 的 kernel 路径没实现 / 不支持。本文讲清楚 MPS 后端的特点、为什么 bool 输入会炸、以及如何规避。二、MPS 后端是什么MPSMetal Performance Shaders是 PyTorch 在 Apple Silicon及部分 Intel Mac 配 AMD上的 GPU 加速后端。它把 PyTorch 算子映射到 Apple 的 Metal GPU 框架。import torch device mps if torch.backends.mps.is_available() else cpu x torch.randn(3, devicedevice)MPS 不是「CUDA 的完全平替」——它支持的算子集合、dtype 支持度和 CUDA 有差异。某些算子在 MPS 上对**冷门 dtype如 bool、complex 的某些组合**支持不完整于是直接 RuntimeError而不是默默算。三、为什么 bool 输入会让 cross 在 MPS 上炸叉积的数学定义以三维为例c a × b c_x a_y*b_z - a_z*b_y c_y a_z*b_x - a_x*b_z c_z a_x*b_y - a_y*b_x它本质是「乘加运算」。bool 张量True/False严格说没有「叉积」定义。在 CPU / CUDA 上PyTorch 可能把 bool 提升为数值True1, False0然后算但 MPS 的 cross kernel 没实现 bool 路径遇到 bool 直接报错。这其实是「MPS 对 bool 支持不完整」的具体表现。报错虽恼人但比「悄悄算错」好——它至少让你知道 dtype 不对。四、可运行复现与对比下面脚本对比 cross 在 CPU / MPS 上对 bool 输入的行为纯 CPU 部分可跑import torch def demo_cross(): a torch.tensor([True, False, True]) b torch.tensor([False, True, True]) # CPU可能把 bool 当 0/1 算或报错 try: c_cpu torch.linalg.cross(a, b) print(CPU cross(bool) 结果, c_cpu, c_cpu.dtype) except Exception as e: print(CPU 也报错, e) # MPS if torch.backends.mps.is_available(): a_m a.to(mps) b_m b.to(mps) try: c_m torch.linalg.cross(a_m, b_m) print(MPS cross(bool) 结果, c_m) except Exception as e: print(MPS 报错符合预期bool 不支持, type(e).__name__) else: print(无 MPS 设备跳过) if __name__ __main__: demo_cross()如果你在 MPS 上看到 RuntimeError就复现了该问题。五、解决方案一把 bool 转成数值 dtype 再算最稳的修复cross 之前把 bool 提升为 float / long叉积就有定义了import torch def safe_cross(a, b, device): # 确保是数值 dtypebool - float if a.dtype torch.bool: a a.float() if b.dtype torch.bool: b b.float() return torch.linalg.cross(a.to(device), b.to(device)) # 使用 a torch.tensor([True, False, True]) b torch.tensor([False, True, True]) device mps if torch.backends.mps.is_available() else cpu out safe_cross(a, b, device) print(正确的叉积, out)bool提升到float后MPS 的 cross kernel 正常工作True1.0, False0.0。六、解决方案二如果本意是「逻辑操作」别用 cross有时你用 bool 是想做「逻辑与 / 或 / 异或」而不是真的叉积。那根本不该用torch.linalg.crossimport torch a torch.tensor([True, False, True]) b torch.tensor([False, True, True]) # 逻辑操作应该用对应算子 and_ a b # 按位与 or_ a | b # 按位或 xor_ a ^ b # 按位异或 print(AND:, and_, OR:, or_, XOR:, xor_)确认你的真实意图要「叉积」就用数值 dtype要「逻辑运算」就用 | ^别混用。七、解决方案三统一设备前统一 dtype避免 CPU 能跑 MPS 不能一个常见坑你在 CPU 上用 bool 测过 cross 能跑或报别的错到了 MPS 就 RuntimeError。为保持一致应该在「进设备前」就规整 dtypeimport torch def prepare_for_device(x, device): # 进 MPS 前bool 一律转 float规避 MPS 对 bool 不支持 if device mps and x.dtype torch.bool: x x.float() return x.to(device) device mps if torch.backends.mps.is_available() else cpu a prepare_for_device(torch.tensor([True, False, True]), device) b prepare_for_device(torch.tensor([False, True, True]), device) out torch.linalg.cross(a, b)这样 CPU / MPS 行为一致不会出现「换个设备就崩」。八、解决方案四用 try/except 优雅降级到 CPU如果你的程序要在「支持 bool cross 的环境」和「MPS」之间移植可以降级import torch def cross_robust(a, b): device a.device try: return torch.linalg.cross(a, b) except RuntimeError: # MPS 不支持时退回 CPU 算bool 也行再搬回原设备 a_cpu, b_cpu a.cpu(), b.cpu() if a_cpu.dtype torch.bool: a_cpu, b_cpu a_cpu.float(), b_cpu.float() c torch.linalg.cross(a_cpu, b_cpu) return c.to(device) a torch.tensor([True, False, True], devicemps) if torch.backends.mps.is_available() else torch.tensor([True, False, True]) b torch.tensor([False, True, True], devicemps) if torch.backends.mps.is_available() else torch.tensor([False, True, True]) out cross_robust(a, b) print(稳健叉积结果, out)九、解决方案五升级 PyTorchMPS 支持持续补全MPS 后端是 PyTorch 较新、持续完善的。新版本可能已补全 cross 对 bool 的支持或给出更清晰错误。查看版本import torch print(PyTorch, torch.__version__) print(MPS 可用, torch.backends.mps.is_available())十、如何判断你踩的是同一条设备是 Apple SiliconMPS 后端调用torch.linalg.cross或torch.cross输入是 bool 张量报错是 RuntimeError且提到 MPS / bool把 bool 转 float 后正常。命中即说明是 MPS 对 bool 的 cross 不支持。十一、小结torch.linalg.cross在 MPS 上对 bool 输入报 RuntimeError是MPS 后端对 bool dtype 支持不完整的具体表现。应对cross 之前把 bool.float()/.long()提升为数值 dtype第五节本意是逻辑运算就用 | ^别用 cross第六节「进设备前」统一 dtype避免 CPU 能跑 MPS 不能第七节必要时 try/except 降级到 CPU 算第八节升级到补全 MPS bool 支持的 PyTorch第九节。MPS 是 Apple Silicon 上宝贵的 GPU 加速但它不是 CUDA 的完全镜像——尤其对冷门 dtypebool / 某些 complex支持有缺口。写「跨设备可移植」的代码时把 dtype 在进设备前规整好是最省心的习惯。