从零搭建 YOLO 训练环境GPU版本
前言
这里是用到的X-AnyLabeling+yolov8产出.pt后转成.onnx文件使用,末尾附带自动按照yolo要求放好文件的脚本。
最近在 Windows 上折腾 YOLO 训练环境,因为是国内网络 + 老显卡驱动,踩了一堆坑:pip 默认源超时、自动装错版本导致 DLL 报错、单线程下载 3 小时……
网上教程大多默认你能流畅访问 GitHub / PyTorch 官网,照着做基本都会卡死。所以我把完整可跑通的流程 + 5 个真实踩坑整理出来,照着做 30 分钟就能在本地 GPU 上跑通yolo train。
实测环境:Windows 10 + RTX 3060 Laptop(6 GB 显存)+ 驱动 527.99
最终成果:yolo train data=xxx.yaml正常 GPU 训练并产出.pt权重文件
一、整体流程(5 步)
① 装 Python 3.11 → ② 建 venv 虚拟环境 → ③ 装 PyTorch GPU 版 → ④ 装 Ultralytics → ⑤ 验证总下载量约2.8 GB,其中 PyTorch(torch)是大头。不要用 pip 默认源直接下,必失败(见坑 2、坑 3)。
二、详细步骤
第 1 步:安装 Python 3.11
- 下载地址:https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe
- 安装时务必勾选 “Add python.exe to PATH”
- 安装结束界面建议点“Disable path length limit”(避免 pip 装大包时路径超长报错)
- ⚠️ 不要用 Python 3.13+,太新容易踩兼容坑;3.11 最稳
验证(新开 cmd):
py -3.11 --version第 2 步:创建虚拟环境
py -3.11 -m venv C:\yolo-env C:\yolo-env\Scripts\activate看到命令行前面出现(yolo-env)才算激活成功,后续所有命令都要在这个状态下执行。
第 3 步:安装 PyTorch GPU 版(关键,先看坑 2、坑 3)
推荐做法(浏览器多线程下载 + 本地安装):
- 浏览器打开下载这两个文件(阿里云镜像,国内满速):
https://mirrors.aliyun.com/pytorch-wheels/cu118/torch-2.7.1%2Bcu118-cp311-cp311-win_amd64.whl (约 2.8 GB) https://mirrors.aliyun.com/pytorch-wheels/cu118/torchvision-0.22.1%2Bcu118-cp311-cp311-win_amd64.whl (约 5 MB) - 等两个都下载完(浏览器里的
.crdownload临时文件消失才算完),然后:
⚠️必须先装 torch,再装 torchvision(后者依赖前者,顺序反了会报pip install "下载目录\torch-2.7.1+cu118-cp311-cp311-win_amd64.whl" pip install "下载目录\torchvision-0.22.1+cu118-cp311-cp311-win_amd64.whl" -i https://pypi.tuna.tsinghua.edu.cn/simpleNo matching distribution)
第 4 步:安装 Ultralytics(YOLO 本体)
pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simpleOpenCV 等依赖自动带入,无需单独安装。
第 5 步:验证全链路
python -c "import torch; print('CUDA可用:', torch.cuda.is_available())" yolo predict model=yolov8n.pt source=https://ultralytics.com/images/bus.jpg通过标准:
- 输出
CUDA可用: True - demo 输出含
CUDA:0 (NVIDIA ...)且Results saved to runs\detect\predict
三、踩坑记录(每条都是实测血泪)
坑 1:pip 混用镜像时自动选错版本 🔴 最隐蔽
pip install torch torchvision -i 清华源 -f 阿里云镜像 ← 错误示范pip 默认挑"最高版本",会无视 cu118 镜像,从清华源装torch 2.13.0(新版内置 CUDA 太新,老驱动带不动),装完import torch直接报:
OSError: [WinError 1114] 动态链接库(DLL)初始化例程失败。Error loading ...\c10.dll对策:必须锁死版本号
pip install torch==2.7.1+cu118 torchvision==0.22.1+cu118 ...坑 2:官方源国内直连必超时
download.pytorch.org在国外,2.8 GB 文件下到一半必断:
pip._vendor.urllib3.exceptions.ReadTimeoutError: ... Read timed out.对策:小依赖走清华源-i https://pypi.tuna.tsinghua.edu.cn/simple,torch 本体走阿里云镜像。
坑 3:pip 单线程下载慢到绝望
即使走阿里云镜像,pip 单线程也只有约 242 kB/s(2.8 GB 要 3 小时+),且pip 不支持断点续传。
对策:改用浏览器 / IDM / 迅雷下载 whl 文件(实测 3.7 MB/s),再本地pip install。
坑 4:CUDA 版本与驱动匹配
| 驱动版本 | 可选 wheel |
|---|---|
| ≥ 527.99(CUDA 12.0) | cu118 ✅ / cu121 ❌ |
| ≥ 531.xx(CUDA 12.1+) | cu118 / cu121 均可 |
先用nvidia-smi看右上角驱动支持的最高 CUDA 版本。cu118 兼容性最广,装机首选;不确定就装 cu118。
坑 5:杂项小坑
- 执行 pip 前确认已激活 venv(命令行有
(yolo-env)前缀),否则装进全局环境 - 浏览器下载没完成时文件是
.crdownload后缀,pip 会报 “No such file or directory”——等下载完再装 - 中文路径加英文双引号:
"下载目录\torch-xxx.whl" setx设置环境变量后要关闭 cmd 重开才生效- 如果重装后仍报 WinError 1114:装微软 VC++ 运行库 https://aka.ms/vs/17/release/vc_redist.x64.exe
四、磁盘规划建议
| 位置 | 内容 | 占用 |
|---|---|---|
C:\yolo-env | 虚拟环境(torch 等大包) | ~6 GB |
C:\yolo | 工作区(数据集、yaml、训练输出) | 随项目增长 |
- 系统盘建议预留 ≥ 20 GB 余量
- 想换盘:把上面路径里的
C换成D即可,流程完全一样
五、日常训练命令
1、cmd====C:\yolo-env\Scripts\python.exe "C:\Users\Admin\Desktop\DeepTrain\ScriptFile\3_convert_dataset.py" <图片JSON文件夹> screw ok ng----------加载图像,将图像标签转成txt;区分标签类别;拆分图像文件夹,训练和验证文件; 2、C:\yolo-env\Scripts\activate------调用yolo 3、cd /d C:\yolo------调用yolo 4、yolo train data=C:\yolo\datasets\screw\data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 workers=4 patience=30 name=<训练后的文件名>-----开始训练 {设置训练参数: epochs=100(训练轮数,每次看多少边把训练集完整学 100 遍。学太少没记住,太多会死记硬背); imgsz=640(输入尺寸训练前把每张图统一缩放到 640×640 再喂给模型,什么时候调大:目标在图里很小(小螺丝、远处零件)→ 960/1280。什么时候调小:显存不够、图本身分辨率低) batch=16(一次同时算 16 张图再统一更新一次(越多越快但越吃显存)) workers=4 (数据加载线程,用 4 个线程后台读图/增强,主线程不等待)默认就行。 patience=30(连续 30 轮精度不再提升就自动停下,省时间) name=screw_v2(输出文件夹名,这次结果存到 runs/detect/screw_v2/,不和上次混在一起) 5、yolo export model=C:\yolo\runs\detect\screw_v2\weights\best.pt format=onnx opset=12 将训练的格式从pt转换成onnx; opset=12(把模型用最通用的旧语法导出,确保你那边的老程序也读得动)训练产物:runs\detect\train\weights\best.pt
结语
到这里,你的 YOLO 训练环境就完全搭建好了。后续标注(推荐 X-AnyLabeling)→ 转 YOLO 格式 → 写data.yaml→ 一行yolo train就能开训。
#自动按照yolo要求放好文件的脚本。 #C:\yolo\datasets\screw\ #├── images\ ← 图片总文件夹 #│ ├── train\ ← 90 张训练用图 #│ └── val\ ← 22 张验证用图 #├── labels\ ← 标注总文件夹 #│ ├── train\ ← 90 份训练图的标注(.txt) #│ └── val\ ← 22 份验证图的标注(.txt) #└── data.yaml ← 配置文件 # -*- coding: utf-8 -*- """ Step 3: Convert X-AnyLabeling / LabelMe JSON annotations to YOLO dataset. Works fully offline. Pure standard library, no extra packages needed. Usage: C:\\yolo-env\\Scripts\\python.exe 3_convert_dataset.py <图片和JSON所在文件夹> <项目名> [类别名...] Example (two classes ok/ng, same as screw project): C:\\yolo-env\\Scripts\\python.exe 3_convert_dataset.py D:\\raw\\op100 screw ok ng Output: C:\\yolo\\datasets\\<项目名>\\ images/train, images/val, labels/train, labels/val, data.yaml Split: 80% train / 20% val, stratified so every class appears in val. """ import json, os, shutil, random, sys def main(): if len(sys.argv) < 4: print(__doc__) sys.exit(1) src = sys.argv[1] project = sys.argv[2] class_names = sys.argv[3:] # e.g. ok ng -> "0"->ok, "1"->ng dst = os.path.join(r"C:\yolo\datasets", project) for sub in ["images/train", "images/val", "labels/train", "labels/val"]: os.makedirs(os.path.join(dst, sub), exist_ok=True) items = [] skipped = 0 for f in os.listdir(src): if not f.endswith(".json"): continue name = os.path.splitext(f)[0] img = None for ext in (".jpg", ".jpeg", ".png", ".bmp"): p = os.path.join(src, name + ext) if os.path.exists(p): img = p break if img is None: skipped += 1 # orphan json (image deleted) continue d = json.load(open(os.path.join(src, f), encoding="utf-8")) W, H = d["imageWidth"], d["imageHeight"] lines, classes_in_img = [], set() for s in d["shapes"]: if s.get("shape_type", "rectangle") != "rectangle": continue # only rectangles supported pts = s["points"] xs = [p[0] for p in pts]; ys = [p[1] for p in pts] x1, x2, y1, y2 = min(xs), max(xs), min(ys), max(ys) cx = (x1 + x2) / 2 / W; cy = (y1 + y2) / 2 / H w = (x2 - x1) / W; h = (y2 - y1) / H cls = int(s["label"]) classes_in_img.add(cls) lines.append(f"{cls} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") if lines: items.append((name, lines, classes_in_img, img)) # stratified 8:2 split by rarest class presence random.seed(42) random.shuffle(items) val, train = [], [] # ensure each class shows up in val with ~20% of its images for cls in range(len(class_names)): group = [i for i in items if cls in i[2]] take = group[: max(1, len(group) // 5)] val.extend(take) val_names = {i[0] for i in val} train = [i for i in items if i[0] not in val_names] for name, lines, _, img in train: shutil.copy(img, os.path.join(dst, "images/train", os.path.basename(img))) open(os.path.join(dst, "labels/train", name + ".txt"), "w").write("\n".join(lines)) for name, lines, _, img in val: shutil.copy(img, os.path.join(dst, "images/val", os.path.basename(img))) open(os.path.join(dst, "labels/val", name + ".txt"), "w").write("\n".join(lines)) yaml_lines = [ f"path: C:/yolo/datasets/{project}", "train: images/train", "val: images/val", "names:", ] + [f" {i}: {n}" for i, n in enumerate(class_names)] open(os.path.join(dst, "data.yaml"), "w", encoding="utf-8").write("\n".join(yaml_lines) + "\n") print(f"total: {len(items)} images (skipped orphan json: {skipped})") print(f"train: {len(train)} val: {len(val)}") print(f"yaml : {os.path.join(dst, 'data.yaml')}") print("next : run 4_train.bat") if __name__ == "__main__": main()