1. 方案选型:Windows 之上为什么还要一层原生内核
1.1 双系统、虚拟机与 WSL2 的三方对比
我一开始是在 Windows 上做 AI 开发的。装个 PyTorch、跑个小模型都还好,一旦要上 CUDA、要用 Linux 系的依赖库,问题就来了:很多深度学习框架、训练脚本、推理引擎优先适配 Linux,Windows 下经常碰到编译链断裂、依赖冲突、路径分隔符历史遗留问题。一开始我试过双系统,Linux 当主力,Windows 只用来开视频会议和做演示,但来回重启实在太伤效率,切换一次起码浪费五分钟,有时候正在调试的进程还得重跑。
后来我转过虚拟机方案,用 VMware 装 Ubuntu。勉强能跑,但显卡性能损失非常大,尤其是显存密集型任务,虚拟显卡桥接过去的效果远不如原生。我甚至试过 PCIe 直通把物理显卡塞给虚拟机,配置过程繁琐不说,Windows 宿主就没法用这块显卡了,等于二选一。直到 WSL2 出来,这套纠结才真正结束。WSL2 不是虚拟机,也不是简单的子系统,它是微软把完整 Linux 内核放进来跑的轻量级方案,任务管理器里能看到 Vmmem 进程,但它对资源的占用远低于传统虚拟机,启动速度又接近命令行工具。
对比一下这三条路的心态差异:双系统要选边站,虚拟机要牺牲性能,WSL2 则是“同时拥有”。尤其做 AI 开发时,多数情况是 Windows 负责日常办公、WSL2 负责全部训练推理和部署,两者之间可以通过文件系统互相访问,代码还能在同一个 IDE 里打开。这套组合对做深度学习、大模型微调、推理部署的人来说,几乎是当前最顺滑的 Windows 开发答案。
1.2 GPU 直通机制的前因后果
标题里最唬人的“GPU 直通”其实和硬件虚拟化里的 PCIe Passthrough 不是同一个东西。WSL2 采用了一种更聪明的设计,NVIDIA 为 WSL2 专门做了 vGPU 方案:Windows 宿主机正常安装显卡驱动,WSL2 里不需要额外安装完整的 NVIDIA 内核驱动,而是通过 Windows 显卡驱动栈把 CUDA 调用转发过去。
原理层面可以这么理解:WSL2 的 Linux 内核起来后,会把/usr/lib/wsl这个目录挂载进发行版,里面放着libcuda.so等一组转译库。当你跑 PyTorch 或者 TF 时,CUDA 运行时调用会经这些库转发到 Windows 侧的原生驱动,再由驱动调度到物理 GPU。这个叫做“GPU 虚拟化转发”的设计,性能损耗远比传统虚拟机的 3D 加速小得多,实测大部分训练任务能达到接近原生 Linux 的水平。值得注意的是,微软和 NVIDIA 专门维护了这条链路,而不是靠某种不稳定的补丁,所以前几年大家担心“Windows 玩不了 GPU 计算”的顾虑,从 WSL2 普及后基本就换了个说法。
这套机制的深坑在于驱动版本必须匹配。Linux 侧不需要装驱动,但 Windows 侧必须是支持 WSL2 的 NVIDIA 驱动,官方驱动都内置了。很多人踩坑是在 WSL 里又执行了apt install nvidia-driver-xxx之类的命令,结果把/usr/lib/wsl里的库覆盖了,导致nvidia-smi时好时坏。
1.3 这套方案真正适合谁
如果你只是在 Windows 上用 ChatGPT 网页版,完全不需要这套东西。如果你要写 Python 脚本调一个简单模型接口,只要会 pip 安装也能跑。但我判断下来,有三类人特别适合 WSL2 做 AI 开发:
第一类是本地大模型玩家,要在自己机器上跑量化后的 7B、8B、14B 模型。这类推理工具(比如 Ollama、llama.cpp)对 Linux 兼容性最好,Windows 原生跑的坑不少。第二类是做训练和微调的同学,要用 CUDA、cuDNN、FlashAttention 这些需要 Linux 生态的库。第三类是研究部署链路的人,最终要往服务器上扔 Docker 容器,但想在本地预演一遍,WSL2 天然支持 Docker Desktop 后端,容器行为和生产环境高度一致。
我见过不少从双系统迁回来的人,他们最真实的感受是“终于不用为了跑训练重启电脑了”。Windows 里开着浏览器写文档,WSL2 里跑着训练任务,全机资源调度统一由 Windows 管理,内存不够还能调,Ubuntu 里所有进程 LT 环境也不会因为界面切换受影响。这套方案我稳定用了快两年,值得花点篇幅把每一步怎么落地说透。
2. 部署实操:从 Windows 到内核级 Linux
2.1 开启虚拟机平台等前置条件
WSL2 依赖 Windows 的虚拟化底层,所以首先得确认几个前置项。第一是操作系统版本,Windows 10 版本 2004 及以上或者 Windows 11 都行,Windows 11 23H2 以后的版本体验最好,特别是网络配置方面。第二是 BIOS 里要打开虚拟化,Intel 叫 VT-x、AMD 叫 SVM。我遇到过一台老笔记本,系统更新到最新还是没虚拟化选项,任务管理器里看“虚拟化”显示“已禁用”,最后进 BIOS 才找到开关。开机自检时狂按 DEL 或 F2 进厂商界面,不同主板位置不太一样。
然后是 Windows 功能。最省事的方式是直接用管理员 PowerShell 执行以下命令,它会把“适用于 Linux 的 Windows 子系统”和“虚拟机平台”两个功能一起打开:
wsl --installwsl --install在最新版本里是一条全自动命令,它会启用所需功能、下载安装当前最新内核、默认安装 Ubuntu 发行版。如果执行后提示找不到命令或者版本太旧,也可以用传统方式手动开功能:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart这两条命令完成后,系统会要求重启。重启后打开 PowerShell,先看一下 WSL 内核版本:
wsl --version wsl --status如果 WSL 版本不是 2,可以用这条命令设置默认版本:
wsl --set-default-version 2顺带说一下,很多人卡在最开始是因为安装了旧版 WSL,微软在 2023 年后把 WSL 改成了独立应用,可以通过“Windows 应用商店”搜索“Windows Subsystem for Linux”更新,或者用wsl --update拉内核更新。我见过太多报错最后都是旧版内核导致,所以更新 WSL 本身应该是前置动作而非事后排查。
2.2 用命令行完成 WSL2 + Ubuntu 安装
当前主流推荐直接装 Ubuntu 24.04 LTS。wsl --install -d ubuntu-24.04是一条官方支持的命令,装完以后会让你设置用户名密码。这里有个小细节:密码在 Linux 下输入时终端不显示任何字符,很多新手以为键盘坏了,其实只是安全机制。
# 查看所有可安装发行版 wsl --list --online # 安装指定版本 wsl --install -d ubuntu-24.04 # 查看当前已安装发行版及 WSL 版本 wsl --list --verbose安装完成后进入 Ubuntu,顺手做两件事:更新软件源和安装基础工具:
sudo apt update && sudo apt upgrade -y sudo apt install build-essential git curl wget python3-pip -y这里我建议装build-essential,因为后面编译一些 CUDA 扩展、调用 Rust 第三方库时,缺少 gcc/g++ 会报莫名其妙的错。Python 我建议到时候用 conda 管理,系统自带的 python3-pip 只是兜底。
如果你用的是国内网络环境,apt 源可能偏慢,Ubuntu 24.04 的源文件在/etc/apt/sources.list.d/ubuntu.sources里,可以把官方源换成国内镜像。这个是常规操作,在这里不展开,但一定要做,否则动辄几 GB 的工具链下载会让你怀疑人生。
2.3 换个姿势把系统搬到 D 盘
WSL2 默认会把虚拟硬盘(ext4.vhdx)放在 C 盘的用户目录下,大概在C:\Users\你的用户名\AppData\Local\Packages\底下。做 AI 开发的人都知道,本地模型动不动几十 GB,C 盘很容易爆。我之前就被坑过,一个 vhdx 直接干到 80GB,C 盘变红。好在 WSL 提供了一套导出导入机制。
先执行wsl --shutdown确保没有运行实例,然后:
# 导出当前系统到 D 盘的 tar 文件 wsl --export ubuntu-24.04 D:\wsl\ubuntu24.tar # 注销当前系统 wsl --unregister ubuntu-24.04 # 重新导入到 D 盘目标目录 wsl --import ubuntu-24.04 D:\wsl\ubuntu24\ D:\wsl\ubuntu24.tar --version 2导入后默认登录用户会变成 root,需要在 Ubuntu 里执行这样一段来恢复默认用户(假设你在 Windows 里的用户名是zhangsan):
echo -e "[user]\ndefault=zhangsan" | sudo tee /etc/wsl.conf然后重启 WSL 生效。迁移后体积那几十 GB 就真的放下了。如果你不想这么大的文件长期占着 tar 空间,导入成功后可以手动删掉那个 tar 文件。另外提一句,有个工具叫 LxRunOffline 也能做迁移,但我实测官方wsl --export/--import流程最稳,没必要用第三方工具。
2.4 .wslconfig 资源规划:内存与交换空间
WSL2 默认会吃掉你一半物理内存,这对 AI 开发来说其实是好事,因为大模型推理很吃内存,但也会造成 Windows 本机卡顿。要精细控制资源,就在用户目录C:\Users\你的用户名\下新建文件.wslconfig,内容示意如下:
[wsl2] memory=16GB processors=8 swap=8GB localhostForwarding=true networkingMode=mirroredmemory是 WSL 能用的最大内存,我 32GB 的机器给 WSL 分了 16GB,既能跑 7B 量化的 LLM,又保证 Windows 还有余量处理浏览器和编辑器。processors限制 CPU 核心数,如果专机专用也可以不设。swap很重要,模型加载超出物理内存时会用 swap 补位,否则直接 OOM 崩溃。
networkingMode=mirrored是 Windows 11 22H2 之后提供的镜像网络模式。简单说就是让 WSL 和 Windows 共享网络栈,端口监听、远程访问都更直观,尤其是你要在 WSL 里启动 API 服务再供 Windows 上其他程序调用时,省掉不少端口转发问题。WSL 设置改完后都要wsl --shutdown再重新打开才生效,很多人改完发现没变,就是没重启实例。
3. GPU 直通配置与 CUDA 环境校验
3.1 Windows 驱动与 WSL 内核透传的关系
基础环境装好后,最大的重头戏就是让 WSL 里能调用到物理 GPU。前面说过,这套机制是 Windows 宿主机装驱动 + WSL 内转发。所以第一步是确认 Windows 侧驱动是最新的,去 NVIDIA 官网下载对应显卡型号的驱动。现在驱动默认支持 WSL2,不需要额外选什么分支。
装好驱动后进入 WSL,执行nvidia-smi,正常情况下会输出和 Windows 里一样的显卡信息,包括显存占用。我见过最多的报错就是找不到命令,那多半是驱动装好后没重启 Windows,或者驱动版本太老。确认方式:
nvidia-smi如果输出正常,再检查关键库文件:
ls /usr/lib/wsl/lib/正常情况下能看到libcuda.so、libcuda.so.1、libnvidia-ml.so等文件。这些就是转发到 Windows 驱动栈的桥梁。接下来要装 CUDA 工具链。这里有个关键认知:你在 WSL 里跑 AI 框架,不需要装完整 NVIDIA Linux 驱动,但需要 CUDA Toolkit 来提供编译器、运行时库。最省心的方法是用 conda 装:
conda create -n ai python=3.10 conda activate ai conda install cuda -c nvidia conda install cudnn -c conda-forge也有人直接用 NVIDIA 官网的 CUDA Toolkit 安装包,但我更推荐 conda 方式,它不会污染系统目录,而且版本管理灵活。cuda包会把nvcc编译器、CUDA 运行时都带到 conda 环境里。
3.2 验证 Python 环境里的 CUDA 与 cuDNN
环境配完,一定要做一次完整的探针测试,别等到训练到一半才发现问题。我习惯写一个最短的 Python 验证脚本:
import torch print("PyTorch:", torch.__version__) print("CUDA available:", torch.cuda.is_available()) print("Device name:", torch.cuda.get_device_name(0)) print("Device capability:", torch.cuda.get_device_capability(0)) print("cuDNN version:", torch.backends.cudnn.version())在 PyTorch 里,torch.cuda.is_available()返回True才代表 GPU 通了。如果返回False,问题出在三个地方:一是驱动没识别到显卡,二是 PyTorch 版本与 CUDA 版本不匹配,三是 CUDA 环境变量不对。最常见的组合是 PyTorch 官方默认安装的 wheel 已经自带 CUDA 运行时,所以理论上只要驱动对就可以通。
再跑一个能体现算力的测试:
import torch import time size = 4096 a = torch.randn(size, size, device="cuda") b = torch.randn(size, size, device="cuda") for _ in range(10): c = a @ b torch.cuda.synchronize() print("MatMul 4096 done on", torch.cuda.get_device_name(0))矩阵乘法的耗时能直观感受 GPU 是否真的参与计算。如果一切正常,CPU 跑一个 4096 矩阵乘法要几秒,GPU 只需几十毫秒。这个差异比任何文档都直观。
3.3 一套基于 PyTorch 的 GPU 探针测试
我再补一个更接地气的测试方法:跑一个 Mini 版的训练循环。这个测试的目的不是练模型,而是验证数据加载、GPU 显存分配、反向传播、参数更新这一整条链路没问题。
import torch import torch.nn as nn model = nn.Linear(1024, 512).cuda() optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) loss_fn = nn.MSELoss() for step in range(3): x = torch.randn(128, 1024).cuda() y = torch.randn(128, 512).cuda() out = model(x) loss = loss_fn(out, y) optimizer.zero_grad() loss.backward() optimizer.step() print(f"step {step}, loss={loss.item():.4f}, memory={torch.cuda.memory_allocated()/1024**2:.0f}MB")这个脚本能跑通,说明 WSL2 里的 GPU 链路基本没大问题。如果这步报错,比如 out of memory 或者未定义符号,那就回到 Windows 驱动和 CUDA 的匹配问题上排查。我印象最深刻的一次折腾,是某个版本的驱动和某个版本的 cuDNN 在 WSL 转发场景下有兼容问题,conda 装的最新版 cuDNN 反而导致错误。最终结论是回退一个版本的 cuDNN 就稳了。所以遇到奇奇怪怪的 CUDA 报错,优先考虑版本组合问题,不要一股脑更新到最新。
4. 搭建一个真正的 AI 开发工作流
4.1 用 VS Code Remote-WSL 告别编辑器切换
开发环境只停在命令行是不够的。我主力编辑器是 VS Code,它自带 Remote-WSL 插件。装上这个插件后,VS Code 会直接在 WSL2 里启动一个服务端,你在 Windows 的 VS Code 里编辑代码,实际运行环境完全在 Linux 内。这样 Python 解释器、CUDA 环境、调试器都在 WSL2 里,不用再单独配置 Windows 侧的任何 Python 环境。
安装插件后,左下角有个远程连接图标,点击后选择“连接到 WSL”,它会自动打开一个新窗口,并且在系统托盘提示连接到哪个发行版。打开终端,你会发现自己就在 Ubuntu 的 shell 里。然后把 conda 环境激活,把 VS Code 的 Python 解释器指到 conda 环境:
which python # 查看 python 路径在 VS Code 的命令面板(Ctrl+Shift+P)里选“Python: Select Interpreter”,粘贴刚才的路径。这一步做好后,代码里import torch就会使用 WSL2 里的环境,GPU 直接可用。我见过很多人明明 WSL 环境装好了,还在 Windows 侧跑代码,结果torch.cuda.is_available()一直 False,虚惊一场。
4.2 Docker Desktop 与 WSL2 后端
如果要做 AI 服务的容器化部署,Docker Desktop 在 WSL2 模式下非常舒服。安装完 Docker Desktop 后,在设置里选择“Use the WSL 2 based engine”,它能和 WSL2 共享内核,性能比传统 Hyper-V 隔离模式更好。但光共享引擎还不够,需要启用特定发行版的集成:在 Docker Desktop 的 Resources -> WSL Integration 里把 Ubuntu-24.04 打开。
启用后你在 WSL2 里直接敲docker version,能正常输出客户端和服务端信息。做一个 GPU 容器的验证:
docker run --rm --gpus all nvidia/cuda:12.3.0-base-ubuntu22.04 nvidia-smi能看到 GPU 信息就说明容器里也能透传显卡。这也是后续在生产服务器上部署 AI 推理服务前最有效的本地预演方式。我在本地容器里跑过 API 推理,和线上行为的差异几乎只有网络延迟这一个变量。
4.3 在 WSL2 里跑本地大模型推理
本地大模型推理最方便的工具是 Ollama。安装很简单:
curl -fsSL https://ollama.com/install.sh | sh ollama serve然后在另一个终端拉模型并运行。以当前很受欢迎的 DeepSeek-R1 系列为例,7B 量化版在消费级显卡上就能跑:
ollama run deepseek-r1:7b第一次运行会下载模型文件,之后就能在终端里对话。Ollama 在 WSL2 里的 GPU 支持非常完善,它自动利用 CUDA 库。你可以在启动前用nvidia-smi看显存占用,会发现加载模型后显存大幅上升,这就说明真的在用 GPU 推理。
我还试过用 WSL2 跑多 AI 协作场景:在 WSL2 里分别启动不同的 Ollama 实例,比如一个跑 7B 模型做对话,一个跑小模型做摘要,Python 端通过 API 把它们串起来。这种多模型协作在 Windows 原生环境下反而难配置,因为依赖的 shell 工具链、端口管理都不如 Linux 顺手。WSL2 下这些全部变成常规操作。
4.4 从物理 GPU 到容器前后端协作的完整链路
搭好这套环境后,一个典型的本地 AI 应用链路是:Windows 上打开浏览器访问前端页面,页面请求发到 WSL2 里跑的 FastAPI 服务,FastAPI 再调用 GPU 推理模型,结果返回前端展示。物理链路里 WSL2 像一个独立 Linux 服务器,但网络层和文件系统层与 Windows 无缝衔接。
例子代码很简单,在 WSL2 里写一个 FastAPI 服务:
from fastapi import FastAPI import torch app = FastAPI() @app.get("/health") def health(): return {"cuda": torch.cuda.is_available()}启动:
pip install fastapi uvicorn uvicorn main:app --host 0.0.0.0 --port 8000然后在 Windows 浏览器访问http://localhost:8000/health。由于 WSL2 的端口转发机制,Windows 侧可以直接用 localhost 访问 WSL2 服务。如果你开了镜像网络模式,这种访问更直接可靠。
这个链路我强烈建议每个人都跑通一次,因为它是理解“WSL2 到底能干什么”的最快路径。跑完之后你会发现,AI 开发不会再因为“Windows 不支持某些 Linux 依赖”而停摆。
5. 常见问题速查与避坑技巧
5.1 “WSL2 尚未准备就绪”的三种成因
这个报错我见得太多了。每次群里有人发wsl2 尚未准备就绪,心情我都懂。它的出现通常有三种成因。
第一,Windows 功能没开全。去“控制面板 -> 程序 -> 启用或关闭 Windows 功能”里看“虚拟机平台”和“适用于 Linux 的 Windows 子系统”是否打勾,如果没有就勾上重启。
第二,BIOS 虚拟化没开。打开任务管理器 -> 性能 -> CPU,看右下角“虚拟化”是否显示“已启用”。如果显示“已禁用”,进 BIOS 找 Intel Virtualization Technology 或 AMD SVM 开启。这一步对很多笔记本用户尤其容易踩坑,因为某些品牌默认关闭。
第三,WSL 内核太旧。打开 PowerShell 执行wsl --update,等它更新内核后重启。微软现在把 WSL 当作应用商店里的独立应用,如果系统不是从商店安装的版本,需要去应用商店搜“Windows Subsystem for Linux”更新一下。
5.2 虚拟化配置错误的处理流程
还有一种报错更具体:运行wsl --install -d ubuntu-24.04时报“WSL2 无法启动,因为此计算机上未启用虚拟机”。这个报错直接把问题引向了虚拟机平台。处理顺序我建议这样:
# 第一步:检查虚拟化功能状态 Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform # 第二步:如果状态不是 Enabled dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart # 第三步:打开 Hypervisor 启动类型 bcdedit /set hypervisorlaunchtype auto第三步尤其关键。有些第三方安全软件会顺手把 hypervisor launch type 改成 off,导致 WSL2 起不来。我自己遇到过一次,是因为系统装了某款模拟器之后,Hyper-V 启动被改掉,执行bcdedit /set hypervisorlaunchtype auto后重启才恢复。如果 Windows 上还开着旧版 VMware Workstation,也可能和 WSL2 冲突,尽量停在同一个 Hyper-V 生态里。
5.3 磁盘与 IO 性能优化中的隐藏参数
WSL2 的根文件系统是 ext4 格式,存放在 vhdx 虚拟硬盘中。默认情况下 vhdx 会随着使用不断膨胀。解决办法是在.wslconfig里增加自动回收:
[wsl2] sparseVhd=true这个参数会把 vhdx 设置为稀疏文件,动态回收未使用的空间。但如果你已经有一个很大的 vhdx,这个参数不会收缩现有文件。可以手动用 PowerShell 管理员模式执行:
Optimize-VHD -Path "C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited...\ext4.vhdx" -Mode FullOptimize-VHD是 Hyper-V 模块里的命令,Windows 10/11 专业版默认有。执行前确保wsl --shutdown过。做完这一套,一个 80GB 的 vhdx 可能瘦身到 20GB,效果立竿见影。
另外,文件 IO 性能有个重要注意点:在 WSL2 里访问 Windows 的 NTFS 盘(比如/mnt/c)速度明显比访问 WSL 自身文件系统慢。做 AI 训练时,数据集、代码尽量放在 Linux 文件系统内部,不要放在 Windows 盘符目录下跨文件系统读写。我有个项目本来把数据集放在 D 盘,通过/mnt/d挂载读取,训练时磁盘 IO 成了瓶颈,移动进 WSL 后速度翻了几倍。
5.4 长期使用时建议养成的习惯
最后分享几个我自己长期用下来觉得非常重要的小习惯。
第一,定期清理不用的发行版。wsl --list --verbose看看是不是装了好几个 Ubuntu 副本,不用的直接wsl --unregister,把空间让出来。
第二,养成wsl --shutdown的习惯。不是让你每次都关,而是在改动.wslconfig、重新导入镜像、处理网络异常之后,先关掉再开。WSL 内部没有 systemd 管理复杂的服务依赖,热切换不如重启彻底。现在新版 WSL 默认支持 systemd,但资源异常时重启仍然是最快的恢复方式。
第三,conda 环境命名的时候带上用途字段。我习惯叫ai、data、web这种一眼能看懂的名字。AI 开发迭代很快,今天装了 PyTorch,明天要装 TensorRT,环境混在一起早晚出事。独立环境之间切换就是conda activate一条命令,混乱的成本永远大于规整的成本。
第四,把 Windows 驱动升级和 WSL 内核更新放在同一维护周期里。每个月更新一次 Windows 驱动,之后顺手wsl --update。我发现很多人 GPU 直通失效不是配置错了,就是 Windows 更新后驱动不一致导致。维护周期短一点,这类问题基本不出现。
这套 WSL2 环境我每天都在用,从最初的装系统、调 CUDA,到后来直接在上面跑大规模训练和容器化推理服务,整体稳定性远超我预期。配置过程看起来步骤多,但只要把前置项检查好,后面就是一马平川。如果你是 Windows 用户又想做 AI 开发,这套方案值得直接抄作业。