本节目标
- 摸清 L20 的真实可用资源(有别人在用,不能想当然)
- 建立独立的 conda 环境,装好 PyTorch 并验证 CUDA 可用
- 掌握显存限制的写法,避免占满影响他人
- 配好远程开发(在家也能用公司的 L20)
第一步:摸清环境现状
先搞清楚这台机器现在什么状况。不要跳过这步——你的显存预算取决于别人占了多少。
# 1. 看 GPU 型号、显存、当前占用
nvidia-smi
# 2. 只看显存数字,方便脚本判断(单位 MiB)
nvidia-smi --query-gpu=name,memory.total,memory.used,memory.free \
--format=csv,noheader
# 3. 看谁在用 GPU(排查是不是自己的僵尸进程)
nvidia-smi --query-compute-apps=pid,process_name,used_memory \
--format=csv
# 4. 持续监控(每 2 秒刷新,Ctrl+C 退出)
watch -n 2 nvidia-smi
按你之前贴的输出,当前状况是:
| 项目 | 数值 | 含义 |
|---|---|---|
| GPU | NVIDIA L20 | Ada 架构,支持 bf16 和 FP8 |
| 总显存 | 46068 MiB(约 45GB) | 比 RTX 4090 还多一倍 |
| 已用 | 3546 MiB | 桌面环境 + 两个 safety_monitor + 一个 python |
| 你可用 | 约 42GB | 足够训 BEVFormer,甚至能跑 7B 模型 |
| CUDA | 12.6 / Driver 560.35.05 | 较新,装 PyTorch 要选对版本 |
| GPU-Util | 72% | 注意:算力也在被占用,你的训练会变慢 |
那两个 safety_monitor_GAOZHOU_camera 进程是别人的生产任务。
如果你占满显存导致它们 OOM 崩溃,后果很严重。
本节后面会教你怎么硬性限制自己的显存上限—— 这是在共享环境里干活的基本职业素养,也是面试时可以聊的工程习惯。
第二步:安装 Miniconda(如已有可跳过)
你的提示符显示已经是 (base),说明 conda 已装好。如果需要在别的机器重装:
# 下载并安装 Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda3
# 初始化(之后重开终端生效)
$HOME/miniconda3/bin/conda init bash
source ~/.bashrc
# 验证
conda --version
第三步:创建独立环境并安装 PyTorch
这里有个关键选择:PyTorch 的 CUDA 版本怎么选。
很多人以为「驱动是 CUDA 12.6,就必须装 cu126 版本的 PyTorch」。不对。
CUDA 驱动是向下兼容的——12.6 的驱动可以跑 cu118、cu121 编译的 PyTorch。 而且老一点的版本生态更成熟(mmcv、mmdet3d 这些库对新 CUDA 支持往往滞后)。
本课程主力用 cu121——它在 L20 上完全可用, 且与 BEVFormer 依赖链兼容性最好。
# 创建主力环境(Python 3.10 兼容性最佳)
conda create -n ad python=3.10 -y
conda activate ad
# 安装 PyTorch —— 选 cu121,兼容性最好
pip install torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 \
--index-url https://download.pytorch.org/whl/cu121
# 常用基础库
pip install numpy==1.26.4 opencv-python matplotlib tqdm \
pyyaml scipy pillow tensorboard
# 注意:numpy 锁 1.x,很多 CV 库还没适配 numpy 2.x
验证安装
把下面这段保存成 check_env.py 并运行。它会检查所有关键项:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""环境自检脚本 —— 一次性验证所有关键依赖"""
import sys
import subprocess
def line(title):
print("\n" + "=" * 60)
print(f" {title}")
print("=" * 60)
def check_python():
line("Python 环境")
print(f"版本: {sys.version.split()[0]}")
print(f"路径: {sys.executable}")
major, minor = sys.version_info[:2]
ok = (major == 3 and 8 <= minor <= 11)
print(f"评估: {'✓ 版本合适' if ok else '⚠ 建议用 3.8-3.11'}")
return ok
def check_torch():
line("PyTorch 与 CUDA")
try:
import torch
except ImportError:
print("✗ PyTorch 未安装")
return False
print(f"torch 版本 : {torch.__version__}")
print(f"编译时 CUDA : {torch.version.cuda}")
print(f"cuDNN 版本 : {torch.backends.cudnn.version()}")
avail = torch.cuda.is_available()
print(f"CUDA 可用 : {'✓ 是' if avail else '✗ 否'}")
if not avail:
print(" → 排查: 驱动版本是否过低?是否装成了 CPU 版 torch?")
return False
n = torch.cuda.device_count()
print(f"GPU 数量 : {n}")
for i in range(n):
props = torch.cuda.get_device_properties(i)
total_gb = props.total_memory / 1024**3
free_b, total_b = torch.cuda.mem_get_info(i)
free_gb = free_b / 1024**3
print(f" [{i}] {props.name}")
print(f" 算力 : sm_{props.major}{props.minor}")
print(f" 总显存 : {total_gb:.1f} GB")
print(f" 当前可用 : {free_gb:.1f} GB")
if free_gb < 10:
print(" ⚠ 可用显存偏低,注意其他进程占用")
return True
def check_compute():
"""实际跑一次矩阵乘法,验证算力真的可用"""
line("GPU 实算测试")
import torch, time
if not torch.cuda.is_available():
print("跳过(CUDA 不可用)")
return False
dev = torch.device("cuda:0")
size = 4096
a = torch.randn(size, size, device=dev)
b = torch.randn(size, size, device=dev)
# 预热(第一次调用有初始化开销,不计入)
for _ in range(3):
_ = a @ b
torch.cuda.synchronize()
t0 = time.time()
for _ in range(10):
c = a @ b
torch.cuda.synchronize()
dt = (time.time() - t0) / 10
# 矩阵乘法浮点运算量 = 2 * N^3
tflops = 2 * size**3 / dt / 1e12
print(f"{size}x{size} 矩阵乘法")
print(f" 单次耗时 : {dt*1000:.2f} ms")
print(f" 实测算力 : {tflops:.1f} TFLOPS (fp32)")
print(" 参考: L20 fp32 理论约 60 TFLOPS")
print(" 注: 若明显偏低,可能是 GPU 正被其他进程占用算力")
del a, b, c
torch.cuda.empty_cache()
return True
def check_bf16():
"""L20 是 Ada 架构,支持 bf16,训练时能省一半显存"""
line("混合精度支持")
import torch
if not torch.cuda.is_available():
print("跳过"); return
print(f"bf16 支持 : {'✓' if torch.cuda.is_bf16_supported() else '✗'}")
print(f"TF32 已启用: {torch.backends.cuda.matmul.allow_tf32}")
print("提示: L20 支持 bf16,训练时用它比 fp16 更稳定")
def check_libs():
line("常用库")
libs = ["numpy", "cv2", "matplotlib", "tqdm", "yaml", "scipy"]
for name in libs:
try:
mod = __import__(name)
ver = getattr(mod, "__version__", "?")
print(f" ✓ {name:12} {ver}")
except ImportError:
print(f" ✗ {name:12} 未安装")
if __name__ == "__main__":
print("\n端到端自动驾驶课程 · 环境自检")
ok = check_python()
ok = check_torch() and ok
if ok:
check_compute()
check_bf16()
check_libs()
line("检查完毕")
print("若全部 ✓,可以进入下一节 CARLA 部署\n")
conda activate ad
python check_env.py
第四步:共享 GPU 的礼貌用法
这一节是本课的特色内容——多数教程假设你独占 GPU,但你的实际情况不是。
方法一:限制 PyTorch 的显存占比(推荐)
PyTorch 默认会缓存显存不释放,导致看起来占用很高。用这个 API 限制上限:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""共享 GPU 上的礼貌用法工具 —— 在训练脚本开头 import 并调用"""
import os
import torch
def setup_polite_gpu(max_gb=30, device=0, verbose=True):
"""
在共享 GPU 上限制自己的显存占用上限。
参数:
max_gb : 你允许自己最多用多少 GB
device : GPU 编号
原理:
set_per_process_memory_fraction 设置的是「占总显存的比例」,
超过后 PyTorch 会主动抛 OOM,而不是把别人挤崩。
"""
if not torch.cuda.is_available():
print("[polite] CUDA 不可用,跳过")
return
total_b = torch.cuda.get_device_properties(device).total_memory
total_gb = total_b / 1024**3
free_b, _ = torch.cuda.mem_get_info(device)
free_gb = free_b / 1024**3
# 不要超过当前实际可用的量(留 2GB 余量给别人波动)
safe_gb = min(max_gb, max(free_gb - 2, 1))
frac = safe_gb / total_gb
torch.cuda.set_per_process_memory_fraction(frac, device)
if verbose:
print(f"[polite] GPU{device} 总显存 {total_gb:.1f}GB / 当前空闲 {free_gb:.1f}GB")
print(f"[polite] 本进程上限设为 {safe_gb:.1f}GB (占比 {frac:.1%})")
print(f"[polite] 超限时会抛 OOM,不会挤崩其他进程")
def report_memory(tag=""):
"""打印当前显存使用情况,训练循环里可定期调用"""
if not torch.cuda.is_available():
return
alloc = torch.cuda.memory_allocated() / 1024**3
reserved = torch.cuda.memory_reserved() / 1024**3
peak = torch.cuda.max_memory_allocated() / 1024**3
print(f"[mem]{tag} 已分配 {alloc:.2f}GB | "
f"已保留 {reserved:.2f}GB | 峰值 {peak:.2f}GB")
def free_cache():
"""主动归还缓存显存给系统(阶段切换时调用)"""
if torch.cuda.is_available():
torch.cuda.empty_cache()
torch.cuda.reset_peak_memory_stats()
# ---------------- 使用示例 ----------------
if __name__ == "__main__":
setup_polite_gpu(max_gb=30)
# 模拟分配一块显存
x = torch.randn(8000, 8000, device="cuda")
report_memory(" 分配后")
del x
free_cache()
report_memory(" 释放后")
方法二:用环境变量控制可见 GPU
# 只让程序看到 GPU 0(多卡机器上限制自己)
export CUDA_VISIBLE_DEVICES=0
python train.py
# 或者一次性写在命令前
CUDA_VISIBLE_DEVICES=0 python train.py
# 控制显存分配策略:减少碎片(大模型训练时有用)
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
「在共享 GPU 集群上通过显存配额限制与监控,保障多任务并行不互相影响」—— 这是真实的工程习惯,面试聊到团队协作或资源管理时可以自然提到。 很多只在自己电脑上跑过模型的候选人没有这个意识。
第五步:远程开发配置
你希望在家也能用公司的 L20。最舒服的方案是 VS Code Remote-SSH。
配置 SSH 免密登录
# 在你的本地机器上生成密钥(如已有可跳过)
ssh-keygen -t ed25519 -C "ad-course"
# 把公钥传到 L20 机器
ssh-copy-id leoking@<L20机器IP>
# 测试免密登录
ssh leoking@<L20机器IP>
本地 SSH config 加个别名
编辑本地的 ~/.ssh/config:
Host l20
HostName <L20机器IP>
User leoking
ServerAliveInterval 60
ServerAliveCountMax 5
# 端口转发:把远程的 TensorBoard / Jupyter 映射到本地
LocalForward 6006 localhost:6006
LocalForward 8888 localhost:8888
之后直接 ssh l20 就能连上,而且 TensorBoard 端口自动转发到本地。
VS Code 装 Remote-SSH 插件
装好后按 F1 → 输入 Remote-SSH: Connect to Host → 选 l20。
之后你在本地 VS Code 里写代码,实际运行在 L20 上——体验和本地开发一模一样。
用 tmux 防止断线丢任务
训练动辄几小时,网断了 SSH 会话就没了。必须用 tmux:
# 安装(若没有)
sudo apt install tmux -y
# 新建一个命名会话
tmux new -s train
# 在里面跑训练...
conda activate ad
python train.py
# 按 Ctrl+B 然后按 D → 脱离会话(训练继续跑)
# 断网重连后,恢复会话:
tmux attach -t train
# 查看所有会话
tmux ls
常见报错与排查
| 报错 | 原因 | 解决 |
|---|---|---|
torch.cuda.is_available() 返回 False |
装成了 CPU 版 PyTorch | 卸载重装,注意加 --index-url 参数 |
CUDA error: out of memory |
显存不够,或别人占用了 | 先 nvidia-smi 看实际可用;减小 batch size;用 setup_polite_gpu |
CUDA driver version is insufficient |
PyTorch 的 CUDA 版本高于驱动支持 | 换低一档的 PyTorch(如 cu118) |
numpy.dtype size changed |
numpy 2.x 与老库不兼容 | pip install numpy==1.26.4 |
| 训练特别慢 | GPU 算力被其他进程占用(你的 Util 已 72%) | nvidia-smi 确认;错峰跑;或接受较慢速度 |
| SSH 连接频繁断开 | 网络空闲超时 | config 里加 ServerAliveInterval 60 |
验收清单
- 能说出 L20 当前有多少显存可用、有哪些进程在占用
conda activate ad后python check_env.py全部通过- 实算测试的 TFLOPS 数值合理(若偏低知道是共享导致)
- 理解
setup_polite_gpu的作用,并会在训练脚本里调用 - 能从本地 VS Code 远程连上 L20 并编辑运行代码
- 会用 tmux 保持长时间训练不中断
本节小结
- L20 46GB 显存是巨大优势——之前担心的显存问题基本消失,但要注意算力是共享的
- PyTorch 选 cu121 而非 cu126——驱动向下兼容,老版本生态更成熟
- 共享 GPU 要限制自己的显存占比,这既是职业素养,也是可以写进简历的工程习惯
- 远程开发三件套:SSH 免密 + VS Code Remote + tmux,缺一不可
- 环境自检脚本要留着,后面每换一个环境都跑一遍
本节是纯工程内容,但有一个概念可以联系起来——混合精度训练。 L20 支持 bf16,这直接关系到你后面训 BEVFormer 时的显存和速度。
④ BEVFormer 第 2 节讲了张量形状与显存占用的关系——理解了那里,你就知道 batch size 该设多少 →