Windows on Arm 运行 PyTorch-DirectML 实录
在一台搭载高通骁龙 8cx Gen 3 的联想 ThinkPad X13s 上,我尝试运行一个最简单的 PyTorch 推理任务——不是通过 WSL2、不是模拟 CUDA,而是真正让模型在 Adreno GPU 上跑起来。这台设备没有 NVIDIA 显卡,不支持 CUDA,甚至连原生的 ARM64 版本 PyTorch 都拿不到。但结果出乎意料:它真的动了。
这不是一场高性能计算的胜利,而是一次边缘 AI 的突围。当主流目光聚焦于 A100、H100 和大模型训练集群时,我们是否忽略了那些希望用轻薄本做点小推理、本地化处理、离线实验的开发者?Windows on Arm(WOA)平台或许正是这群人的“备胎选项”,而 DirectML 正是让它活过来的关键引信。
没有 CUDA 的世界,PyTorch 还能跑吗?
答案是:能,只要换条路走。
传统深度学习开发几乎被pytorch-cuda基础镜像垄断。从torchvision到 HuggingFace 的accelerate,整个生态链都围绕 NVIDIA 构建。但在 WOA 设备上:
- CUDA 不可用
- cuDNN、NCCL 等底层库缺失
- NVIDIA 官方驱动压根不存在
这意味着哪怕你把.whl包强行塞进去,也会在第一行torch.cuda.is_available()就宣告失败。
不过微软早就留了一手:DirectML(DirectX Machine Learning)。它是 Windows 10/11 内建的硬件加速接口,基于 DirectX 12,专为通用 GPU 计算设计。更重要的是,它对 Qualcomm Adreno、Intel Iris、AMD Radeon 等非 NVIDIA 显卡一视同仁。
而torch-directml,就是 Microsoft 提供的 PyTorch 后端绑定,官方定义很清晰:
“一个实验性 PyTorch 后端,使用 DirectML 在任何支持 DirectX 12 的 GPU 上实现硬件加速。”
GitHub 仓库在这里:https://github.com/microsoft/torch-directml
换句话说,只要你有 DX12 兼容显卡——哪怕是在 ARM 笔记本上的集成 GPU——就能让 PyTorch 动起来。
我的测试平台:Lenovo ThinkPad X13s Gen 1
| 项目 | 配置 |
|---|---|
| 设备型号 | Lenovo ThinkPad X13s Gen 1 (5G) |
| SoC | Qualcomm Snapdragon 8cx Gen 3 |
| 显卡 | Qualcomm Adreno GPU (DX12 兼容) |
| 内存 | 16GB LPDDR4x |
| 存储 | 512GB NVMe SSD |
| 操作系统 | Windows 11 Pro 22H2 (Build 22621.2428) |
| 架构 | ARM64 |
这台机器出厂预装 Win10,手动升级至 Win11 22H2,并安装了联想官网提供的最新图形驱动(版本30.0.3741.8500)。通过dxdiag确认 Direct3D 加速已启用,Adreno GPU 处于活跃状态。
由于目前尚无官方发布的适用于Windows on Arm 的 PyTorch wheel 包,我们只能依赖微软的x64 模拟层(Arm64EC)来运行标准 x64 Python 应用程序。这是当前阶段绕不开的妥协,但也足够让我们迈出第一步。
开发环境搭建:从零开始
1. 安装 x64 版本 Python
前往 python.org 下载并安装:
- Python 3.10.11 (x64)
⚠️ 不建议使用高于 3.11 的版本,部分依赖包尚未适配高版本解释器
安装时务必勾选“Add to PATH”,后续虚拟环境将基于此构建。
2. 克隆测试项目
为了快速验证功能,选用微软官方维护的示例库:
git clone https://github.com/microsoft/torch-directml-examples.git cd torch-directml-examples该项目包含 ResNet、BERT、Stable Diffusion Lite 等多个经典模型的推理脚本,非常适合做功能性验证。
3. 创建虚拟环境并安装依赖
python -m venv venv .\venv\Scripts\activate pip install --upgrade pip核心依赖安装命令如下:
pip install torch-directml pip install torchvision pip install numpy pillow tqdm matplotlib transformers accelerate安装过程顺利,日志显示所有包均成功安装,包括torch==2.0.0和torch-directml==0.2.0.dev230426。
值得注意的是,虽然torch-directml是独立包,但它会自动兼容标准 PyTorch API,无需修改代码逻辑。
实测三连击:张量运算 → 图像分类 → NLP 推理
✅ 测试一:基础张量运算加速
写个最小脚本test_dml.py验证设备识别与矩阵乘法能力:
import torch import torch_directml dml_device = torch_directml.device() print(f"Using device: {dml_device}") a = torch.randn(1000, 1000, device=dml_device) b = torch.randn(1000, 1000, device=dml_device) c = torch.matmul(a, b) print(f"Result shape: {c.shape}, stored on: {c.device}")输出:
Using device: dml:0 Result shape: torch.Size([1000, 1000]), stored on: dml:0✅ 成功!张量已在 Adreno GPU 上完成计算,且未触发 CPU 回退。
✅ 测试二:图像分类推理(ResNet-50)
加载 ImageNet 预训练模型进行真实场景测试:
from PIL import Image import torch import torchvision.transforms as T from torchvision.models import resnet50 import torch_directml model = resnet50(weights='IMAGENET1K_V1').eval() dml_device = torch_directml.device() model.to(dml_device) transform = T.Compose([ T.Resize(256), T.CenterCrop(224), T.ToTensor(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) img = Image.open("cat.jpg") input_tensor = transform(img).unsqueeze(0).to(dml_device) with torch.no_grad(): output = model(input_tensor) _, predicted_idx = torch.max(output, 1) with open("imagenet_classes.txt") as f: categories = [line.strip() for line in f.readlines()] print(f"Predicted class: {categories[predicted_idx.item()]}")运行结果:
Predicted class: Egyptian cat⏱️ 单次推理耗时约1.8秒,相较纯 CPU 模式(约 2.4秒)有明显提升。GPU 活跃度稳定在 70%-80%,说明 Adreno 并非摆设,确实在承担计算负载。
✅ 测试三:自然语言处理(BERT 文本分类)
尝试 HuggingFace 上的小型 BERT 模型:
from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch import torch_directml tokenizer = AutoTokenizer.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment") model = AutoModelForSequenceClassification.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment") dml_device = torch_directml.device() model.to(dml_device) text = "I love using PyTorch on Windows on Arm with DirectML!" inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True).to(dml_device) with torch.no_grad(): outputs = model(**inputs) predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) print(predictions)输出:
tensor([[0.0021, 0.0123, 0.0876, 0.3210, 0.5770]], device='dml:0')预测为五星好评,功能完整可用。尽管速度无法与 RTX 显卡相比,但对于本地文本分析、情感判断等轻量任务而言,已经足够实用。
性能表现与瓶颈剖析
| 项目 | 表现 | 分析 |
|---|---|---|
| 张量运算加速 | ✅ 明显优于 CPU | 利用了 Adreno 的 SIMD 能力 |
| 模型加载时间 | ⏱️ 较长(尤其 BERT 类) | 受限于内存带宽 + x64 模拟开销 |
| 批处理支持 | ❌ 基本无效 | batch_size > 1 极易 OOM |
| 分布式训练 | ❌ 不支持 | 缺少 NCCL 替代方案 |
| 自动微分训练 | ⚠️ 实验性支持 | 可跑小模型,但不稳定 |
| 显存管理 | ⚠️ 敏感 | 实际可用 VRAM 不足 1GB |
📊 实测资源占用情况(任务管理器观察):
- CPU 占用:~30%(主要来自 x64 模拟层)
- 内存占用:~4.2 GB(模型加载峰值)
- GPU 活动:Adreno 持续活跃于 70%-80%
- 温控表现:机身温升明显,风扇低速持续运转
结论很现实:这套组合适合轻量级推理,不适合大规模训练或批量处理。它的定位更接近“移动实验箱”而非“生产服务器”。
对比“PyTorch-CUDA 基础镜像”:差距在哪?
我们常把pytorch:latest-cuda当作 AI 开发的起点,那 WOA + DirectML 到底差多少?
| 特性 | PyTorch-CUDA 镜像 | WOA + DirectML 现状 |
|---|---|---|
| GPU 加速 | ✅ CUDA + cuDNN | ✅ DirectML(有限支持) |
| 多卡并行 | ✅ NCCL 支持 | ❌ 不可用 |
| 分布式训练 | ✅ DDP/FSDP | ❌ 无分布式后端 |
| 生产部署 | ✅ Triton/TensorRT | ❌ 无工业级服务支持 |
| 框架兼容性 | ✅ 完整生态 | ⚠️ 缺失 xformers 等模块 |
| 启动即用 | ✅ Docker 一键拉取 | ⚠️ 手动配置复杂 |
| 性能水平 | ⚡ 高吞吐、低延迟 | 🐢 中低速,仅适合边缘 |
显然,当前 WOA + DirectML 更像是一个“边缘 AI 实验平台”。但它也有独特优势:
- 无需联网即可运行模型
- 数据全程本地化,隐私安全可控
- 可作为教学演示工具,降低学生门槛
- 推动微软构建统一跨平台 AI 运行时
未来展望:从小众走向可用
虽然现在还谈不上“生产力工具”,但我看到了几个积极信号:
- 微软正在加大投入 DirectML,近期更新频繁,算子覆盖率逐步提升;
- ONNX Runtime-DirectML已经成熟,可用于替代部分 PyTorch 推理;
- 社区已有尝试将 Stable Diffusion Lite 移植到 WOA 设备;
- 微软文档明确支持“在 Surface Pro X 上运行机器学习应用”。
如果未来能实现以下几点,WOA 的 AI 能力将迎来质变:
- 发布原生 ARM64 Wheel 包,消除模拟层性能损耗
- 补齐关键缺失算子(如 GroupNorm、LayerNorm)
- 实现对 HuggingFace Accelerate 的部分支持
- 与 Azure ML 联动,支持边缘-云协同推理管道
届时,“WOA 也能跑深度学习”就不再是极客玩具,而是真正进入日常生产力序列。
结语:AI 普惠化的另一种可能
当我们谈论“AI 民主化”时,往往只盯着顶级 GPU 集群和大模型 API。但真正的普惠,应该是让每一个普通用户、每一台普通设备,都能拥有基础的人工智能能力。
这一次,在一台 ARM 架构的笔记本上跑通 PyTorch,也许只是技术长河中的一朵小浪花。但它提醒我们:创新不止发生在数据中心,也可能诞生于一次不起眼的本地推理尝试。
而这,或许才是技术民主化的真正体现。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考