简介:面向希望在本地私有化运行 DeepSeek 的开发者与企业运维团队,这份 PDF 围绕硬件选型、系统环境搭建与依赖配置给出可落地的部署参考,覆盖个人开发测试到企业生产集群的不同规模场景。内容按模型参数量分级列出处理器、显卡显存、内存、存储与网络配置建议,并延伸到 Ubuntu/Windows 环境准备、CUDA 与 cuDNN 验证、PyTorch 定制安装、分布式训练参数,以及 4-bit 量化加载、显存分级卸载和 DCGM/PyTorch Profiler 监控调优等关键环节;同时给出最低要求与推荐配置的对照、显存估算经验、常用命令和配置片段,便于读者按目录快速定位所需配置与排错方向。包内共 1 个 PDF 文件,约 274KB,篇幅紧凑、便于随取随查。目前已有 2219 人学习,适合需要评估本地部署可行性、规划硬件预算或搭建实验环境的中高级读者参考,也可供技术负责人做方案对比与资源评估。
1. 显卡明明在,torch.cuda.is_available() 却返回 False
做 DeepSeek 本地部署的人,十个里有八个会在第一个晚上撞上同一堵墙:nvidia-smi把显卡型号、显存、驱动版本列得明明白白,进到 Python 敲一句torch.cuda.is_available(),返回的偏偏是 False。硬件要求对照着清单买齐了,环境配置的文档也翻了三遍,卡还是用不上。
这类故障最让人难受的地方是它不告诉你错在哪:没有堆栈、没有红色报错,只有一个 False。往下走还会引发一连串问题——4-bit 量化加载报 “no GPU device was found”,FlashAttention 装完 import 就崩,多卡启动卡在 NCCL init 一动不动。新手会怀疑显卡坏了,老手知道八成是版本没对上。
这篇按“报错现象 → 根因 → 命令 → 怎么避免”的顺序,把本地部署里最容易失败的几处逐个拆开:显存怎么算、量化怎么配、编译参数怎么填、多卡为什么不说话。适合第一次上机的人,也适合已经在集群里反复处理过多次故障的人。
2. torch.cuda.is_available() 返回 False:驱动、运行时、框架三层对齐
2.1 三层版本各管一段,混着看就永远对不上
几乎所有“显卡看不见”的问题,根子都在把三个不同的版本号当成一个东西。第一层是驱动,nvidia-smi右上角那个CUDA Version说的是“这块驱动最高能支持到哪个 CUDA 运行时”,不是你装了什么。第二层是CUDA 运行时 / Toolkit,nvcc --version输出的才是真正躺在/usr/local/cuda-*里的那套。第三层是PyTorch 编译时链接的 CUDA 版本,用torch.version.cuda看。
关键规则只有一条:驱动支持的上限 ≥ PyTorch 编译版本,并不要求三者完全相等。比如驱动支持到 12.4,你装 cu121 的轮子完全没问题;反过来驱动只到 11.8,你硬装 cu121 的 PyTorch,is_available()就会老老实实返回 False。很多人一看版本号不一致就重装驱动,白折腾一晚上,其实只是 torch 装成了 CPU 轮子。
还有一层容易被忽略:cuDNN 是由 PyTorch 轮子自带、跟 CUDA 版本绑定的。系统里另外装一份 cuDNN 并塞进LD_LIBRARY_PATH,反而可能让 torch 加载到不匹配的.so,症状是is_available()为 True 但一跑前向就段错误。我一般不去动系统 cuDNN,需要哪个版本交给轮子自己管。
2.2 三条命令定位断在哪一层
不要一上来就重装。先花三十秒把三层信息一次性打出来,看断点落在哪儿。
# 第一层:驱动能支持到的最高 CUDA 版本 nvidia-smi # 第二层:实际安装的 CUDA Toolkit(没装过就是 command not found,属正常) nvcc --version # 第三层:PyTorch 编译时链接的 CUDA 版本与设备可见性 python -c " import torch print('torch :', torch.__version__) print('torch cuda :', torch.version.cuda) print('available :', torch.cuda.is_available()) print('device cnt :', torch.cuda.device_count()) "逻辑说明:nvidia-smi证明驱动加载成功、内核模块正常;torch.version.cuda为None就是装成了纯 CPU 轮子,这是最常见的元凶;device_count()返回 0 而is_available()为 True,说明驱动和框架都对,但设备被CUDA_VISIBLE_DEVICES屏蔽了。
参数说明:CUDA_VISIBLE_DEVICES是排查时必看的变量。有人为了多卡隔离在~/.bashrc里写了CUDA_VISIBLE_DEVICES=0,后来换成索引为 2 的卡,程序就一直“看不见显卡”。排查时先echo $CUDA_VISIBLE_DEVICES确认一下。
常见组合与对应根因:
| nvidia-smi | torch.version.cuda | is_available | 根因 |
|---|---|---|---|
| 正常显示 | None | False | 装了 CPU 轮子 |
| 正常显示 | 12.1 | False | 驱动版本低于运行时要求 |
| 正常显示 | 12.1 | True 但 count=0 | 环境变量屏蔽了设备 |
| command not found | 12.1 | False | 驱动没装或内核模块未加载 |
| 正常显示 | 12.1 | True 但一跑就崩 | cuDNN 冲突或显存被占 |
2.3 重装匹配的 PyTorch 轮子
确认是 CPU 轮子之后,卸载要干净,别只pip install --upgrade,那样容易留下新旧混杂的.so。
# 三个包必须一起卸,版本不匹配是另一个高频坑 pip uninstall -y torch torchvision torchaudio # 显式指定 cu121 索引源,避免解析到 CPU 版本 pip install torch==2.1.0+cu121 \ --extra-index-url https://download.pytorch.org/whl/cu121 # 复验:三个值都要正确 python -c " import torch print(torch.__version__, torch.version.cuda, torch.cuda.is_available()) "逻辑说明:+cu121这个本地版本号后缀是关键,它把轮子和纯 CPU 包区分开;--extra-index-url让 pip 去官方轮子仓库找带 CUDA 的构建。只写pip install torch时,最终装到哪个变体取决于平台和源,这就是有人机器上一次就成、有人怎么装都是 CPU 版的原因。
参数说明:如果项目锁定了别的框架版本,把2.1.0+cu121换成对应组合即可,原则是cuXXX不高于驱动支持上限。装完不要急着跑模型,先用一个小张量做一次真实计算,确认不是“能看见但算不了”:
import torch # 真跑一次矩阵乘,比 is_available 更能暴露驱动/内核问题 x = torch.randn(1024, 1024, device="cuda", dtype=torch.bfloat16) y = x @ x torch.cuda.synchronize() print(y.shape, torch.cuda.get_device_name(0))2.4 cuDNN 校验:版本号对了才算真通
is_available()只说明 CUDA 运行时通了,卷积、注意力这些算子还要过 cuDNN 这一关。
import torch print(torch.backends.cudnn.is_available()) # 应为 True print(torch.backends.cudnn.version()) # 应 >= 8902 print(torch.backends.cudnn.enabled) # 应为 True逻辑说明:version()返回的是编译进轮子的 cuDNN 版本号,不是系统里的。数字对不上 8902 这条线,FlashAttention、部分量化算子会在运行时抛 “no kernel image is available”。
参数说明:如果is_available()为 False,先确认不是被torch.backends.cudnn.enabled = False手动关掉了——有些为了复现性关掉它的脚本会一直留着这行。真是版本问题,正确做法是换 PyTorch 轮子,而不是单独装系统 cuDNN,两套.so抢加载顺序的结果通常更难查。
2.5 Windows 加 WSL2:多出来的一层,坑也最多
Windows 上跑本地部署,正规路径是 WSL2 里装 Ubuntu,显卡驱动只装在 Windows 侧。WSL2 内部再装一遍 Linux 驱动,nvidia-smi会直接报错或者返回空设备列表。
需要对齐的组件:Windows 11 Pro 22H2 及以上、WSL2 内的 Ubuntu 20.04 LTS、DirectX 12 Ultimate 运行时、NVIDIA 驱动 535.54.03 以上。四样缺一样,症状都差不多——WSL 里nvidia-smi命令存在但看不到卡。
# 在 Windows 侧执行,把 WSL 内核升到支持 GPU 的版本 wsl --update # 进入 WSL 后验证,这一步能看到卡才算打通 nvidia-smi # 能看到卡之后再验框架,顺序不能反 python -c "import torch; print(torch.cuda.is_available())"逻辑说明:WSL2 的 CUDA 支持由 Windows 驱动通过/dev/dxg透传,WSL 内不需要nvidia.ko。所以 WSL 里lsmod | grep nvidia什么都没有是正常现象,别拿这个判断故障。
参数说明:wsl --update更新的是 WSL 内核本身,老版本内核不支持 GPU 直通,表现就是设备节点缺失。执行完要wsl --shutdown重启一次再验证,否则旧内核还在跑。这套环境下显存是由 Windows 侧统一管理的,nvidia-smi显示的占用会包含桌面程序,排查 OOM 时容易误判,后面第 3 章会专门说。
3. CUDA out of memory:先算清楚显存需求,再决定量化还是卸载
3.1 显存实际被哪些部分占用
CUDA out of memory是本地部署里出现频率最高的报错,也是最容易误判的。很多人看到它第一反应是“模型太大,卡不够”,于是去加卡,结果 80GB 的卡照样爆。
按工程上常用的粗略估算方式,FP16 精度下每 10 亿参数约占 1.2GB 显存。这个数字不是纯数学换算,它已经把加载时的临时张量、部分框架开销算进去了。32B 模型落在 38GB 上下,A100 80GB 单卡放权重绰绰有余。那为什么还会 OOM?因为权重只是常住人口,真正把显存吃光的是流动人口:
| 占用项 | 随什么增长 | 典型量级 |
|---|---|---|
| 模型权重 | 参数量 × 精度 | 32B FP16 约 38GB |
| KV Cache | 并发数 × 上下文长度 | 长上下文下可超过权重 |
| 中间激活 | batch × 序列长度 | 训练时占比高,推理较小 |
| 显存碎片 | 反复分配释放 | 长跑服务里能吃掉几个 GB |
把这张表记住,排查顺序就出来了:先看是权重一次性放不下,还是跑到一半才慢慢涨上去。前者要量化,后者要控并发和上下文。
3.2 先区分是权重 OOM 还是 KV OOM
这一步决定了后面所有方案的方向,判断方法很土但很准:启动后立刻nvidia-smi -l 1盯着。
# 每秒刷新一次显存占用,观察曲线形态 nvidia-smi --query-gpu=memory.used,memory.total \ --format=csv -l 1逻辑说明:如果进程刚加载完模型显存就顶到天花板,说明权重本身放不下,走量化路线;如果加载完只占了六成,请求进来之后一路爬升直到 OOM,那是 KV Cache 在涨,量化救不了多少,得从并发数和max_new_tokens下手。
参数说明:-l 1是刷新间隔秒数,排查时用 1 秒够用;正式压测可以改 0.2,但输出会很密。真正比总量更有价值的是碎片量——memory_reserved减memory_allocated的差值,差值持续变大说明有内存泄漏或变长序列导致的反复分配。
3.3 4-bit 量化:把 32B 压缩到单卡能放下的范围
权重放不下时,量化是成本最低的一步。NF4 量化能把 32B 模型压到 20GB 以内,单张 24GB 卡就能跑起来。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig import torch # 4-bit 量化配置:nf4 + 双重量化 + bf16 计算精度 bnb_config = BitsAndBytesConfig( load_in_4bit=True, # 权重以 4bit 存储 bnb_4bit_use_double_quant=True, # 对量化常数再量化一次,省约 0.4bit/参数 bnb_4bit_quant_type="nf4", # 正态分布友好的 4bit 格式 bnb_4bit_compute_dtype=torch.bfloat16, # 计算时反量化到 bf16,兼顾速度与精度 ) model = AutoModelForCausalLM.from_pretrained( "/opt/deepseek/models/deepseek-32b", quantization_config=bnb_config, device_map="auto", # 自动切分到多卡/CPU low_cpu_mem_usage=True, )逻辑说明:nf4是专门为正态分布权重设计的 4bit 表示,实测比对称 int4 的精度损失小;double_quant把每组的缩放系数再压一遍,32B 模型能再省出 1GB 多;compute_dtype决定反量化后用什幺精度做矩阵乘,选bfloat16而不是float16,是因为大模型激活值范围宽,fp16 容易溢出成 inf 然后输出全是nan。
参数说明:device_map="auto"依赖 accelerate,会根据每张卡的剩余显存自动切层。显存紧张时可以用更精细的写法device_map="balanced_low_0",把更多层堆到非 0 号卡上,0 号卡留给显示输出。注意开了量化之后不能再做全参数训练,只能走 LoRA 这类微调,否则反传梯度会直接崩。
3.4 量化后仍然 OOM:激活检查点与分级卸载
量化解决的是权重的静态占用,如果显存还是不够,说明问题在动态部分。这时要启用激活检查点,用时间换空间。
# 用计算换显存:不保存中间激活,反向传播时重算 model.gradient_checkpointing_enable() # 输入侧同步压缩:加载时不做完整拷贝 model = AutoModelForCausalLM.from_pretrained( "/opt/deepseek/models/deepseek-32b", use_memory_efficient=True, )逻辑说明:gradient_checkpointing_enable()让前向只保留每层的入口状态,反向时重新跑一遍前向拿中间值。显存能降三到四成,代价是训练速度慢 20% 到 30%。纯推理场景收益有限,主要用在微调。
再往下就是分级卸载,把放不下的参数和优化器状态挪到 NVMe 或内存里:
accelerate launch --config_file accelerate_config.yaml \ --num_processes 4 \ --mixed_precision bf16 \ --gradient_accumulation_steps 8 \ --offload_param_device="nvme" \ --offload_optimizer_device="cpu"逻辑说明:--num_processes 4要和实际参与计算的 GPU 数一致;--gradient_accumulation_steps 8是在小 batch 下凑等效大 batch,卸载本身会拖慢单步,靠累积把吞吐补回来;两个 offload 参数指定溢出数据的落点。
参数说明:offload_optimizer_device放 CPU 内存,走 PCIe,代价可控;offload_param_device放 NVMe,走的是磁盘 IO,单步延迟会明显上升。只有前两者都撑不住才该用 nvme,我在生产环境里见过把它当常规配置用的,延迟从 200ms 飙到 2s,最后发现只要把 batch 调小就能避免。这是典型的“为了省显存把性能全赔进去”。
3.5 出现 OOM 后的三步处理
第一步,看曲线定性质,权重型还是增长型。第二步,权重型先降精度到 4bit,别急着改架构。第三步,增长型砍max_new_tokens和并发,把max_batch_size从自动改成固定小值,观察拐点在哪里。
还有一个环境变量值得记住:PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True。长跑服务里显存碎片累积导致的“明明有空闲却分配失败”,加上这一句往往就好了。它不是万能药,但在反复启停、变长输入的场景里确实省事。
4. 4-bit 量化与 FlashAttention 编译失败:依赖链上的坑
4.1 bitsandbytes 加载失败:动态链接不上
量化配置写对了,运行时报libbitsandbytes_cuda*.so: cannot open shared object file,或者更含糊的no GPU device was found。这两个报错指向同一件事:量化后端没找到能用的 CUDA 库。
# 官方自检脚本,会打印找到的 CUDA 版本和可用设备 python -m bitsandbytes # 查看包内实际带进来的动态库 python -c "import bitsandbytes, os; print(os.listdir(os.path.dirname(bitsandbytes.__file__)))"逻辑说明:bitsandbytes 安装时会根据当前环境的 CUDA 版本编译或下载对应的.so。如果装的时候环境里没有nvcc、或者 torch 是 CPU 版,它会退化到一个不带 CUDA 支持的构建,装完不报错,跑起来才崩。
参数说明:python -m bitsandbytes是官方保留的自检入口,输出里CUDA Version和Device count两行直接说明问题。修复顺序是先确保第 2 章的is_available()为 True,再重装 bitsandbytes,顺序反了重装十次也是白装。Windows 原生环境不支持它,必须走 WSL2 或 Linux。
4.2 FlashAttention 编译:架构列表填错就等于白等
TORCH_CUDA_ARCH_LIST这个环境变量是编译期的最大变量。填错了不会立刻报错,而是给你一个更隐蔽的症状:编译跑了四十分钟成功结束,一运行就illegal memory access。
# 为 A100(计算能力 8.0)编译 FlashAttention-2 # MAX_JOBS 限制并行编译进程数,防止编译期把内存打满 MAX_JOBS=4 TORCH_CUDA_ARCH_LIST="8.0" pip install flash-attn==2.3.3逻辑说明:TORCH_CUDA_ARCH_LIST决定生成哪些 GPU 架构的 cubin。只填8.0而实际跑在 8.6 的卡上,运行时找不到匹配的内核镜像,报错信息通常是no kernel image is available for execution on the device。
参数说明:A100 是8.0,3090 是8.6,4090 是8.9,H100 是9.0,V100 是7.0。要一次覆盖多种卡就用分号连写8.0;8.6;8.9,代价是编译时间翻倍。MAX_JOBS=4是经验值,机器内存小的话降到 2,否则编译阶段的 gcc 进程会把内存吃光,直接被 OOM killer 干掉,表现出来就是“编译到一半就没了”。
4.3 CUDA Toolkit 安装:别让 runfile 静默覆盖驱动
装 CUDA 有个操作容易出问题:runfile 默认会检测驱动版本,版本不匹配就中止,很多人习惯性加--override硬上,结果把驱动一起覆盖了。
# --toolkit 只装工具链,--samples 装样例,都不碰驱动 # --override 跳过编译器版本检查(gcc 版本偏新时必需) sudo sh cuda_12.1.0_530.30.02_linux.run \ --override --toolkit --samples --silent # 装完配好路径,否则新开的 shell 还是用旧的 nvcc export PATH=/usr/local/cuda-12.1/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64:$LD_LIBRARY_PATH逻辑说明:--toolkit是关键参数,只安装编译和运行所需的库,不安装内核模块和驱动。不加这个参数时,runfile 会尝试安装驱动,而服务器上的驱动往往由运维统一管理,覆盖后重启就再也起不来。--silent让整个过程无人值守,适合批量部署,但正因如此它不会提示你正在覆盖什么,风险也在这里。
参数说明:--override只影响主机的 gcc 版本检查,不影响安装内容,gcc 太新(比如 12 以上)时没有它 CUDA 12.1 会直接拒绝安装。装完建议立刻nvcc --version确认路径生效,同时nvidia-smi再看一眼驱动版本有没有被改动——这一步很多人跳过,等重启后才发现问题。
4.4 系统层的一行配置,能把推理延迟抖出一倍
这一项不报错,但会让性能变得不可预期。Linux 默认vm.swappiness=60,意思是内存有压力时积极把匿名页换到 swap。模型加载之后内存本来就紧张,一触发换出,推理时每一步都在等 page fault。
# 降低换出倾向,让模型常驻物理内存 echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 顺手建好专用部署目录,避免和用户目录抢磁盘配额 sudo mkdir -p /opt/deepseek && sudo chmod 755 /opt/deepseek逻辑说明:swappiness取 0 到 100,越低越不愿意换出。生产环境一般设 10,留一点缓冲避免 OOM killer 直接杀进程,设 0 在极端情况下反而更危险。
参数说明:sysctl -p让配置立即生效,不执行的话只写进了文件。目录权限给 755 而不是 777——容器里 UID 映射不一致时 777 也能写进去,但对生产环境来说权限开太大本身就是隐患,正确做法是把运行用户加进对应组,而不是靠放开权限绕过去。
5. 常见问题排查:五个容易卡住一整天的坑
5.1 nvidia-smi 显示显存空闲,程序却报 OOM
现象:nvidia-smi显示 80GB 里只用了 12GB,模型加载照样抛CUDA out of memory。
原因有两个。一是残留进程:上一次跑崩的 Python 没退干净,显存挂在僵尸进程上,nvidia-smi的进程列表里能看到但不显眼。二是碎片化:长跑服务反复分配不同长度的 KV Cache,空闲显存是碎的,单块连续空间不够。
解决:先nvidia-smi --query-compute-apps=pid,used_memory --format=csv把占用进程列出来,确认后kill -9。碎片问题加环境变量PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True重启进程,比调小 batch 更直接。
5.2 多卡启动卡在 NCCL init,日志一行都不出
现象:accelerate launch或torchrun起四卡任务,进程都在,日志停在初始化那行,等十分钟没动静。
原因基本是三选一:init_method里的 IP 不是通信网卡;world_size写成了 4 但实际只起了 3 个进程;节点间防火墙挡了端口。
解决:把init_method里的地址换成本机通信网卡的 IP,先用ip addr确认哪张卡是内网。临时加NCCL_DEBUG=INFO跑一次,日志会明确告诉你它在等哪个 rank、连的哪个地址。
# 打开 NCCL 详细日志,卡住时能看到它在等谁 NCCL_DEBUG=INFO NCCL_DEBUG_SUBSYS=INIT,NET \ torchrun --nproc_per_node=4 train.py逻辑说明:NCCL_DEBUG_SUBSYS只开初始化和网络两个子系统,日志量可控。全开会把每次集合通信都打出来,反而看不清 init 阶段的问题。
5.3 部署目录权限放开了,容器里还是写不进去
现象:宿主机上/opt/deepseek已经chmod 777,容器内挂载后写模型缓存仍报 Permission denied。
原因:容器内的 UID 和宿主机不是同一个,777 生效的前提是挂载本身可写;如果挂载点设成了只读,或者宿主机开了 SELinux,权限位根本轮不到起作用。
解决:先确认挂载参数没有:ro,再ls -Z看 SELinux 上下文。生产环境不建议靠 777 解决,把容器运行用户加进宿主机对应组、给目录设 775,比放开全局写权限稳得多。
5.4 推理延迟远高于 200ms 的基线
现象:输入 512 tokens,单条请求延迟到 800ms 以上,GPU 利用率却只有 30%。
原因通常是四类:没开 bf16,权重跑在 fp32;batch 一直为 1,GPU 大量时间在等调度;offload 把参数放在 NVMe 上,每步都要读盘;没用 TensorRT 或 Triton,走的是朴素 PyTorch 推理路径。
解决:按代价从低到高排——先确认mixed_precision是 bf16,再开动态批处理把并发合起来,然后检查有没有误开offload_param_device="nvme"。前三条都没问题,再考虑用torch2trt转 TensorRT 或者上 Triton 推理服务器,那属于另一个量级的改造。
# 先在框架层确认精度设置是否生效 import torch print(torch.get_float32_matmul_precision()) # 应为 high 或 medium5.5 模型能加载,输出却是乱码或无限重复
现象:加载不报错,推理出来的内容重复同一句,或者夹杂乱码字符。
原因有三个:tokenizer 路径和模型权重不是同一份,词表对不上;bnb_4bit_compute_dtype用了float16,大模型激活溢出成 inf;量化后端和推理后端不一致,一边 4bit 加载一边按 fp16 解码。
解决:确认 tokenizer 和 model 从同一个目录加载;计算精度统一用 bfloat16;量化加载后不要再用.half()转一遍,那会把已经反量化的层再压回去。这个问题的排查成本最高,因为它不报错,只能靠对比输出判断。
6. 快速定位:把“跑不动”拆成五步可测量的检查
处理到后面会发现,这类故障其实不是靠灵感解决的,靠的是把“跑不动”拆成几个能测量的层,从下往上逐层确认。我现在的习惯是,任何一台新机器上手,先不管模型,跑一遍下面这张表。
| 顺序 | 检查项 | 命令 | 通过标准 |
|---|---|---|---|
| 1 | 驱动与设备 | nvidia-smi | 列出目标卡,无 ERR |
| 2 | 运行时 | nvcc --version | 版本不高于驱动上限 |
| 3 | 框架 | torch.cuda.is_available() | True 且 count 正确 |
| 4 | 精度库 | torch.backends.cudnn.version() | ≥ 8902 |
| 5 | 真实计算 | 跑一次 bf16 矩阵乘 | 无 nan、无 illegal access |
这张表的价值在于把故障范围缩小到一层。第 1 层不过,别碰 Python;第 3 层不过,别碰量化;第 5 层不过,问题在 cuDNN 或架构列表,跟显存一点关系都没有。我见过太多人一上来就调device_map、改 batch size,其实卡在第二步。
再往上走是模型层,顺序是:先加载小模型确认链路通,再加载目标模型确认权重放得下,最后压测确认 KV Cache 撑得住。每一步失败都对应不同的处理手段,混着做只会让变量失控。
# 一条命令把关键指标抓成一行,方便比对两次改动前后 nvidia-smi --query-gpu=index,name,memory.used,memory.total,utilization.gpu \ --format=csv,noheader逻辑说明:utilization.gpu是判断瓶颈位置最直接的指标。延迟高但利用率低,多半卡在 CPU 侧的数据准备或 offload 的磁盘 IO;利用率打满但延迟仍高,才是算力不够,这时候加卡或上 TensorRT 才有意义。
参数说明:noheader去掉表头,方便直接喂给监控脚本做对比。
还有一个我强制自己做的动作:每次改配置只改一个变量,改完立刻重跑第 5 步的真实计算,再跑一次目标模型。听起来很笨,但它能避免“改了三处,好了,不知道是哪处起的作用”这种后续无法复用的结果。
从那以后我每次上新机器,都会先把这五步走完再碰模型文件,宁可多花二十分钟,也不愿在凌晨两点对着一个 False 猜。
这份 PDF 把硬件分级的参数、量化配置、卸载策略和监控命令都收在了一处,对着自己机器的实际配置过一遍,比零散地翻文档省事。希望帮到你。
本文还有配套的精品资源,点击获取