
PyTorch 2.15는 애플 실리콘 맥의 MPS에서 FP8 연산을 지원하고, 언어 모델 추론과 영상 디코딩에 쓰이는 일부 연산을 빠르게 한다. MPS를 사용하는 개발자는 macOS 15 이상과 Python 3.11 이상이 필요하다.
허깅페이스의 PyTorch 팀은 이번 버전에서 FP8 텐서를 MPS에서 다루고 F.scaled_mm으로 행렬 곱을 수행할 수 있다고 밝혔다. FP8 값은 BF16의 절반 공간을 차지한다. 선형 계층과 소프트맥스에도 전용 Metal 커널을 적용했다. 팀이 제시한 측정에서는 M3 Ultra에서 torch.compile을 사용한 혼합 전문가(MoE) 모델의 디코딩 속도가 PyTorch 2.14보다 5~6.5배 빨라졌다. Qwen3.6-35B-A3B는 초당 9.4토큰에서 61.3토큰으로, LFM2.5-8B-A1B는 23.6토큰에서 123.6토큰으로 늘었다.
영상 처리에서는 Wan2.2의 타일 방식 VAE 디코딩 중 드라이버 메모리 사용량이 약 270GiB에서 약 8GiB로 줄었다. Qwen-Image-2.1의 MPS 이미지 인코더가 이미지를 손상시키던 문제도 패딩 변경으로 수정됐다고 팀은 설명했다. 인코드와 디코드 결과를 비교한 PSNR은 10.06dB에서 29.95dB로 개선됐다.
그 밖에 복소수 LU 분해와 삼각 행렬 풀이, 소규모 행렬 역산과 QR 분해 지원을 늘렸다. 오디오·학습 작업의 합성곱, 패딩, 드롭아웃, 업샘플링 역전파에도 Metal 경로를 추가했다. Python에서 MPS 스트림을 선택하고 이벤트 시간을 측정하는 기능도 개선됐다.
PyTorch 2.15 릴리스 후보는 별도 환경에서 uv pip install torch==2.15.0 --index-url https://download.pytorch.org/whl/test/cpu 명령으로 설치할 수 있다. MPS는 애플 실리콘 맥과 macOS 15 이상이 필요하며, 운영체제가 너무 오래됐거나 Metal GPU를 사용할 수 없으면 MPS 사용 가능성 확인에서 이유를 알려준다. 자세한 내용은 PyTorch 2.15 호환성 표와 허깅페이스의 발표를 참고할 수 있다.
PyTorch 2.16에서는 어텐션을 Metal에서 처리하고 MPSGraph 사용을 더 줄이는 작업이 진행 중이다. 발표 시점 기준 일부 변경은 이미 main과 나이틀리 빌드에 반영됐고, 일부는 검토 중이어서 세부 내용이 바뀔 수 있다.
부록: 원문 예시
import torch import torch.nn.functional as F def quantize_fp8(x): limit = torch.finfo(torch.float8_e4m3fn).max scale = x.abs().amax().clamp_min(1e-12) / limit return (x / scale).to(torch.float8_e4m3fn), scale x = torch.randn(1, 1024, device="mps", dtype=torch.float32) weight = torch.randn(1024, 1024, device="mps", dtype=torch.float32) x_fp8, x_scale = quantize_fp8(x) w_fp8, w_scale = quantize_fp8(weight) y = F.scaled_mm( x_fp8, w_fp8.t(), scale_a=x_scale, scale_recipe_a=F.ScalingType.TensorWise, scale_b=w_scale, scale_recipe_b=F.ScalingType.TensorWise, output_dtype=torch.bfloat16, ) print(y.shape, y.dtype)
import torch import torch.nn.functional as F tokens = torch.randn(64, 64, device="mps", dtype=torch.bfloat16) weights = torch.randn(3, 128, 64, device="mps", dtype=torch.bfloat16) ends = torch.tensor([16, 48, 64], device="mps", dtype=torch.int32) out = F.grouped_mm(tokens, weights.transpose(-2, -1), offs=ends) print(out.shape)
import torch a = torch.randn(8, 8, device="mps", dtype=torch.complex64) a = a + 8 * torch.eye(8, device="mps", dtype=torch.complex64) b = torch.randn(8, 2, device="mps", dtype=torch.complex64) lu, pivots = torch.linalg.lu_factor(a) x = torch.linalg.lu_solve(lu, pivots, b) print((a @ x - b).abs().max().item())
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요