将下述命令保存为uvinit.sh,然后bash uvinit.sh
即使terminal用的是zsh,还是推荐用bash执行(下述命令是按照bash的语法编写的)
# 在已有项目根目录执行,不需要 mkdir,也不需要创建新项目目录。
#
# 第一行的 cpu 是默认选择:
# Linux:CPU 构建。
# macOS:从 PyPI 安装,运行检查使用可用的 MPS,否则使用 CPU。
#
# NVIDIA CUDA 服务器:
# 先用 nvidia-smi 检查显卡与驱动;
# 确认兼容后,将第一行 cpu 改为 cu128、cu126 或 cu130。
# 这些是构建选项,不代表任意显卡都适用。
#
# 不安装或升级系统显卡驱动,不安装系统 CUDA Toolkit。
# bash 子进程避免把 set -e 等设置留在你的交互式终端里。
TORCH_BACKEND=cpu bash <<'BASH'
set -euo pipefail
# ============================================================================
# 1. 检查现有环境,避免覆盖项目
# ============================================================================
command -v uv >/dev/null 2>&1 || {
echo '请先安装 uv。' >&2
exit 1
}
if [ -e pyproject.toml ] || [ -e uv.lock ] || [ -e uv.toml ]; then
echo '检测到已有项目配置;请使用 uv sync --locked,或选择性合并配置。' >&2
exit 1
fi
if [ -e .python-version ]; then
echo '检测到已有 .python-version;请先核对 Python 版本,不自动覆盖。' >&2
exit 1
fi
if [ -e .venv ]; then
echo '检测到已有 .venv;请先确认其用途,不自动覆盖或删除。' >&2
exit 1
fi
if [ -e .env.local ] && [ ! -f .env.local ]; then
echo '.env.local 已存在但不是普通文件,请先检查。' >&2
exit 1
fi
TORCH_BACKEND="${TORCH_BACKEND:-cpu}"
case "$TORCH_BACKEND" in
cpu|cu126|cu128|cu130) ;;
*)
echo '支持的模板后端:cpu、cu126、cu128、cu130。' >&2
exit 1
;;
esac
PROJECT_NAME="${PROJECT_NAME:-deep-learning-project}"
export TORCH_BACKEND
# 只使用当前项目 .venv,不误用外部已经激活的虚拟环境。
# 这些设置仅在当前 bash 子进程内生效。
unset VIRTUAL_ENV
export UV_PROJECT_ENVIRONMENT=.venv
uv --version
# ============================================================================
# 2. 安装 Python,并固定实际补丁版本
# ============================================================================
# 使用 uv 管理 Python,不修改系统 Python。
uv python install 3.12
PYTHON_BIN="$(uv python find --managed-python --no-project 3.12)"
PYTHON_EXACT="$(
"$PYTHON_BIN" -c 'import platform; print(platform.python_version())'
)"
# 不传入目录参数,因此直接在当前目录初始化。
# --bare:不生成 README、main.py、src/ 等示例文件。
# --no-package:当前模板作为训练脚本项目,而不是待发布的 Python 包。
# --vcs none:不自动初始化或改动版本控制系统。
# --no-workspace:不自动加入父目录工作区。
#
# >=3.12,<3.13 是本模板的选择,不是所有深度学习项目的统一要求。
uv init \
--bare \
--no-package \
--vcs none \
--no-workspace \
--name "$PROJECT_NAME" \
--python '>=3.12,<3.13'
# 固定实际安装的 Python 补丁版本,便于其他机器复现。
uv python pin "$PYTHON_EXACT"
export UV_PYTHON="$PYTHON_EXACT"
# ============================================================================
# 3. 配置依赖组与 PyTorch 专用下载源
# ============================================================================
# 先定义空组,避免 default-groups 指向不存在的组。
#
# explicit = true:
# 只有明确绑定到 pytorch 源的包才使用该源;
# 普通依赖不会因为添加 PyTorch 源而误走该源。
#
# 平台标记:
# Linux / Windows 使用所选 PyTorch 源;
# macOS 回退到 PyPI,不尝试安装 CUDA 构建。
#
# torchaudio 暂不默认安装,但预先配置相同来源,后续添加时可复用。
cat >> pyproject.toml <<TOML
[dependency-groups]
dev = []
notebook = []
[tool.uv]
default-groups = ["dev", "notebook"]
[tool.uv.sources]
torch = [{ index = "pytorch", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }]
torchvision = [{ index = "pytorch", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }]
torchaudio = [{ index = "pytorch", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }]
[tool.uv.index](#broken-link-tool.uv.index)
name = "pytorch"
url = "https://download.pytorch.org/whl/${TORCH_BACKEND}"
explicit = true
TOML
# ============================================================================
# 4. 添加训练、分析、开发与 Notebook 依赖
# ============================================================================
# --no-sync:
# 更新依赖定义和锁文件,但暂不反复安装;
# 后面统一执行 uv sync。
uv add --no-sync \
torch torchvision \
numpy scipy pandas scikit-learn matplotlib pillow \
tqdm pyyaml rich python-dotenv tensorboard einops safetensors
# 开发工具。
# 安装 pre-commit 不等于安装 Git 钩子;
# 应在项目已有 .pre-commit-config.yaml 后另行安装钩子。
uv add --dev --no-sync \
ruff pytest pytest-cov debugpy pre-commit
# Notebook 单独分组:
# 本地开发默认安装;
# 部署或纯训练环境可排除这个组。
uv add --group notebook --no-sync \
jupyterlab ipykernel ipywidgets
# ============================================================================
# 5. 本地缓存与运行环境变量
# ============================================================================
# 不覆盖已有 .env.local,不写入真实访问令牌。
# .env.local 和 .cache/ 已包含在配套 .gitignore 中。
#
# 这些路径相对于运行命令时的工作目录;
# 后续也应从项目根目录启动。
#
# 不设置 UV_CACHE_DIR:
# 保留 uv 的默认全局缓存,避免每个项目重复下载 Python 依赖。
if [ ! -e .env.local ]; then
cat > .env.local <<'ENV'
PYTHONUNBUFFERED=1
HF_HOME=.cache/huggingface
HF_HUB_CACHE=.cache/huggingface/hub
HF_DATASETS_CACHE=.cache/huggingface/datasets
TORCH_HOME=.cache/torch
TORCH_EXTENSIONS_DIR=.cache/torch_extensions
TORCHINDUCTOR_CACHE_DIR=.cache/torchinductor
TRITON_CACHE_DIR=.cache/triton
MPLCONFIGDIR=.cache/matplotlib
NUMBA_CACHE_DIR=.cache/numba
ENV
fi
# ============================================================================
# 6. 同步环境并检查锁文件、包依赖
# ============================================================================
# 根据锁文件同步项目环境。
# 不需要先 source .venv/bin/activate,也不需要手动安装 pip。
uv sync --locked
# 检查锁文件与项目定义是否一致。
uv lock --check
# 明确检查当前项目解释器中的依赖关系。
uv pip check --python .venv/bin/python
# ============================================================================
# 7. 运行检查:解释器、包导入、算子、反向传播与参数更新
# ============================================================================
# .env.local 需要显式加载,并不是文件存在就会自动生效。
# 选择了 CUDA 构建但 CUDA 不可用时,明确失败,不以 CPU 冒充成功。
uv run --locked --env-file .env.local python - <<'PY'
import os
import platform
import sys
from pathlib import Path
import numpy as np
import torch
import torchvision
from torchvision.ops import nms
assert Path(sys.prefix).resolve() == Path(".venv").resolve(), sys.prefix
backend = os.environ.get("TORCH_BACKEND", "cpu")
if backend.startswith("cu") and sys.platform != "darwin":
assert torch.cuda.is_available(), (
"安装了 CUDA 构建,但 CUDA 不可用;"
"请检查驱动、显卡支持、容器 GPU 透传。"
)
mps_available = (
hasattr(torch.backends, "mps")
and torch.backends.mps.is_available()
)
device = (
"cuda"
if torch.cuda.is_available()
else ("mps" if mps_available else "cpu")
)
# 检查 NumPy 与 PyTorch 的互操作。
array = np.ones(4, dtype=np.float32)
assert torch.from_numpy(array).sum().item() == 4
# 检查 torchvision 的编译算子是否正常。
boxes = torch.tensor([
[0.0, 0.0, 2.0, 2.0],
[0.0, 0.0, 2.0, 2.0],
])
scores = torch.tensor([0.9, 0.8])
assert nms(boxes, scores, 0.5).tolist() == [0]
# 在实际选中的设备上执行一次训练更新。
model = torch.nn.Linear(8, 4).to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
x = torch.randn(16, 8, device=device)
before = model.weight.detach().clone()
optimizer.zero_grad(set_to_none=True)
loss = model(x).square().mean()
loss.backward()
optimizer.step()
assert torch.isfinite(loss).item()
assert not torch.equal(before, model.weight.detach())
print("Python:", platform.python_version())
print("解释器:", sys.executable)
print("PyTorch:", torch.__version__)
print("torchvision:", torchvision.__version__)
print("NumPy:", np.__version__)
print("CUDA 构建版本:", torch.version.cuda)
print("MPS 可用:", mps_available)
print("实际测试设备:", device)
if device == "cuda":
print("GPU:", torch.cuda.get_device_name(0))
print("环境检查通过。")
print("此检查不代表完整训练、分布式训练或所有算子均已验证。")
PY
printf '\n配置完成。\n'
printf '%s\n' \
'应提交:pyproject.toml、uv.lock、.python-version、.gitignore' \
'不提交:.venv、.env.local、下载缓存、数据集及训练产物'
BASH