我见过很多人在 Windows 上搞 AI 开发时的纠结:想用 Linux 环境跑 PyTorch,又离不开 Windows 的日常办公生态;装双系统来回切换浪费时间,传统虚拟机里 GPU 根本不干活;云 GPU 虽好,调试时数据来回传又折磨人。直到 WSL2 把“内核级 Linux 环境 + GPU 直通”这两件事真正做成熟,踩了一整年坑之后,我可以负责任地说:在 Windows 上用 WSL2 部署 AI 开发环境,是目前把办公和训练整合在一台机器上最顺手的方案。这篇文章就基于我自己的实操过程,把 WSL2 搭建 AI 开发环境的完整路径、原理和踩坑记录分享出来,目标是让从零开始的朋友也能照着搭出一套能真正跑 GPU 训练的环境。
1. 为什么我最终把 AI 开发环境迁到了 WSL2
1.1 传统方案在 AI 场景里的真实痛点
在 WSL2 成熟之前,Windows 用户跑深度学习基本就只有三条路:双系统、传统虚拟机、云 GPU。双系统本质上是个时间管理灾难——训练任务经常要跑十几个小时,白天在 Windows 写代码做方案,晚上切到 Ubuntu 挂训练,第二天早上又切回 Windows 开会演示。来回重启看似没问题,但你开着浏览器几十个标签页、IDE 里一堆未保存的窗口,切换成本高得让人烦躁。更麻烦的是项目文件在两边来回拷,路径、权限、编码问题层出不穷,模型权重文件动辄几个 GB,光同步就够折腾。
传统虚拟机的情况更不乐观。我当初在 VMware 里装完 Ubuntu,兴冲冲地跑torch.cuda.is_available(),结果返回 False。查了一圈发现,VMware 对 NVIDIA GPU 的透传支持非常有限,除非用 PCI Passthrough 把整块显卡直接分配给虚拟机——这要求硬件支持 IOMMU、还要牺牲 Windows 侧的显卡功能,配置复杂度极高,桌面级用户基本不可能去弄。没有 GPU 加速,训练小模型都得等半天,批量跑实验更是想都别想。
云 GPU 倒是解决了算力问题,V100、A100 按小时租确实快,可成本不低。调试阶段代码经常要改,数据集和权重文件来回上传下载,网络一慢,等待时间比训练时间还长。一个月下来账单挺心虚的,而且真正调通之前,大量的时间其实浪费在环境同步和文件传输上,而不是模型迭代上。
这三条路的痛点总结起来就三件事:你需要一个真正的 Linux 内核环境,你需要 GPU 能被深度学习框架直接调用,你又想跟 Windows 桌面工作流无缝衔接。这三个需求在过去不可能同时满足,直到 WSL2 和 GPU 半虚拟化方案出现。
1.2 WSL2 的“内核级”是什么意思:不是模拟器
很多朋友一听到 WSL 就以为它是“Windows 里的 Linux 模拟器”,这个印象来自 WSL1。WSL1 确实不是虚拟机,它的实现方式是把 Linux 的系统调用翻译成 Windows 内核调用,本质上是一个兼容层,碰到底层操作——比如需要加载特定内核模块、处理复杂网络协议栈、访问某些硬件设备——就会出各种奇怪的问题。
WSL2 则彻底换了架构。它跑在一个经过深度优化的轻量级虚拟机上,这个虚拟机的内核是微软维护的定制版 Linux 内核,和你平时在服务器上用的 Linux 5.x/6.x 内核没有本质区别。你在 WSL2 里执行uname -a,看到的是真实的内核版本号,不是翻译层模拟出来的东西。这就意味着你可以在 WSL2 里加载没被裁剪的内核模块,可以跑 Docker 容器,可以运行任何需要完整 Linux 系统调用的软件。对 AI 开发来说,这意味着 PyTorch、TensorFlow 这类深度依赖 CUDA 的系统调用的框架,在 WSL2 里是原生运行,跟一台原生 Ubuntu 服务器几乎没有差异。
1.3 什么样的 AI 开发场景最适合 WSL2
根据我这一年多的使用体验,WSL2 特别适合这几类人:
第一类,日常用 Windows 办公,同时又需要 Linux 环境做 AI 项目的人。这是最典型的场景,WSL2 把两个系统整合在同一台机器上,训练和办公互不干扰,Ctrl+C、Ctrl+V 直接从 Windows 往 WSL2 里粘贴命令,文件也可以通过\\wsl$\Ubuntu-22.04路径直接访问。第二类,模型调试为主、训练规模适中的场景。单卡或双卡的机器上做模型微调、跑中小规模数据集、验证结构、调参,这类工作 WSL2 完全能胜任。真要到大规模分布式训练或者训练超大模型的地步,本地机器的显存和算力本来就不够,那得上 GPU 服务器或集群,WSL2 也帮不上忙。第三类,需要在本地跑大模型推理、LoRA 微调、Agent 工作流的开发者。这类任务通常单张 RTX 3090/4090 或者专业卡就能跑起来,加上 WSL2 对显存直通的支持体验相当好。
某类特殊场景我会劝你放弃 WSL2:如果你需要用到 WSL2 内核里没有芯片组驱动支持的特殊硬件(比如某些采集卡、专用加速卡),或者对多 GPU NCCL 通信延迟有极致要求,那还是原生 Linux 或物理服务器更稳。不过对大多数 Windows 上的 AI 开发者来说,WSL2 已经足够用,而且足够爽。
| 对比项 | WSL2 | 传统虚拟机(VMware/VirtualBox) |
|---|---|---|
| Linux 内核 | 定制原生内核 | 模拟硬件上的原生内核 |
| GPU 支持 | GPU 半虚拟化,CUDA 可用 | 很难透传 GPU,CUDA 基本不可用 |
| 启动速度 | 秒级 | 数十秒以上 |
| 与 Windows 文件互通 | 内置/mnt/c互通 | 需要配置共享文件夹 |
| AI 开发适合度 | 单卡训练/推理足够 | 不适合 GPU 任务 |
2. 环境搭建第一步:WSL2 安装与初始配置
2.1 系统要求与安装前的检查
WSL2 对系统有硬性要求,Windows 11 从发布起就是完整支持;Windows 10 需要 21H2 及以上版本,并且系统更新要打齐。CPU 需要支持 Hyper-V 虚拟化,对应 Intel 的 VT-x 或 AMD 的 SVM,大部分电脑默认开启,但如果之前装过虚拟机出过问题,建议先去 BIOS/UEFI 确认一下虚拟化开关。
正式安装前,打开“控制面板 - 程序 - 启用或关闭 Windows 功能”,确认“虚拟机平台”和“适用于 Linux 的 Windows 子系统”这两项处于开启状态。如果没开,勾选后重启系统。实际上运行wsl --install命令时系统会自动启用这些组件,只是部分老版本 Windows 需要手动操作,提前确认能少走弯路。
2.2 安装命令与版本模式确认
Windows 11 和较新的 Windows 10 走一条命令即可:
wsl --install -d Ubuntu-22.04执行过程大致是:安装 WSL2 内核、启用必要的 Windows 功能、下载并安装 Ubuntu 22.04 发行版。完成后重启系统,首次进入 Ubuntu 会让你设置用户名和密码,设置完之后你就有了一套干净的 Linux 环境。
如果你是从 WSL1 时代升上来的老用户,或者系统里已经装了某个发行版但模式不对,需要手动确认切换到 WSL2 模式:
wsl --set-default-version 2然后用wsl -l -v查看所有发行版的状态:
wsl -l -v正常输出如下,重点看 VERSION 列是否为 2:
NAME STATE VERSION * Ubuntu-22.04 Running 2如果 VERSION 显示是 1,说明还是 WSL1 模式,GPU 直通根本不可能启用。切换命令:
wsl --set-version Ubuntu-22.04 2这个转换过程可能需要几分钟,期间会自动下载 WSL2 内核和对应组件。
2.3 下载慢、卡进度和“尚未准备就绪”的解决方案
安装过程中最常遇到的就是下载问题。wsl --install执行时发行版和内核走的是微软官方分发渠道,网络一波动,就会长时间停在“正在下载”甚至直接失败。GitHub 和微软服务器在部分网络环境下的连接质量确实不稳定,这个没办法靠命令本身解决。
我试过有效的方案有三个。第一个,换个网络环境重试,手机热点有时候反而顺畅。第二个,手动下载离线安装包。在微软的 WSL 发行版页面找到对应版本的 tar 包或 Appx 包,然后用wsl --install --from-file <文件路径>安装。这个方法适合慢速网络,缺点是文件路径和版本要自己看清。第三个,处理内核更新问题,执行:
wsl --update wsl --shutdown然后再启动发行版。如果还是报错,排查顺序建议是:检查 Windows 功能里“虚拟机平台”是否开启、到 BIOS 确认虚拟化开关、最后看安全软件是否拦截了 WSL 相关组件。有些公司电脑装了第三方杀软,会把 WSL2 的基础运行组件拦掉,这种情况只能在安全软件里加放行规则。
3. GPU 直通的核心机制:Windows 驱动如何驱动 Linux 里的 CUDA
3.1 GPU 半虚拟化(GPU-PV)到底是怎么回事
先纠正一个常见误解:WSL2 里的 GPU 并不是传统意义上的“直通”。真正的 PCIe Passthrough 是把物理显卡整个设备直接分配给一个虚拟机独占,宿主机就没法再用它了。WSL2 用的是另一套机制,叫 GPU 半虚拟化(GPU Paravirtualization,简称 GPU-PV)。
原理可以这样理解:Windows 侧拥有完整的 GPU 驱动,直接管理物理显卡;WSL2 虚拟机的 Linux 内核中有一个虚拟设备接口(/dev/dxg),当 WSL2 里的 CUDA 程序发起 GPU 操作时,调用会通过这个虚拟设备转发到 Windows 侧的 GPU 驱动,由 Windows 驱动真正在硬件上执行。整个过程对用户完全透明。
这里最关键的信息是:WSL2 里的 Linux 根本不需要安装 NVIDIA 显卡驱动。我见过不少人被老教程误导,费劲在 WSL2 里装 Linux 版驱动,装上之后反而把 CUDA 环境搞坏。WSL2 的 CUDA 支持是微软和 NVIDIA 合作的产物,NVIDIA 把 WSL2 专用的 GPU 支持集成在了 Windows 版驱动里。换句话说,你要做的只是保证 Windows 侧的 NVIDIA 驱动处于较新版本,Linux 侧只需要装 CUDA Toolkit 和 cuDNN,不需要碰内核模块。
3.2 在 WSL2 里安装 CUDA Toolkit
既然 WSL2 里不需要显卡驱动,那 CUDA Toolkit 是怎么解决的呢?它作为用户态的编译器和运行时库,确实要装在 Linux 环境里。最简单的方式是添加 NVIDIA 官方的 WSL-Ubuntu 软件源:
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb sudo dpkg -i cuda-keyring_1.1-1_all.deb sudo apt-get update sudo apt-get -y install cuda装完以后,CUDA Toolkit 会被安装在/usr/local/cuda-12.x目录下。建议建立软链接统一路径:
sudo ln -s /usr/local/cuda-12.3 /usr/local/cuda然后把环境变量写进~/.bashrc或~/.zshrc:
export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH配置完执行source ~/.bashrc生效。注意一点:apt-get install cuda安装的是一个默认的完整版本,如果你需要特定版本(比如 11.8 或 12.1),可以用cuda-11-8这样的包名精确控制,避免高版本的 Toolkit 跟你使用的深度学习框架版本不兼容。
3.3 验证 GPU 是否真正被 CUDA 识别
安装完成后,验证环节绝对不能省。在 WSL2 终端里执行:
nvidia-smi如果环境正常,你会看到显卡型号、显存大小、驱动版本和当前的显存占用。注意输出顶部的 CUDA Version,它代表 Windows 驱动支持的最高 CUDA 版本,这个数字可能会比你后面安装的 Toolkit 版本高,这是正常的。实际程序用的 CUDA 运行时版本由 Toolkit 决定,两者不需要完全相等,只要 Toolkit 版本不高于驱动支持版本就行。
接着用 Python 验证一下:
python -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))"如果输出True和你的显卡名字,说明 PyTorch 已经成功走通了 WSL2 的 GPU 通路。这一步如果报Torch not compiled with CUDA enabled,说明你装的是 CPU 版 PyTorch,后面章节会展开说。
4. 深度学习框架落地:PyTorch GPU 版安装与首次训练验证
4.1 环境管理:conda 还是 pip
进入 PyTorch 安装之前,先解决 Python 环境管理的问题。我的建议是在 WSL2 里装 Miniconda 而不是 Anaconda。Anaconda 自带的几百个包大部分用不上,白白占磁盘和启动时间;Miniconda 只带 conda 和 Python,轻量干净。安装命令:
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh装完后创建一个独立的 AI 开发环境:
conda create -n ai python=3.11 conda activate ai用 conda 的好处是环境隔离干净、切换快捷。PyTorch 这类带大量 C 扩展的框架,用 conda 安装通常最省心;纯 Python 的 Web 项目用 venv+pip 也完全够用。在 WSL2 里两者都能正常工作,按你的习惯选一套即可,但别在一个项目里混用两套环境管理工具,容易导致依赖错乱。
4.2 安装 PyTorch:先对好 CUDA 版本
PyTorch GPU 版安装最大的坑就是 CUDA 版本对不上。这里给个原则:用官方推荐的安装命令,不要直接在默认源里pip install torch。PyPI 默认的 torch 包是 CPU 版,装完跑了半天才发现训练没用 GPU,那才叫浪费时间。
去 PyTorch 官网的 Get Started 页面,它会根据你的系统给出具体命令。以 CUDA 12.1 为例:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121conda 方式则用:
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia安装前先拿nvidia-smi看看驱动支持的最高 CUDA 版本,然后选择等于或低于这个版本的 PyTorch 构建。比如驱动显示支持 CUDA 12.4,你用 cu121 完全没问题;想用 cu124 也行,但要确认 PyTorch 官方提供对应的 wheel 包。
安装完验证一下安装结果:
python -c "import torch; print('Torch version:', torch.__version__); print('CUDA available:', torch.cuda.is_available()); print('GPU:', torch.cuda.get_device_name(0))"我机器上输出的是:
Torch version: 2.3.1+cu121 CUDA available: True GPU: NVIDIA GeForce RTX 4090看到这样的结果,环境就算立住了。
4.3 跑一段真实的训练代码,确认 GPU 真的在干活
有些教程到“打印 GPU 名称”就结束了,但我会劝你多做一步:跑一个真正的训练脚本,确认 CUDA 不但可用,而且是真的在加速计算。下面是一个很轻量的 MNIST 分类训练脚本,不用太多轮次,几分钟就能跑完验证:
import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision import datasets, transforms device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(f'Using device: {device}') transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) train_set = datasets.MNIST(root='./data', train=True, download=True, transform=transform) train_loader = DataLoader(train_set, batch_size=256, shuffle=True, num_workers=4) class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv = nn.Sequential( nn.Conv2d(1, 32, 3, 1), nn.ReLU(), nn.MaxPool2d(2, 2), nn.Conv2d(32, 64, 3, 1), nn.ReLU(), nn.MaxPool2d(2, 2), ) self.fc = nn.Linear(64 * 4 * 4, 10) def forward(self, x): x = self.conv(x) x = x.view(x.size(0), -1) return self.fc(x) model = SimpleCNN().to(device) optimizer = optim.Adam(model.parameters(), lr=0.001) loss_fn = nn.CrossEntropyLoss() for epoch in range(3): model.train() total_loss = 0 for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() output = model(images) loss = loss_fn(output, labels) loss.backward() optimizer.step() total_loss += loss.item() print(f'Epoch {epoch+1}, Loss: {total_loss / len(train_loader):.4f}')跑之前先确认两件事:数据集下载是否顺畅(如果下载慢,手动把 MNIST 文件放到./data目录下),以及num_workers是否设置合理。训练过程中打开 Windows 任务管理器,切到“性能 - GPU”,观察专用 GPU 内存和 CUDA 利用率。如果 CUDA 利用率持续在 90% 以上,说明 GPU 是真的在工作。这里注意一个小细节:Windows 任务管理器默认展示的是 3D/DX 图形引擎的占用,CUDA 计算负载要单独看 CUDA 那一列,如果你发现 3D 利用率不高但 CUDA 接近满载,那是正常的。
4.4 顺便说下 TensorFlow 的安装
默认首选是 PyTorch,但有些项目必须用 TensorFlow。TensorFlow 的 GPU 支持在较新版本中已经合并进了主包,不需要再单独装tensorflow-gpu:
pip install tensorflow装完同样验证一下:
import tensorflow as tf print(tf.config.list_physical_devices('GPU'))TensorFlow 在 WSL2 里遇到过一些内存分配的问题,常见报错是显存分配失败,原因是 TensorFlow 默认会预先占满全部显存。设置允许增长可以缓解:
physical_devices = tf.config.list_physical_devices('GPU') tf.config.experimental.set_memory_growth(physical_devices[0], True)这个设置在有其他图形应用共享显卡的场景下几乎必用,否则一跑训练,Windows 桌面先卡成幻灯片。
5. 磁盘、网络与开发体验调优:把 WSL2 调整到顺手状态
5.1 把 WSL2 发行版迁移到 D 盘
WSL2 的虚拟磁盘文件默认在 C 盘,路径形如C:\Users\<用户名>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu...\LocalState\ext4.vhdx。装了深度学习环境之后,这个文件会迅速膨胀:一个 Ubuntu 发行版加 conda 环境、CUDA Toolkit、数据集,轻轻松松 50GB 以上。C 盘吃紧的话,建议第一时间把发行版迁走。
老而稳的方法是导出再导入:
wsl --shutdown wsl --export Ubuntu-22.04 D:\wsl-backup\ubuntu-22.04.tar wsl --import Ubuntu-22.04-D D:\wsl\Ubuntu-22.04\ D:\wsl-backup\ubuntu-22.04.tar注意导入后注册的是一个新发行版名称(这里是 Ubuntu-22.04-D),默认用户会变成 root,可以用ubuntu2204.exe config --default-user 你的用户名恢复默认用户。新一代 Windows 11 有更直接的迁移命令:
wsl --manage Ubuntu-22.04 --move D:\wsl\Ubuntu-22.04这种方式不需要导出导入,直接把 vhdx 文件搬过去,所有配置和用户都原样保留。迁移完先确认新发行版能正常启动,再删旧的释放空间:wsl --unregister Ubuntu-22.04。注意--unregister会彻底删除该发行版的所有数据,执行前务必确认旧发行版已经不需要了。
5.2 跨文件系统性能的坑:为什么不能在/mnt/c下跑训练
WSL2 内部使用 ext4 文件系统,Windows 侧是 NTFS,两边通过 9P 协议互通。也就是说,你在 WSL2 里访问/mnt/c或/mnt/d下的文件,本质上走的是网络协议式的文件共享,速度远不如直接操作 Linux 文件系统内的文件。
这个性能差异在 AI 开发里是致命的。举个实测数据:同样是读取 10 万张图片的数据集,放在/mnt/d/dataset时每个 epoch 耗时接近 3 分钟,放到~/dataset之后降到 1 分 40 秒左右,速度提升了将近一半。原因是大量小文件的随机读场景下,9P 协议的吞吐和延迟都远不如本地 ext4。
所以我的原则很简单:代码、conda 环境、数据集全部放在 WSL2 的 Linux 文件系统内,也就是~/下面。如果你需要从 Windows 侧同步数据,用rsync之类的工具定时同步到 Linux 文件系统内,再跑训练,而不是直接在/mnt/c路径下工作。这一步做不做,差距是肉眼可见的。
5.3 用.wslconfig控制内存、CPU 和 swap
WSL2 的默认内存上限是宿主总内存的 50%,这个设置在 16GB 机器上经常导致两边都不够用。我通常的做法是在 Windows 用户目录下创建.wslconfig文件,内容示例:
[wsl2] memory=24GB processors=8 swap=8GB localhostForwarding=truememory是 WSL2 可用的最大内存,processors是逻辑 CPU 核数,swap是交换分区大小。设置完成后执行wsl --shutdown再重新启动,配置才生效。注意不要把所有内存都塞给 WSL2,Windows 本体、浏览器、IDE 也要吃内存,留足余量比纯堆 WSL2 内存更重要。我见过有人把 32GB 机器设成memory=28GB,结果 Windows 端先卡出天际,又回头调。
localhostForwarding=true可以让 WSL2 里的服务通过localhost从 Windows 侧访问,对调试 Flask、Jupyter、TensorBoard 这类开发服务非常方便。启动 Jupyter 后直接在 Windows 浏览器里开http://localhost:8888就能访问,不需要额外配置。
5.4 用一个 WSL2 跑多个发行版做环境隔离
WSL2 支持一个系统里同时存在多个 Linux 发行版,每个发行版是独立实例,不共享文件系统。这很适合做隔离测试:比如 Ubuntu 里放 PyTorch 主力环境,Debian 里做数据处理工具链测试,互不干扰。多发行版的操作非常简单,继续用wsl --install -d Debian就能添加。
不同的发行版可以通过wsl --set-default指定默认启动项。Windows Terminal 对 WSL 多标签的支持也很好,建议所有 WSL2 用户把默认终端换成 Windows Terminal,尤其是用 Vim、Tmux 或者看长日志的时候,渲染流畅度和操作手感比老 console 窗口好太多。
6. 实战踩坑记录:从启动失败到显存抢占的完整排查链路
6.1 WSL2 启动不了、一直转圈怎么办
有一次 Windows 系统更新后,WSL2 突然启动不了,执行wsl后卡在启动界面转圈,或者直接弹“尚未准备就绪”。排查过程我复盘一下,给同样遇到这个问题的朋友一个缩略版的排查链路:
第一步,执行wsl --shutdown强制关闭所有 WSL 实例。很多时候不是系统坏了,而是残留的 WSL 进程占着资源,新开的实例进不去。第二步,执行wsl --update更新 WSL2 内核和组件。第三步,检查“虚拟机平台”和“适用于 Linux 的 Windows 子系统”功能是否被关闭,某些安全软件会把相关的 Windows 功能项禁用。第四步,管理员 PowerShell 里执行bcdedit /set hypervisorlaunchtype auto,确保 Hyper-V 引导类型是自动。第五步,如果还是不行,去 BIOS 确认虚拟化开关还在,有可能是误触关掉了。
还有一个隐藏原因,某次我排查了半天发现是显卡驱动太老导致 WSL2 内核升级后蓝屏重启。从那以后我养成一个习惯:每次更新 WSL2 内核或 Windows 大版本之前,先去 NVIDIA 官网装最新的显卡驱动。Windows 更新和显卡驱动的兼容性组合是玄学,提前更新驱动能少踩一大半坑。
6.2 显卡驱动更新后 CUDA 版本不匹配
Windows 侧 NVIDIA 驱动更新后,偶尔会碰到 WSL2 里 CUDA 程序报 “CUDA error: no kernel image is available” 或 “libcuda.so.1 cannot open shared object file”。原因在于 Windows 驱动里的 WSL2 CUDA 模块被更新到新版本,而 Linux 侧安装的 CUDA Toolkit 停留在旧版本,两边衔不上。
解法也不复杂:更新 Windows 侧驱动后,同步升级 WSL2 里的 CUDA Toolkit:
sudo apt-get update sudo apt-get -y install --only-upgrade cuda如果升级后默认的/usr/local/cuda软链接还指向旧目录,手动改一下软链接或者PATH环境变量。我遇到过更隐蔽的坑:有人在~/.bashrc里写死了/usr/local/cuda-11.x/bin,升级后没改路径,导致命令行用的是新版本,但 Python 运行时调的还是旧库。排查时第一步就是打印which nvcc、nvcc -V,确认实际调用的版本路径,再往里查。
6.3 显存被抢占和 OOM 的奇怪表现
WSL2 的显存管理有个跟原生 Linux 不太一样的地方。跑训练跑到一半突然报CUDA out of memory,但nvidia-smi里显存明明还有空闲,这种情况我在 WSL2 上遇到过好几次。后来大致摸清了原因:Windows 侧的桌面合成器(DWM)、浏览器硬件加速、直播软件等进程会占用一部分显存,这些显存在nvidia-smi里不一定看得那么直观;而 CUDA 在 WSL2 中的内存映射策略有时候会触发意外的系统内存分配,报错信息表达得不够明确。
排查手段是用nvidia-smi dmon实时看 GPU 内存占用曲线,或者看 OOM 报错时具体说的是显存不足还是 host 内存不足。如果是显存不足,就得在 Windows 侧关掉一些占用显存的应用,再跑训练。这个坑在 WSL2 上比原生 Linux 更容易踩到,毕竟 Windows 桌面本身就是一大堆图形进程,对显存的需求不少。解决办法就两个:升级显卡容量,或者调低 batch size。跑大模型的时候还要留意同一个 GPU 上的其他进程——用CUDA_VISIBLE_DEVICES给每个任务单独指定 GPU,避免默认全部打到 0 号 GPU 上瞬间爆显存。
6.4 本地跑大模型微调与 Agent 工作流的性能观察
在 WSL2 上做 LoRA 微调和跑推理,是我目前用得最多的场景。以单卡 RTX 4090 为例,用 LoRA 方式微调 7B 左右的模型,WSL2 和原生 Linux 的差距几乎可以忽略,训练耗时差别在几个百分点以内。推理侧也没什么问题,加载量化后的模型做对话、代码分析,响应速度都很正常,基本看不到虚拟化层的开销。
不过多 Agent 并发要对显存做严格规划。我试过同时跑 3 个本地模型 Agent 处理任务,如果都用默认配置,3 个进程会抢同一个 GPU,直接 OOM。后来给每个 Agent 设置独立的CUDA_VISIBLE_DEVICES,并且在代码里限制每个进程的显存占用上限,问题才解决。如果你打算在 WSL2 上跑 Agent 工作流,记得在程序设计上把显存规划放到第一位。
还有两个小习惯非常有价值,分享给你。第一,在 WSL2 里跑超过几小时的训练任务,务必用screen或tmux把任务挂在后台,这样即使 Windows Terminal 窗口被关闭,任务也不会中断。第二,Windows 更新有时会直接重启系统,把训练中断。我一般会去系统设置里把自动更新的“重启时间”尽量往后拖,或者干脆用“专注助手”避开训练时段。这两个看似不起眼的细节,能帮你避免很多次训练进度清零的崩溃瞬间。
整套 WSL2 + CUDA + PyTorch 的环境跑通之后,有一个让我特别安心的特性就是它的备份恢复非常方便。整个 Linux 文件系统都在一个 vhdx 文件里,我定期会做一次导出快照,万一环境被搞崩,几分钟内就能恢复到可用状态。如果你也准备长期在 WSL2 里搞 AI 开发,强烈建议养成这个习惯。最后说一句个人体会:真正让开发效率提升的不是跑通 PyTorch 的那一瞬间,而是在折腾环境的过程中积累下来的排查思路——现在看到CUDA out of memory,我已经能第一时间判断是显存真的不够,还是 Windows 桌面的图形进程抢占了资源,这种“心里有数”的感觉,比任何现成教程都值钱。