YOLOV5 训练PASCAL VOC数据集

环境

  • Ubantu 18.04

1. 安装pytorch

1) 安装Anaconda
anconda是一个用于科学计算的Python发行版,支持Linux,Mac,Windows 包含了众多流行的科学计算、数据分析的Python包
(1) 先去官方下载好对应的安装包
下载地址:https://www.anaconda.com/download/#linux
(2)然后安装anaconda

bash ~/Downloads/Anaconda3-2020.07-Linux-x86_64.sh

anaconda会自动将环境变量添加到PATH里面,如果后面你发现输出conda提示没有该命令,那么你需要执行 source ~/.bashrc更新环境变量,就可以正常使用了。
如果发现这样还没用,那么需要添加环境变量。
编辑 vim ~/.bashrc文件,在文件后面加上

export PATH=/home/yuan/anaconda3/bin:$PATH

注意:路径应该为自己机器上的路径
保存退出后执行:source ~/.bashrc
再次输入conda list 测试看看,应该没问题
(3) 添加Anaconda国内镜像
清华TUNA提供了Anaconda仓库的镜像,运行以下三个命令:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes

1) 安装Pytorch
注意:需要安装pytorch1.6以上版本
首先pytorch创建一个anaconda虚拟环境,环境名字可自己确定,这里本人使用pytorch1.6作为环境名:

conda create -n pytorch1.6 python=3.8

安装成功后,激活pytorch1.6虚拟环境

conda activate pytorch1.6

在所建的pytorch环境下安装pytorch1.6版本,执行命令:

conda install pytorch torchvision cudatoolkit=10.1 -c pytorch

注意:10.1处应为cuda的安装版本号
编辑~/.bashrc文件,设置使用pytorch1.6虚拟环境下的python3.8

alias python='/home/yuan/anaconda3/envs/pytorch1.6/bin/python3.8'

注意:python路径应改为自己机器上的路径
保存并退出后执行:source ~/.bashrc
该命令将自动回到base环境,再执行conda activate pytorch1.6到pytorch环境

2. yolov5项目的克隆和安装

1) 克隆yolov5项目(v3.1)
安装Git软件(https://git-scm.com/downloads),克隆项目到本地

git clone https://github.com/ultralytics/yolov5.git

或下载yolovt版本v3.1 https://github.com/ultralytics/yolov5/releases/tag/v3.1
YOLOV5 训练PASCAL VOC数据集_第1张图片
2) 安装需要的库
使用清华镜像源:
在yolov5路径下执行

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

注意:simple不能少,是https而不是http
3) 下载预训练权重文件
下载yolov5s.pt,yolov5m.pt,yolov5l.pt,yolov5x.pt权重文件,并新建weights夹,放在该文件夹下
4) 安装测试
在yolov5路径下执行

python detect.py --source ./inference/images/ --weights weights/yolov5s.pt  --conf 0.4

YOLOV5 训练PASCAL VOC数据集_第2张图片

3. 准备数据集

1) 下载项目文件:下载链接
下载到yolov5目录下:

  • VOCtrainval_06-Nov-2007.tar
  • VOCtrainval_11-May-2012.tar
  • VOCtest_06-Nov-2007.tar
  • voc_label.py

voc_label.py

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir,getcwd
from os.path import join
import shutil

sets=[('2012','train'),('2012','val'),('2007','train'),('2007','val'),('2007','test')]

classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]

def convert(size, box):
    dw = 1./size[0]
    dh = 1./size[1]
    x = (box[0] + box[1])/2.0
    y = (box[2] + box[3])/2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)

def convert_annotation(year, image_id):
    in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
    out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
    tree=ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

wd = getcwd()

for year, image_set in sets:
    if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
        os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
    image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
    list_file = open('%s_%s.txt'%(year, image_set), 'w')
    for image_id in image_ids:
        list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
        convert_annotation(year, image_id)
    list_file.close()

# 合并多个文本文件
def mergeTxt(file_list,outfile):
    with open(outfile,'w') as wfd:
        for f in file_list:
            with open(f,'r') as fd:
                shutil.copyfileobj(fd,wfd)

file_list=['2007_train.txt','2007_val.txt','2012_train.txt','2012_val.txt']
outfile='train.txt'
mergeTxt(file_list,outfile)
file_list=['2007_train.txt','2007_val.txt','2007_test.txt','2012_train.txt','2012_val.txt']
outfile='train.all.txt'
mergeTxt(file_list,outfile)

#创建VOC文件夹及子文件夹
wd=os.getcwd()
data_base_dir=os.path.join(wd,"VOC/")
if not os.path.isdir(data_base_dir):
    os.mkdir(data_base_dir)
img_dir=os.path.join(data_base_dir,"images/")
if not os.path.isdir(img_dir):
    os.mkdir(img_dir)
img_train_dir=os.path.join(img_dir,"train/")
if not os.path.isdir(img_train_dir):
    os.mkdir(img_train_dir)
img_val_dir=os.path.join(img_dir,"val/")
if not os.path.isdir(img_val_dir):
    os.mkdir(img_val_dir)
label_dir=os.path.join(data_base_dir,"labels/")
if not os.path.isdir(label_dir):
    os.mkdir(label_dir)

label_train_dir=os.path.join(label_dir,"train/")
if not os.path.isdir(label_train_dir):
    os.mkdir(label_train_dir)

label_val_dir=os.path.join(label_dir,"val/")
if not os.path.isdir(label_val_dir):
    os.mkdir(label_val_dir)

print(os.path.exists('train.txt'))
f=open('train.txt','r')
lines=f.readlines()

#使用train.txt中的图片作为yolov5的训练集
for line in lines:
    line=line.replace('\n','')
    if(os.path.exists(line)):
        shutil.copy(line,"VOC/images/train") #复制图片
        print('coping train img file %s' %line +'\n')

    line=line.replace('JPEGImages','labels') #复制label
    line=line.replace('jpg','txt')
    if(os.path.exists(line)):
        shutil.copy(line,"VOC/labels/train")
        print('copying train label file %s' %line +'\n')

# 使用2007_test.txt中的图片作为yolov5验证集
print(os.path.exists('2007_test.txt'))
f=open('2007_test.txt','r')
lines=f.readlines()

for line in lines:
    line=line.replace('\n','')
    if(os.path.exists(line)):
        shutil.copy(line,"VOC/images/val") #复制图片
        print('coping val img file %s' %line +'\n')

    line=line.replace('JPEGImages','labels') #复制label
    line=line.replace('jpg','txt')
    if(os.path.exists(line)):
        shutil.copy(line,"VOC/labels/val")
        print('copying val img label  %s' %line +'\n')

1) 生成训练集和验证集
解压数据集

tar xf VOCtrainval_11-May-2012.tar
tar xf VOCtrainval_06-NOV-2007.tar
tar xf VOCtest_06-NOV-2007.tar

新建文件夹VOCdevkit,在该文件夹下新建VOC2007,VOC2012,将解压的2007的数据放在VOC2007中,解压的2012的数据放在VOC2012
执行python脚本:

python voc_label.py

VOCdevkt/VOC2007VOCdevkit/VOC2012目录下可以看到生成了文件夹labels;
在yolov5目录下生成了文件2007_train.txt,2007_val.txt,2007_test.txt,2012_train.txt,2012_val.txt,train.txt,train.all.txt

在VOC目录下生成了images和labels文件夹

  • labels下的文件是JPEGImages文件夹下每一个图像的yolo格式的标注文件,这是由annotationsxml标注文件转换来的
  • train.txt2007_test.txt分别给出了yolov5训练集和yolov5验证集图片的列表,含有每个图片的路径和文件名
  • VOC/images文件夹下有trainval文件夹,分别放置yolov5训练集和验证集图片:VOC/labels文件夹有trainval文件夹,分别放置yolov5训练集和验证集标签(yolo格式)

4. 修改配置文件

1) 新建文件data/voc-new.yaml
可以复制data/voc.yaml再根据自己的情况进行修改;可以重新命名如:data/voc-new.yaml
然后修改配置参数:

#download command/URL (optional)
#download:bash data/scripts/get_voc.sh

# train and val data as 1) directory:path/images/,2) file:path/images.txt,or 3) list:[path1/images/, path2/images/]
train:VOC/images/train/       # 16551 images
val:VOC/images/val/           # 4952 images

2) 新建文件models/yolov5s-voc.yaml
可以复制models/yolov5s.yaml再根据自己的情况修改;可以重新命名如:models/yolov5s-voc.yaml,然后修改配置参数

#parameters
nc:20 #number of cloass  

5. 训练自己的数据集

1) 训练命令
yolov5路径下执行

python train.py --data data/voc-new.yaml  --cfg models/yolov5s-voc.yaml --weights weights/yolov5s.pt  --batch-size 16 --epochs 200

注:训练过程如果提示GPU显存不足,可以把batch-size大小改小点,如4,8等在训练
2) 训练过程可视化tensorboard
在yolov5路径下执行

tensorboard  --logdir=./runs

6. 测试训练出的网络模型

1) 测试图片

python detect.py  --source ./VOC/images/val/000001.jpg --weights runs/exp0/weights/best.pt  --conf 0.4

YOLOV5 训练PASCAL VOC数据集_第3张图片
YOLOV5 训练PASCAL VOC数据集_第4张图片

你可能感兴趣的:(object,detection)