在 WSL 里做 AI 开发:GPU、CUDA、模型缓存和文件 IO 的坑
原创 · 约 21 分钟阅读 · 阅读 --

在 WSL 里做 AI 开发:GPU、CUDA、模型缓存和文件 IO 的坑

作者: Alex Xiang


古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。更完整的更新写在微信公众号「字与码」:工作经历、对新技术的想法,以及这些年走弯路的记录,会不定期发在那里。若觉得博客对你有用,欢迎顺手关注。

WSL 做 AI 开发最舒服的地方,是你可以用 Linux 生态里的 Python、CUDA、PyTorch、向量库、编译工具,又不用离开 Windows 桌面。最不舒服的地方也差不多:显卡驱动在 Windows,CUDA 在 WSL,模型缓存可能在 Linux,也可能被你放到了 Windows 分区,Docker 又可能再套一层。

很多“GPU 没生效”的问题,不是模型问题,而是边界没理清。

WSL 里的 GPU、CUDA 与本地模型开发环境

这篇不追求把所有 AI 框架都装一遍。我们只用一个可复制的场景:在 WSL 里确认 NVIDIA GPU 可见,跑一个 PyTorch 小测试,再跑一个本地模型服务,最后把模型缓存、Docker 和文件 IO 的坑讲清楚。

先确认 GPU 是从 Windows 驱动过来的

WSL 里的 NVIDIA CUDA 不是传统虚拟机里的 PCIe 直通。你不应该在 Ubuntu 里安装完整的 Linux NVIDIA 显卡驱动。正确的路径是:Windows 安装支持 WSL 的 NVIDIA 驱动,WSL 里通过暴露出来的 CUDA 接口使用 GPU。

Microsoft 的文档把第一步写得很明确:先在 Windows 侧安装 NVIDIA CUDA enabled driver for WSL。NVIDIA 的 CUDA on WSL 文档也强调,这套工作流是让 CUDA 应用和容器在 WSL2 环境里运行。

在 WSL 里先看:

nvidia-smi

如果能看到显卡、驱动版本、显存占用,说明最基础的桥通了。

如果命令不存在或报错,不要急着在 Ubuntu 里乱装驱动。先回到 Windows 检查:

nvidia-smi
wsl --version
wsl --update
wsl --shutdown

再重进 WSL。

我会把第一层检查写成一个小脚本:

cat > check-wsl-gpu.sh <<'SH'
set -e
echo "== WSL =="
uname -a
echo
echo "== NVIDIA =="
nvidia-smi
echo
echo "== CUDA libraries =="
ls -l /usr/lib/wsl/lib/libcuda.so* 2>/dev/null || true
SH

bash check-wsl-gpu.sh

这个脚本不负责修复,只负责回答一个问题:WSL 是否能看到 Windows 驱动暴露出来的 GPU 能力。

PyTorch 测试不要直接上大模型

很多人一上来就跑本地大模型,失败后日志滚一屏,很难看出是 CUDA 问题、依赖问题还是模型问题。先跑最小 PyTorch 测试。

用一个干净环境:

mkdir -p ~/work/wsl-gpu-check
cd ~/work/wsl-gpu-check
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

安装 PyTorch 时要按官方页面选择匹配的 CUDA 版本。这里不要抄固定命令,因为 PyTorch 的安装索引和 CUDA 版本会变化。装完后跑:

import torch

print("torch:", torch.__version__)
print("cuda available:", torch.cuda.is_available())
print("device count:", torch.cuda.device_count())

if torch.cuda.is_available():
    print("device:", torch.cuda.get_device_name(0))
    x = torch.randn(4096, 4096, device="cuda")
    y = x @ x
    torch.cuda.synchronize()
    print(float(y[0, 0]))

保存为 check_torch_cuda.py

python check_torch_cuda.py

同时另开一个 WSL 窗口:

watch -n 0.5 nvidia-smi

如果 torch.cuda.is_available()True,而 nvidia-smi 里能看到 Python 进程短暂占用显存,说明 PyTorch 这层基本没问题。接下来再谈模型。

模型缓存放哪,比你想象中重要

AI 开发里,模型文件往往比代码大得多。一个 7B 量化模型几 GB,一个多模态模型十几 GB,Hugging Face 缓存、Ollama 模型、向量索引、数据集,很快把磁盘吃满。

我不建议把模型缓存放到 /mnt/c/Users/... 再从 WSL 读取。原因和前面几篇一样:高频读取、大文件 mmap、小文件 tokenizer 配置、索引文件,会不断跨 Windows/WSL 边界。

更稳的做法是把项目和模型缓存都放 WSL 文件系统:

mkdir -p ~/models
mkdir -p ~/datasets
mkdir -p ~/work/ai-lab

Hugging Face 可以设置:

export HF_HOME="$HOME/models/huggingface"
export TRANSFORMERS_CACHE="$HF_HOME/transformers"
export HF_DATASETS_CACHE="$HOME/datasets/huggingface"

写进 ~/.bashrc 或项目的 .envrc 前,先确认团队约定。模型缓存路径一旦散落,清理会很痛苦。

Ollama 在 Windows 和 WSL 都能跑。官方 Windows 文档里说,Windows 版 Ollama 会作为原生应用运行,API 默认在 http://localhost:11434。如果你已经主要在 Windows 桌面用模型,Windows 版更省心。如果你的脚本、数据处理、评估工具都在 WSL,WSL 里跑 Ollama 也合理。

关键是不要同时跑两套还共用同一批模型目录。模型目录应该有明确归属。

本地模型服务:先看 API,再看显存

假设你在 WSL 里跑 Ollama:

curl -fsSL https://ollama.com/install.sh | sh
ollama serve

另一个窗口:

ollama pull qwen2.5:7b
ollama run qwen2.5:7b "用一句话解释 WSL"

先不要写复杂 agent。只测试三件事:

curl http://localhost:11434/api/tags

确认 API 通。

nvidia-smi

确认模型运行时显存确实变化。

du -sh ~/.ollama 2>/dev/null || true

确认模型落在哪。

如果 Windows 里也有程序要访问 WSL 里的 Ollama,先看当前网络模式。NAT 模式下,Windows 访问 WSL 服务通常可以用 localhost;mirrored 模式下 localhost 互通更直观。但服务自身也要监听正确地址。有些服务默认只监听 127.0.0.1,有些可以配置 OLLAMA_HOST=0.0.0.0:11434

这里的安全边界要想清楚。本地模型 API 如果监听 0.0.0.0,可能不只 Windows 能访问,局域网也可能访问。不要为了图省事把模型服务暴露给整个网络。

Docker 里的 GPU:多一层就多一层排障

本地 AI 开发常常会用 Docker。WSL + Docker + GPU 这条链路可以跑,但排障要分层。

先确认 WSL 宿主能看到 GPU:

nvidia-smi

再确认容器能看到 GPU。Docker Desktop 和 NVIDIA Container Toolkit 的支持状态会随版本变化,具体以当前官方文档为准。常见测试命令类似:

docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

如果宿主能看到 GPU,容器看不到,问题在 Docker GPU runtime,不在 PyTorch。

如果容器能看到 GPU,PyTorch 看不到,再看镜像里的 CUDA/PyTorch 版本。

如果 PyTorch 能看到 GPU,模型仍然跑 CPU,再看模型框架自己的加载参数。有些库需要显式传:

device_map="cuda"

或者:

model.to("cuda")

不要把所有问题都归成“WSL 没配好”。WSL 只是第一层。

文件 IO:训练小模型和跑推理不是一回事

推理时,模型加载阶段吃磁盘,运行阶段主要吃显存和内存。训练或微调时,数据读取会持续影响性能。

如果你把数据集放在 /mnt/d/datasets,训练脚本在 WSL 里跑,就会持续跨边界读取。图片数据集、小 parquet 文件、tokenized shard,都会放大这个成本。

我会这样安排:

~/work/ai-lab/          # 代码
~/models/               # 模型权重
~/datasets/             # 训练/评估数据
~/runs/                 # 实验输出
/mnt/d/archive/          # 冷备份,不直接训练读取

训练前可以用 rsync 从 Windows 分区或移动硬盘同步一份到 WSL:

rsync -av --info=progress2 /mnt/d/datasets/my-set/ ~/datasets/my-set/

实验结束后再把结果归档出去:

rsync -av ~/runs/exp-2026-06-21/ /mnt/d/archive/ai-runs/exp-2026-06-21/

不要让训练脚本每一步都从 Windows 分区读。

显存不够时,先控制问题规模

WSL 不会帮你变出更多显存。8GB 显存就是 8GB,最多靠量化、offload、batch size、上下文长度、模型大小做取舍。

排查显存时,先收集:

nvidia-smi
free -h
df -h

再看模型参数:

  • 模型大小;
  • 量化格式;
  • context length;
  • batch size;
  • 是否启用 KV cache;
  • 是否 CPU/GPU 混合 offload;
  • 是否同时跑了浏览器、游戏、视频会议、另一个模型服务。

Windows 桌面也会占 GPU。你在 WSL 里看 nvidia-smi,看到的不是一块“只给 Linux 的显卡”,而是和 Windows 共享的设备。开发机上开着浏览器硬件加速、视频会议、另一个推理服务,都会影响剩余显存。

我推荐的一套最小自检

把这些命令放进项目 README:

# 1. WSL 能看到 GPU
nvidia-smi

# 2. Python 能看到 CUDA
python - <<'PY'
import torch
print(torch.__version__)
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "cpu")
PY

# 3. 模型缓存路径
echo "HF_HOME=$HF_HOME"
du -sh "$HF_HOME" 2>/dev/null || true

# 4. 本地模型 API
curl -s http://localhost:11434/api/tags | head

# 5. 文件位置
pwd
df -T .

这套检查覆盖五层:驱动、框架、模型缓存、服务 API、文件系统。一次性讲清楚,团队新人就不需要在“CUDA 版本”“WSL 版本”“模型路径”“代理问题”之间来回猜。

我现在怎么取舍 Windows 原生和 WSL

如果只是聊天、临时跑几个模型,Windows 原生 Ollama 更简单。安装完就有后台服务,Windows 程序访问也自然。

如果要写 Python 脚本、跑评估、做向量索引、编译依赖、接 Linux 工具链,我会放到 WSL。代码、模型、数据都在 WSL 文件系统,Windows 只负责浏览器、编辑器、聊天工具和偶尔的文件查看。

如果要上生产,我不会因为本地 WSL 跑通就认为 Linux 服务器一定一样。WSL 是很好的开发环境,但它的 GPU、文件系统、网络、systemd、Docker 都有自己的边界。上线前仍然要在目标 Linux 环境里做一次完整验证。

参考资料