目录
尽管当前目标检测领域的研究热点集中在YOLO系列,但诸多经典算法在架构设计和性能对比中仍具有不可替代的价值。为弥补现有教程的不足——付费内容居多或细节缺失——本文将提供PyTorch版Faster R-CNN的完整训练指南,涵盖环境配置、训练及验证全流程。
本文的教程只包括基础的训练及验证精度,适合有对比实验需求的使用,鉴于现有的经典模型的教程存在付费或者不够详细等问题,因此写了本文方便有一定深度学习基础的同学学习,因为经典模型的训练较慢,因此本文不对只有CPU的单独介绍,有相关需求可联系我代训练。
1. 前言
2015年,由微软亚洲研究院的Shaoqing Ren、Kaiming He等学者提出的Faster R-CNN,以革命性的区域提议网络(RPN) 设计,解决了长期困扰检测领域的效率瓶颈。它将候选区域生成时间从秒级压缩至毫秒级,实现了惊人的端到端联合训练,使检测精度与速度首次达到工业级应用标准。其创新性的"注意力机制"思想,更成为后续YOLO、SSD等经典模型的灵感源泉。
本文使用代码为bubbliiiing大佬的开源代码
https://github.com/bubbliiiing/faster-rcnn-pytorch
代码及预训练文件我已经打包上传到网盘 夸克网盘分享,方便无法访问外网的情况下使用。
2. 查看电脑状况
深度学习这些经典模型如Faster R-CNN和SSD的训练对于电脑显卡要求较高,与YOLOv8同样的数据集,训练速度可能会有10倍左右的差距,因此只推荐使用NVIDIA显卡训练。若不清楚电脑有无显卡可以打开任务管理器,点击性能往下找GPU,就可以看到是否有独立显卡,不清楚是否为独立显卡则搜索型号。
图中我的显卡为RTX 3070,8G显存,一般常用笔记本上有MX系列、GTX系列和RTX系列,MX系列的性能相对较低,但是跟着教程往下做也可以使用。
嫌麻烦或者教程看不懂或者没有NVIDIA显卡的友友可以私信我或者关注公众号-笑脸惹桃花找我配置环境或者代训练模型哦~
3. 安装所需软件
推荐安装Anaconda3+Pycharm,都需要加入环境变量,会安装或者安装过了则跳过这一步骤,跟着我的教程安装过anaconda、pycharm和cuda11.8的可以直接从创建虚拟环境开始看。
3.1 Anaconda3安装
Anaconda3由于是国外网站下载较慢,推荐通过清华镜像源安装。
Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
选择带有Anaconda3...Windows...exe 字样的进行下载,建议寻找我图片上同版本的文件下载,不然安装后软件界面不一致,容易出现看不懂的情况,可以点击网盘下载相同版本。最好下载与我相同的版本。
下载完成之后打开Anaconda3进行安装,一直点下一步,选Just Me,安装路径不建议安装到c盘,可以直接复制粘贴修改到 D:\Anaconda3 ,也可以修改到其他路径,最好纯英文路径。
点击下一步后,需要选择添加到环境变量,如下图前三个一定要勾选,也可以按照我图中全选。
点击install安装后耐心等待进度条满安装完成即可,进度较慢,耐心等待。
3.2 Pycharm安装
安装Pycharm可以直接去官网下载,速度较快。
下载 PyCharm:JetBrains 出品的用于数据科学和 Web 开发的 Python IDE
往下拉下载第二个Community Edition社区免费版就可以,也可以网盘下载相同版本。
下载完之后打开安装,点下一步,遇到选择路径 修改路径到D盘或者其它除C盘外的文件夹,可以建个自己喜欢的全英文名字。
需要勾选这些选项,五角星必勾选,建议全选。
再点下一步,直接安装就可以了,耐心等待进度条满安装完成即可。
4. 安装环境
4.1 安装cuda及cudnn
4.1.1 下载及安装cuda
在安装pytorch前需要安装cuda,下载cuda前需要先查看显卡支持的CUDA版本最高是多少,按下win+r键,输入cmd,在打开的页面输入:nvidia-smi ,即可查看。
上图红框位置显示即为cuda最高支持版本,本教程cuda最高版本达到11.8即可,若没有达到则需要更新显卡驱动。
CUDA Toolkit Archive | NVIDIA Developer
在这个网站挑选下载或者直接点击夸克网盘下载下载或者点此下载 。
下载完之后运行安装,建议安装到默认路径,所以C盘需要留有20G以上的存储空间,一直点击下一步,直到出现这个界面点击自定义,然后全部勾选即可。
将下图中选项全部勾选安装。
安装完成后可以再次在cmd里输入命令:nvcc -V 查看,如下显示即安装成功
4.1.2 cudnn安装
进入cudnn官网,选择合适版本的文件。
cuDNN Archive | NVIDIA Developer
进入后在文件列表中选择cudnn版本与上面cuda安装相匹配的版本。
下载Windows版本的压缩包文件。
下载需要登录,也可以复制下载链接打开迅雷下载,或者点击链接下载下载cudnn。
将得到的压缩文件进行解压,解压后得到下图三个文件夹,全选复制进cuda的文件夹中进行覆盖替换,替换完成后即cudnn安装完成。按照本文教程安装的cuda的文件夹默认在 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 目录下。
4.2 创建虚拟环境
按下Win键,输入anaconda prompt,打开下图所示的应用。
默认进入的是base环境,base环境的版本与下载的anaconda3版本有关,因此不建议直接使用,需要新建环境,在新建环境之前建议更改默认的pip源和conda源可加速下载速度。
更改代码如下,直接输入即可,这里选择更换的是中科大源,建议使用,亲测完美运行。
conda config --remove-key channels
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple
此时新建虚拟环境(需要关闭加速软件),这里创建一个名为frcnn,python版本为3.8的虚拟环境,也可以修改为其他名,本文所用为python3.8,同时本教程所用pytorch源及python版本只支持3.8。
conda create -n frcnn python=3.8
回车后出现新建环境提醒输入y继续,耐心等待全部下载完成后自动安装。
注意:此时如果报错
UnavailableInvalidChannel: HTTP 404 NOT FOUND for channel anaconda/pkgs/free <https://mirrors.ustc.edu.cn/anaconda/pkgs/free>
The channel is not accessible or is invalid.
You will need to adjust your conda configuration to proceed.
Use `conda config --show channels` to view your configuration's current state,
and use `conda config --show-sources` to view config file locations.
等错误,需要修改隐藏文件 .condarc文件的内容,具体路径为:c:\users\用户名\.condarc
使用记事本打开,复制下面这一段进去替换掉原本所有的内容,替换完之后保存即可
channels:
- defaults
show_channel_urls: true
channel_alias: http://mirrors.tuna.tsinghua.edu.cn/anaconda
default_channels:
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
conda-forge: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
此时再重复上面新建环境的指令。
出现这样的done即为创建完成。
创建完之后输入
conda activate frcnn
4.3 安装pytorch
打开prompt 输入conda activate frcnn进入frcnn环境,之后输入下方命令即可安装pytorch,耐心等待安装完成。
pip install torch==2.0.0+cu118 torchvision==0.15.1+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
出现ERROR: No matching distribution found for torch==2.0.0+cu118等是因为python版本不对!
torch及相关库比较大,需要耐心等待下载完之后出现 done 则安装完成,因为是外网,如果下载不下来,可以点此下载torch 夸克网盘下载,然后通过pip install安装本地文件的方式安装,可以参考下图的方式,将torch放入d盘的test文件夹下,通过cd将文件目录跳转,再输入如下指令。(只支持python3.8版本,其余版本无法安装)
pip install torch-2.0.0+cu118-cp38-cp38-win_amd64.whl
下图为相对路径安装torch的演示方法,也可以直接使用绝对路径安装。
耐心等待安装完成后,再输入下面的指令通过pip安装其余库。
pip install torch==2.0.0+cu118 torchvision==0.15.1+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
出现successfully即安装torch成功。
4.4 下载Faster R-CNN代码
所使用代码为bubbliiiing大佬的代码,Faster R-CNN源代码地址:
https://github.com/bubbliiiing/faster-rcnn-pytorch
点进去下载代码,进不去可能需要科学上网,或者点击下载 夸克网盘分享,我上传了两个预训练权重文件,方便测试环境使用。链接资源失效请评论区反馈,看到会补,或者至公众号下载。
可以在这两个中挑选一个作为自己训练的,我一般使用resnet。
4.5 安装剩余库
此时需要安装源代码中的requirements内的库。
先找个位置将下载得到的faster-rcnn源代码解压,然后cd到faster-rcnn所在根目录,比如我这里放到了D盘的根目录下,那么我先到D盘,再进入faster-rcnn的根目录,如下图。
进入当前文件夹后,先打开requirements.txt,将下面的内容覆盖并保存,也可以直接新建一个requirements.txt文件,然后将下面的内容复制进去,
torch
torchvision
tensorboard
scipy==1.10.1
numpy==1.24.4
matplotlib==3.1.2
opencv_python==4.1.2.30
tqdm==4.60.0
Pillow==8.2.0
h5py==2.10.0
输入如下指令安装剩余python库
pip install -r requirements.txt
耐心等待,出现下图即安装完成。
5. 使用Pycharm
5.1 pycharm导入环境
下载完成之后解压到D盘或其它盘文件夹内,此时点击鼠标右键文件夹通过pycharm打开,打开后需要配置虚拟环境。打开文件夹后如果弹出创建虚拟环境,点取消
新版pycharm可选中文语言,点击 文件-设置,点击 项目:faster-rcnn,点击python解释器,点击右边添加解释器-添加本地解释器。
点击Virtualenv环境 - 现有,点击右边三个点,找到刚才添加的frcnn环境的位置,按照本文配置即是D:\Anaconda3\envs\frcnn\python.exe 路径,之后一直点确定,点应用,再点确定即可。
或者新版本的界面更为简单,按照下图方式选择就可以。
选择python,接着选择刚刚添加的frcnn环境,选择python.exe。
如果找不到环境所在位置,可以输入
conda env list
在这里面可以找到虚拟环境所在路径,再进pycharm里选择对应的python.exe即可。
正确选择的界面如下
点击确定后耐心等待解释器配置完成。
5.2 验证环境
这里使用预训练权重,并将其放置在model_data文件夹内,并修改predict.py,将里面的mode修改为dir_predict,然后运行,出现下图且没有报错则环境可以正常使用。
打开img_out文件夹,点开图片,可以看到有检测框,环境正常!
6. 模型训练
6.1 数据集处理
这里默认所有都已经有数据集的情况
需要图片+VOC格式的标签,因此如果之前是YOLO格式的文件就需要转换
# 作者:CSDN-笑脸惹桃花 https://blog.csdn.net/qq_67105081?type=blog
# github:peng-xiaobai https://github.com/peng-xiaobai/Dataset-Conversion
import os
import cv2
import numpy as np
#xml文件格式
out0 = '''<annotation>
<folder>%(folder)s</folder>
<filename>%(name)s</filename>
<path>%(path)s</path>
<source>
<database>None</database>
</source>
<size>
<width>%(width)d</width>
<height>%(height)d</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
'''
out1 = ''' <object>
<name>%(class)s</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>%(xmin)d</xmin>
<ymin>%(ymin)d</ymin>
<xmax>%(xmax)d</xmax>
<ymax>%(ymax)d</ymax>
</bndbox>
</object>
'''
out2 = '''</annotation>
'''
def upp2low(directory):
converted_count = 0
# 检查目录是否存在
if not os.path.exists(directory):
raise FileNotFoundError(f"Directory {directory} does not exist.")
# 遍历文件夹中的所有文件
for filename in os.listdir(directory):
file_path = os.path.join(directory, filename)
# 仅处理文件
if os.path.isfile(file_path):
# 拆分文件名和后缀
name, extension = os.path.splitext(filename)
# 检查后缀是否为大写
if extension.isupper():
new_filename = name + extension.lower()
new_file_path = os.path.join(directory, new_filename)
# 重命名文件
os.rename(file_path, new_file_path)
converted_count += 1
print(f"Renamed: {filename} -> {new_filename}")
print(f"All file suffixes in the folder are lowercase, and a total of {converted_count} files have been processed")
return converted_count
def yolo2voc(dir1,dir2,dir3,Class):
file = os.listdir(dir1)
source = {}
label = {}
for img in file:
print(img)
if img.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tif')):
img1 = os.path.join(dir1, img)
image = cv2.imread(img1) # 路径不能有中文
h, w, _ = image.shape
name, extension = os.path.splitext(img)
name1 = name + '.xml'
name2 = name + '.txt'
fxml = os.path.join(dir2, name1)
txt = os.path.join(dir3, name2)
if not os.path.exists(txt):
print(f"{name2}未找到,已跳过")
continue
fxml = open(fxml, 'w')
source['name'] = img
source['path'] = img1
source['folder'] = os.path.basename(dir1)
source['width'] = w
source['height'] = h
fxml.write(out0 % source)
lines = np.loadtxt(txt)
flag = 0
for box in lines:
if box.shape != (5,):
box = lines
flag = 1
'''把txt上的第一列(类别)转成xml上的类别'''
box_index = int(box[0])
label['class'] = Class[box_index] # 类别索引从1开始
'''把txt上的数字(归一化)转成xml上框的坐标'''
xmin = float(box[1] - 0.5 * box[3]) * w
ymin = float(box[2] - 0.5 * box[4]) * h
xmax = float(xmin + box[3] * w)
ymax = float(ymin + box[4] * h)
label['xmin'] = xmin
label['ymin'] = ymin
label['xmax'] = xmax
label['ymax'] = ymax
keys = ['xmin', 'ymin', 'xmax', 'ymax']
limits = [w, h, w, h]
for i, key in enumerate(keys):
if label[key] >= limits[i]:
label[key] = limits[i]
elif label[key] < 0:
label[key] = 0
fxml.write(out1 % label)
if flag == 1:
break
fxml.write(out2)
if __name__ == '__main__':
l = ["hat","nohat"] #所有类别
file_dir1 = r' ' #图像文件夹
file_dir2 = r' ' #xml存放文件夹
file_dir3 = r' ' #txt存放文件夹
if not os.path.exists(file_dir2):
os.makedirs(file_dir2)
upp2low(file_dir1)
yolo2voc(file_dir1,file_dir2,file_dir3,l)
print('转换已结束')
根据代码自行替换路径。
如果训练的图片不是jpg格式的则需要先转换为jpg格式,使用下面的代码
import os
from PIL import Image
import sys
def convert_to_jpg(input_folder, output_folder):
# 确保输出文件夹存在
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 支持的图片格式
supported_formats = ('.png', '.bmp', '.gif', '.tiff', '.webp')
# 遍历输入文件夹中的所有文件
for filename in os.listdir(input_folder):
# 检查文件是否为支持的图片格式
if filename.lower().endswith(supported_formats):
# 构建输入和输出文件路径
input_path = os.path.join(input_folder, filename)
# 去掉原文件扩展名,添加 .jpg
output_filename = os.path.splitext(filename)[0] + '.jpg'
output_path = os.path.join(output_folder, output_filename)
try:
# 打开图片
with Image.open(input_path) as img:
# 转换为 RGB 模式(JPG 不支持透明通道)
if img.mode in ('RGBA', 'LA', 'P'):
img = img.convert('RGB')
# 保存为 JPG
img.save(output_path, 'JPEG', quality=95)
print(f"成功转换: {filename} -> {output_filename}")
except Exception as e:
print(f"转换 {filename} 失败: {str(e)}")
if __name__ == "__main__":
input_folder = r'D:\faster-rcnn-pytorch-master\VOCdevkit\VOC2007\JPEGImages1' #输入文件夹
output_folder = r'D:\faster-rcnn-pytorch-master\VOCdevkit\VOC2007\JPEGImages' #输出文件夹
# 确保输入文件夹存在
if not os.path.exists(input_folder):
print(f"错误: 输入文件夹 {input_folder} 不存在")
sys.exit(1)
convert_to_jpg(input_folder, output_folder)
print("转换完成!")
将数据集复制到目录下的VOCdevkit\VOC2007文件夹下,标注文件放到Annotations,图片文件放到JPEGImages,打开voc_classes.txt,修改为自己数据集的类别,每种一行。之后打开voc_annotation.py,如果之前没有划分过数据集,则mode使用0,再设置合适的比例,后运行代码。
如果之前划分过数据集,则需要先提前将数据集对应划分,使用如下代码
import os
def write_filenames_to_txt(folder_path, txt_path):
# 获取文件夹中所有文件的文件名(不包含路径)
filenames = os.listdir(folder_path)
# 打开txt文件准备写入
with open(txt_path, 'w') as f:
for filename in filenames:
if filename.endswith('.txt'): # 假设标签文件是以.txt结尾
f.write(filename[:-4] + '\n') # 去掉扩展名并写入
def write_trainval_txt(train_folder, val_folder, trainval_txt_path):
# 获取train和val文件夹的文件名
train_filenames = os.listdir(train_folder)
val_filenames = os.listdir(val_folder)
# 打开trainval.txt文件准备写入
with open(trainval_txt_path, 'w') as f:
for filename in train_filenames:
if filename.endswith('.txt'):
f.write(filename[:-4] + '\n') # 去掉扩展名并写入
for filename in val_filenames:
if filename.endswith('.txt'):
f.write(filename[:-4] + '\n') # 去掉扩展名并写入
# 设置文件夹路径
train_folder = r'H:\datasets\train\labels' # 替换为traon实际路径
val_folder = r'H:\datasets\val\labels' # 替换为val实际路径
test_folder = r'H:\datasets\test\labels' # 替换为test实际路径
# 设置输出的txt文件路径
train_txt = r'H:\datasets\VOCdevkit\VOC2007\ImageSets\Main\train.txt' # 替换为实际路径
val_txt = r'H:\datasets\VOCdevkit\VOC2007\ImageSets\Main\val.txt' # 替换为实际路径
test_txt = r'H:\datasets\VOCdevkit\VOC2007\ImageSets\Main\test.txt' # 替换为实际路径
trainval_txt = r'H:\datasets\VOCdevkit\VOC2007\ImageSets\Main\trainval.txt' # 替换为实际路径
os.makedirs(r"H:\datasets\VOCdevkit\VOC2007\ImageSets\Main", exist_ok=True) #替换为Main路径
# 写入文件名到各自的txt
write_filenames_to_txt(train_folder, train_txt)
write_filenames_to_txt(val_folder, val_txt)
write_filenames_to_txt(test_folder, test_txt)
# 写入trainval.txt,包含train和val的所有文件名
write_trainval_txt(train_folder, val_folder, trainval_txt)
print("文件名已成功写入到txt文件中!")
使用代码后,将复制得到的Main文件夹内的txt全部复制到faster-rcnn-pytorch-master\VOCdevkit\VOC2007\ImageSets\Main 文件夹下,在voc_annotation.py中设置mode为2,运行,之后即可训练。
出现具体的类别及数量表示数据可以正常使用。
6.2 训练
打开train.py文件,本文使用voc_weights_resnet.pth训练,如果使用其他的则需要在大概83行修改model_path为其他模型。修改153行左右的Freeze_Epoch和Freeze_batch_size,往下还有UnFreeze_Epoch和UnFreeze_batch_size,这里分为冻结和解冻训练,根据不同的需要,如果训练200轮,则可以设置Freeze_Epoch为150,UnFreeze_Epoch设置为200,在最后50轮解冻训练,batch_size可以适当调整到适合自己显卡的合适数值,修改202行的save_period为25或其它,频繁保存易导致硬盘存储爆炸,217行的eval_period也可以修改为25或其他,减少评估频率,提高训练效率。其他的学习率,优化器等参数也可以根据代码中的注释进行适当修改。第60行的fp16可以开启,减少显存占用,第223行的num_workers设置为8,加快训练速度。
出现这个即可以正常训练。
7. 模型验证
打开predict.py文件,根据不同的需求修改不同的mode,可以使用dir_predict模式检测文件夹的内容并保存,将img文件夹内的图片修改为自己的数据集相关的图片,修改frcnn.py中的model_path为在logs文件夹下训练的最佳模型,一般是best_epoch_weights.pth,替换完就是下图。
之后运行predict代码,打开img_out即可查看检测后的图片。
遇到报错可以打开评论区交流。 关注微信公众号-笑脸惹桃花 快速联系我~