一步一步带你训练自己的SSD检测算法_ssd训练自己的数据集

#########################4、对.json格式的标签文件进行处理#######################
# coding=utf-8
import os
import numpy as np
import codecs
import json
from glob import glob
import cv2
import shutil
from sklearn.model_selection import train_test_split
#1.标签路径
labelme_path = "./xxx/"                 # 原始xxx标注数据路径,需要更换成自己的数据集名称
saved_path = "./datasets/VOC2007/"      # 保存路径

#2.创建要求文件夹
if not os.path.exists(saved_path + "Annotations"):
    os.makedirs(saved_path + "Annotations")
if not os.path.exists(saved_path + "JPEGImages/"):
    os.makedirs(saved_path + "JPEGImages/")
if not os.path.exists(saved_path + "ImageSets/Main/"):
    os.makedirs(saved_path + "ImageSets/Main/")
    
#3.获取待处理文件
files = glob(labelme_path + "\*.json")
files = [i.split("/")[-1].split(".json")[0] for i in files]

#4.读取标注信息并写入 xml
for json_file_ in files:
    json_filename = labelme_path + json_file_ + ".json"
    json_file = json.load(open(json_filename,"r",encoding="utf-8"))
    height, width, channels = cv2.imread(labelme_path + json_file_ +".jpg").shape
    with codecs.open(saved_path + "Annotations/"+json_file_ + ".xml","w","utf-8") as xml:
        xml.write('<annotation>\n')
        xml.write('\t<folder>' + 'UAV\_data' + '</folder>\n')
        xml.write('\t<filename>' + json_file_ + ".jpg" + '</filename>\n')
        xml.write('\t<source>\n')
        xml.write('\t\t<database>The Defect Detection</database>\n')
        xml.write('\t\t<annotation>Defect Detection</annotation>\n')
        xml.write('\t\t<image>flickr</image>\n')
        xml.write('\t\t<flickrid>NULL</flickrid>\n')
        xml.write('\t</source>\n')
        xml.write('\t<owner>\n')
        xml.write('\t\t<flickrid>NULL</flickrid>\n')
        xml.write('\t\t<name>WZZ</name>\n')
        xml.write('\t</owner>\n')
        xml.write('\t<size>\n')
        xml.write('\t\t<width>'+ str(width) + '</width>\n')
        xml.write('\t\t<height>'+ str(height) + '</height>\n')
        xml.write('\t\t<depth>' + str(channels) + '</depth>\n')
        xml.write('\t</size>\n')
        xml.write('\t\t<segmented>0</segmented>\n')
        for multi in json_file["shapes"]:
            points = np.array(multi["points"])
            xmin = min(points[:,0])
            xmax = max(points[:,0])
            ymin = min(points[:,1])
            ymax = max(points[:,1])
            label = multi["label"]
            if xmax <= xmin:
                pass
            elif ymax <= ymin:
                pass
            else:
                xml.write('\t<object>\n')
                xml.write('\t\t<name>'+json_file["shapes"][0]["label"]+'</name>\n')
                xml.write('\t\t<pose>Unspecified</pose>\n')
                xml.write('\t\t<truncated>1</truncated>\n')
                xml.write('\t\t<difficult>0</difficult>\n')
                xml.write('\t\t<bndbox>\n')
                xml.write('\t\t\t<xmin>' + str(xmin) + '</xmin>\n')
                xml.write('\t\t\t<ymin>' + str(ymin) + '</ymin>\n')
                xml.write('\t\t\t<xmax>' + str(xmax) + '</xmax>\n')
                xml.write('\t\t\t<ymax>' + str(ymax) + '</ymax>\n')
                xml.write('\t\t</bndbox>\n')
                xml.write('\t</object>\n')
                print(json_filename,xmin,ymin,xmax,ymax,label)
        xml.write('</annotation>')
        
#5.复制图片到 VOC2007/JPEGImages/下
image_files = glob(labelme_path + "\*.jpg")
print("copy image files to VOC007/JPEGImages/")
for image in image_files:
    shutil.copy(image,saved_path +"JPEGImages/")
    
#6.split files for txt
txtsavepath = saved_path + "ImageSets/Main/"
ftrainval = open(txtsavepath+'/trainval.txt', 'w')
ftest = open(txtsavepath+'/test.txt', 'w')
ftrain = open(txtsavepath+'/train.txt', 'w')
fval = open(txtsavepath+'/val.txt', 'w')
total_files = glob("./VOC2007/Annotations/\*.xml")
total_files = [i.split("/")[-1].split(".xml")[0] for i in total_files]
test_filepath = "./test"
for file in total_files:
    ftrainval.write(file + "\n")
#test
for file in os.listdir(test_filepath):
    ftest.write(file.split(".jpg")[0] + "\n")
#split
train_files,val_files = train_test_split(total_files,test_size=0.15,random_state=42)
#train
for file in train_files:
    ftrain.write(file + "\n")
#val
for file in val_files:
    fval.write(file + "\n")

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

3.3 COCO数据集格式详解
COCO_ROOT
|__ annotations
    |_ instances_valminusminival2014.json
    |_ instances_minival2014.json
    |_ instances_train2014.json
    |_ instances_val2014.json
    |_ ...
|__ train2014
    |_ <im-1-name>.jpg
    |_ ...
    |_ <im-N-name>.jpg
|__ val2014
    |_ <im-1-name>.jpg
    |_ ...
    |_ <im-N-name>.jpg
|__ ...

1、COCO_ROOT表示自己的数据集所在的文件夹的名称;
2、annotations文件夹用来存放标签文件,instances_train2014.json和instances_val2014.json分别表示训练集和验证集的标签;
3、train2014和val2014文件夹分别用来存储训练集和验证集的图片,命名格式为im-N-name.jpg的格式;

3.4 构造新的COCO数据集

本文更倾向于生成VOC格式的数据集,如果你需要生成COCO格式的数据,请参考博文1博文2

4、搭建SSD运行环境

# 克隆一份SSD代码到本地
git clone https://github.com/lufficc/SSD.git 
cd SSD
# 创建conda虚拟环境
conda create -n ssd python=3.6
# 激活虚拟环境
conda activate ssd
# 安装相应的python依赖包
pip install torch torchvision yacs tqdm opencv-python vizer
pip install tensorboardX

# 克隆一份cocoapi到本地
git clone https://github.com/cocodataset/cocoapi.git
# 切换到PythonAPI路径并安装
cd cocoapi/PythonAPI
python setup.py build_ext install
# 切换到ext文件夹
cd ext
# 编译NMS等操作,用来加速网络的训练过程
python build.py build_ext develop

5、修改代码训练网络

5.1 代码架构详解
configs-该文件夹下面存放的是不同的网络配置文件;
	mobilenet_v2_ssd320_voc0712.yaml-表示mobilenet backbone的配置文件;
	vgg_ssd512_voc0712.yaml-表示vgg backbone的配置文件;
datasets-该文件夹存放数据文件,具体的结果看上文;
demo-该文件夹存放一些测试图片;
ext-该文件夹存放CPU和GPU版本的NMS代码;
figures-该文件夹存放网络训练过程中的一些可视化文件;
outputs-该文件夹存放训练过程中的log文件和模型文件(.pth);
demo.py-该文件用来测试新的图片并输出检测结果;
train.py-该文件用来训练网络;
test.py-该文件用来测试网络;
ssd-该文件夹中存放ssd算法的实现代码;
	config-该文件夹存放着默认的配置文件;
	data-该文件夹中存放着基本的数据预处理源文件,包括voc和coco数据集;
	engine-该文件夹中存放着基本的训练和推理引擎的实现源码;
	layers-该文件夹中存放着separable_conv的实现源码;
	modeling-该文件夹中存放着SSD网络的Backbone和head网络的源码;
	solver-该文件中存放着SSD网络中使用到的优化器的源码;
	structures-该文件夹中存放着一些Box的help函数的源码;
	utils-该文件夹中存放着一些训练和推理SSD算法的小工具的源码:

5.2 修改网络配置参数
mv datasets SSD                          # 将构造好的VOC数据集移动到SSD文件夹中
cd configs                               # 切换到配置文件夹下面
vim vgg_ssd512_voc0712.yaml              # 使用vim打开配置文件

注:
1、vgg_ssd512_voc0712.yaml表示使用VGG作为基准网络,SSD网络的输入大小为512x512 ,使用VOC2007格式的数据集来训练新的网络,大量的实验结果表明该配置参数下能够获得最好的检测效果
2、vgg_ssd300_voc0712.yaml表示使用VGG作为基准网络,SSD网络的输入大小为300x300 ,使用VOC2007格式的数据集来训练新的网络,由于输入图片的分辨率由512减小到300,整个网络的训练速度得到了提升,但是效果不如vgg_ssd512_voc0712.yaml架构
3、mobilenet_v2_ssd320_voc0712.yaml表示使用Mobilenet_v2作为基准网络,SSD网络的输入大小为300x300 ,使用VOC2007格式的数据集来训练新的网络,由于使用Mobilenet_v2作为基准网络,因此该架构下面的训练速度最快,但是最终获得精度也是最差的,这个架构适合于一些简单的检测任务,Mobilenet_v2不能能够获得较好的检测效果,而且可以获得接近实时的推理速度

###############################修改前的网络配置###############################
MODEL:
  NUM_CLASSES: 21
  BACKBONE:
    OUT_CHANNELS: (512, 1024, 512, 256, 256, 256, 256)
  PRIORS:
    FEATURE_MAPS: [64, 32, 16, 8, 4, 2, 1]
    STRIDES: [8, 16, 32, 64, 128, 256, 512]
    MIN_SIZES: [35.84, 76.8, 153.6, 230.4, 307.2, 384.0, 460.8]
    MAX_SIZES: [76.8, 153.6, 230.4, 307.2, 384.0, 460.8, 537.65]
    ASPECT_RATIOS: [[2], [2, 3], [2, 3], [2, 3], [2, 3], [2], [2]]
    BOXES_PER_LOCATION: [4, 6, 6, 6, 6, 4, 4]
INPUT:
  IMAGE_SIZE: 512
DATASETS:
  TRAIN: ("voc\_2007\_trainval", "voc\_2012\_trainval")
  TEST: ("voc\_2007\_test", )
SOLVER:
  MAX_ITER: 120000
  LR_STEPS: [80000, 100000]
  GAMMA: 0.1
  BATCH_SIZE: 24
  LR: 1e-3

OUTPUT_DIR: 'outputs/vgg\_ssd512\_voc0712'

###############################修改后网络配置###############################
MODEL:
  NUM_CLASSES: 18
  BACKBONE:
    OUT_CHANNELS: (512, 1024, 512, 256, 256, 256, 256)
  PRIORS:
    FEATURE_MAPS: [64, 32, 16, 8, 4, 2, 1]
    STRIDES: [8, 16, 32, 64, 128, 256, 512]
    MIN_SIZES: [35.84, 76.8, 153.6, 230.4, 307.2, 384.0, 460.8]
    MAX_SIZES: [76.8, 153.6, 230.4, 307.2, 384.0, 460.8, 537.65]
    ASPECT_RATIOS: [[2], [2, 3], [2, 3], [2, 3], [2, 3], [2], [2]]
    BOXES_PER_LOCATION: [4, 6, 6, 6, 6, 4, 4]
INPUT:
  IMAGE_SIZE: 512
DATASETS:
  TRAIN: ("voc\_2007\_trainval",)
  TEST: ("voc\_2007\_test", )

SOLVER:
  MAX_ITER: 120000
  LR_STEPS: [80000, 100000]
  GAMMA: 0.1
  BATCH_SIZE: 12
  LR: 1e-4

OUTPUT_DIR: 'outputs/vgg\_ssd512\_voc0712'

注:
1、NUM_CLASSES参数表示检测的类型,由于当前的缺陷数据集的类别数目为17,另外加上一个__background__类,因此需要将该数值修改为17+1=18;
2、BATCH_SIZE参数表示每次训练的图片的个数,由于训练的图片需要加载到内存中,该数值和你当前使用的显卡的内容有着密切的关系,我根据自己的显卡(Tesla T4)将BATCH_SIZE调整为12
3、LR参数表示网络训练时的学习率,由于我设置的迭代次数比较多,害怕网络跳过最优值,因而我将LR调整为1e-4
4、TRAIN参数表示网络训练时使用的数据集,由于我们新建了一个类似于VOC2007的数据集,因而我删除了voc_2012_trainval
5、其它的这些配置参数,你可以根据自己的需要进行修改,但是我建议你不用修改

5.3 修改VOC类别参数
cd .ssd/data/datasets                # 1、切换到datasets文件夹
vim voc.py                           # 2、打开voc文件 

###############################修改前的类别###############################
class_names = ('\_\_background\_\_',
               'aeroplane', 'bicycle', 'bird', 'boat',
               'bottle', 'bus', 'car', 'cat', 'chair',
               'cow', 'diningtable', 'dog', 'horse',
               'motorbike', 'person', 'pottedplant',
               'sheep', 'sofa', 'train', 'tvmonitor')

###############################修改后的类别###############################
 class_names = ('\_background\_', 'Buttercup', 'Colts Foot', 'Daffodil', 
 				'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'Pansy', 
 				'Sunflower', 'Windflower', 'Snowdrop', 'LilyValley',
 				'Bluebell', 'Crocus', 'Tigerlily', 'Tulip', 'Cowslip')


5.4 下载模型
# 下载vgg\_ssd300\_voc0712.pth预训练模型
wget https://github.com/lufficc/SSD/releases/download/1.2/vgg_ssd300_voc0712.pth
# 下载vgg\_ssd512\_voc0712.pth预训练模型
wget https://github.com/lufficc/SSD/releases/download/1.2/vgg_ssd512_voc0712.pth
# 下载mobilenet\_v2\_ssd320\_voc0712.pth预训练模型
wget https://github.com/lufficc/SSD/releases/download/1.2/mobilenet_v2_ssd320_voc0712.pth
# 创建.torch文件夹用来存放模型
mkdir ~/.torch/
# 将预训练好的模型移动到这个文件夹中
mv vgg_ssd300_voc0712.pth ~/.torch
mv vgg_ssd512_voc0712.pth ~/.torch
mv mobilenet_v2_ssd320_voc0712.pth ~/.torch

5.5 训练模型
# 导入环境变量VOC\_ROOT
export VOC\_ROOT="./datasets"
# 使用vim打开train.py文件
vim train.py

###############################修改前网络训练参数###############################
parser = argparse.ArgumentParser(description='Single Shot MultiBox Detector Training With PyTorch')
# 设置使用的配置文件
parser.add_argument( "--config-file", default="", metavar="FILE", help="path to config file",type=str)
# 设置是否进行local\_rank
parser.add_argument("--local\_rank", type=int, default=0)
# 设置保存log的步长
parser.add_argument('--log\_step', default=10, type=int, help='Print logs every log\_step')
# 设置保存checkpoint文件的步长
parser.add_argument('--save\_step', default=2500, type=int, help='Save checkpoint every save\_step')
# 设置执行网络评估操作的步长
parser.add_argument('--eval\_step', default=2500, type=int, help='Evaluate dataset every eval\_step, disabled when eval\_step < 0')
# 设置是否使用tensorboard进行loss和accuracy的可视化
parser.add_argument('--use\_tensorboard', default=True, type=str2bool)
parser.add_argument("--skip-test", dest="skip\_test", help="Do not test the final model", action="store\_true")
# 设置是否打开使用命令行来改变参数
parser.add_argument("opts", help="Modify config options using the command-line", default=None, nargs=argparse.REMAINDER)
args = parser.parse_args()

###############################修改后网络训练参数###############################
parser = argparse.ArgumentParser(description='Single Shot MultiBox Detector Training With PyTorch')
parser.add_argument("--config-file", default="configs/vgg\_ssd512\_voc0712.yaml", metavar="FILE", help="path to config file", type=str)
parser.add_argument("--local\_rank", type=int, default=0)
parser.add_argument('--log\_step', default=20, type=int, help='Print logs every log\_step')
parser.add_argument('--save\_step', default=2500, type=int, help='Save checkpoint every save\_step')
parser.add_argument('--eval\_step', default=2500, type=int, help='Evaluate dataset every eval\_step, disabled when eval\_step < 0')
parser.add_argument('--use\_tensorboard', default=True, type=str2bool)
parser.add_argument("--skip-test", dest="skip\_test", help="Do not test the final model", action="store\_true")
parser.add_argument("opts", help="Modify config options using the command-line", default=None, nargs=argparse.REMAINDER)
args = parser.parse_args()

注:
1、为了便于后续的代码运行,这里直接将–config-file的默认参数设置为vgg_ssd512_voc0712.yaml,即使用VGG作为基准网路,输入大小为512x512,使用自己创建的VOC2007格式的数据集训练新的模型。
2、对于其它的一些超参数,不建议你去改动。

# 如果你有一个GPU,执行该指令训练模型
python train.py
# 如果你有4个GPU,执行该指令训练模型
export NGPUS=4
python -m torch.distributed.launch --nproc_per_node=$NGPUS train.py

注:
1、下面展示是网络训练过程中输出的配置参数。
在这里插入图片描述
2、下面展示的是网络训练过程中的Loss、Accuracy和运行时间等输出。
在这里插入图片描述

5.6 Loss和Accuracy可视化

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
img

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。

本份面试集锦涵盖了

  • 174 道运维工程师面试题
  • 128道k8s面试题
  • 108道shell脚本面试题
  • 200道Linux面试题
  • 51道docker面试题
  • 35道Jenkis面试题
  • 78道MongoDB面试题
  • 17道ansible面试题
  • 60道dubbo面试题
  • 53道kafka面试
  • 18道mysql面试题
  • 40道nginx面试题
  • 77道redis面试题
  • 28道zookeeper

总计 1000+ 道面试题, 内容 又全含金量又高

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-tYYdB0py-1712774349844)]

  • 21
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值