已记录一下自己的代码在GPU服务器端跑的时候流程和遇到的问题以及解决方法。
需要具备部分基础知识。
声明
国际惯例,写在前面
-----------------------------------------------------------------------------------------------
声明:本文章仅供个人学习之用,由于作者能力有限,相关观点和信息仅供参考。
如有侵权请联系。
欢迎各位读者老爷提问和交流。
我们的目标是星辰大海!
1. 准备情况
因为公司原因,通知xshell和xftp没有版权,不让用了。如何解决远程登录到服务器上成为了第一个问题。
01. 通过vscode实现远程连接服务器
(1)安装remote插件。
安装 Remote Development插件,会自动安装这么多个。
(2)连接到服务器
点击这里的加号,被水印挡住了,或者按按下shift+ctrl+p,输入Remote-SSH: Connect to Host。
输入你要远程访问的IP地址
你可以每次都输入密码,或者自行配置
Host代表连接的名称(自定义)
HostName是服务器的地址
IdentityFile是免密登录需要的 是本地id_rsa文件的路径
User是登录服务器的用户名
Port是端口号
IdentitiesOnly也是免密登录值为yes
02. 通过安装anaconda来安装虚拟环境
(1)下载anaconda
# 切换root用户,输入密码
su root
# 进入root目录,安装脚本存放路径
cd /root
# 下载anaconda安装脚本(本教程采用清华源)
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.07-Linux-x86_64.sh
# 安装anaconda
bash Anaconda3-2020.07-Linux-x86_64.sh
# Please, press ENTER to continue -> 回车继续
# 阅读协议,同意按回车(跳过ctrl+c)
# Do you accept the license terms? [yes|no] -> 同意协议输入yes回车
# Anaconda3 will now be installed into this location -> 选择安装路径(本文安装/usr/local/anaconda3),等待安装
# by running conda init? [yes|no] -> 是否添加系统环境,输入yes回车
# 待安装结束
# 刷新当前用户环境(激活环境)
source ~/.bashrc
#添加国内源
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
## 新建虚拟环境
conda create -n python36 python=3.6.5
# 删除虚拟环境
conda remove -n python36 --all
# 查看所有环境
conda env list
# 激活虚拟环境
conda activate python36
# 退出当前虚拟环境
conda deactivate python36
一定要记得最后一句,刷新
(2)使用conda安装requirement.txt,pip报错
$ git clone https://github.com/ultralytics/yolov5
$ cd yolov5
$ pip3 install -r requirements.txt
while read requirement; do conda install --yes $requirement || pip install $requirement; done < requirements.txt
03.训练自己数据集过程
(1)自己的数据集有几类,要和yaml文件中对应起来,我这里使用的是yolov5s,2类
(2) 照抄一个yaml文件,修改一下,需要按照自己的数据类型具体修改。
在data路径下,新建一个自己的xxx.yaml
需要修改的东西非常少,就是训练集,测试集,测试类别,类别名称。
但是需要注意的是,train:后面有个空格,跟的是你的数据的路径,注意,这里知道文件夹,当时看csdn看到一个写到train.txt的我一度以为我有问题
在这里我产生了问题,
我获取到的数据比较干净,在Annotations中是已经标注好的v5.txt格式 ,JPEGImages里面是原图片。
注意细节:
├── data
│ ├── Annotations 进行 detection 任务时的标签文件,xml 形式,文件名与图片名一一对应
│ ├── images 存放 .jpg 格式的图片文件
│ ├── ImageSets 存放的是分类和检测的数据集分割文件,包含train.txt, val.txt,trainval.txt,test.txt
│ ├── labels 存放label标注信息的txt文件,与图片一一对应
├── ImageSets(train,val,test建议按照8:1:1比例划分)
│ ├── train.txt 写着用于训练的图片名称
│ ├── val.txt 写着用于验证的图片名称
│ ├── trainval.txt train与val的合集
│ ├── test.txt 写着用于测试的图片名称
yolov5使用的是txt格式,每个图像对应一个txt文件,文件每一行为一个目标的信息,包括class,x_center,y_center,width,height格式。
格式如下:
那么问题来了。
很多朋友的数据都是标准的xml格式。
第一步,我们需要把xml转换成txt
xml2txt.py
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
#import shutil
sets = ['train', 'test', 'val']
#classes = ['1', '2', '3', '4', '5']
'''
classes = ['asamu', 'baishikele', 'baokuangli', 'aoliao', 'bingqilinniunai', 'chapai', 'fenda', 'guolicheng',
'haoliyou', 'heweidao', 'hongniu', 'hongniu2', 'hongshaoniurou', 'kafei', 'kaomo_gali', 'kaomo_jiaoyan',
'kaomo_shaokao', 'kaomo_xiangcon', 'kele', 'laotansuancai', 'liaomian', 'lingdukele', 'maidong', 'mangguoxiaolao',
'moliqingcha', 'niunai', 'qinningshui', 'quchenshixiangcao', 'rousongbing', 'suanlafen', 'tangdaren', 'wangzainiunai',
'weic', 'weitanai', 'weitaningmeng', 'wulongcha', 'xuebi', 'xuebi2', 'yingyangkuaixian', 'yuanqishui', 'xuebi-b', 'kebike',
'tangdaren3', 'chacui', 'heweidao2', 'youyanggudong', 'baishikele-2', 'heweidao3', 'yibao', 'kele-b', 'AD', 'jianjiao', 'yezhi',
'libaojian', 'nongfushanquan', 'weitanaiditang', 'ufo', 'zihaiguo', 'nfc', 'yitengyuan', 'xianglaniurou', 'gudasao', 'buding',
'ufo2', 'damaicha', 'chapai2', 'tangdaren2', 'suanlaniurou', 'bingtangxueli', 'weitaningmeng-bottle', 'liziyuan', 'yousuanru',
'rancha-1', 'rancha-2', 'wanglaoji', 'weitanai2', 'qingdaowangzi-1', 'qingdaowangzi-2', 'binghongcha', 'aerbeisi', 'lujikafei',
'kele-b-2', 'anmuxi', 'xianguolao', 'haitai', 'youlemei', 'weiweidounai', 'jindian', '3jia2', 'meiniye', 'rusuanjunqishui',
'taipingshuda', 'yida', 'haochidian', 'wuhounaicha', 'baicha', 'lingdukele-b', 'jianlibao', 'lujiaoxiang', '3+2-2',
'luxiangniurou', 'dongpeng', 'dongpeng-b', 'xianxiayuban', 'niudufen', 'zaocanmofang', 'wanglaoji-c', 'mengniu',
'mengniuzaocan', 'guolicheng2', 'daofandian1', 'daofandian2', 'daofandian3', 'daofandian4', 'yingyingquqi', 'lefuqiu']
'''
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)
path = 'your path'# /a/Annotations 这里就是路径到a
def convert_annotation(image_id):
in_file = open(path+'Annotations/%s.xml' % (image_id))
#print(111,in_file)
out_file = open(path+'labels/%s.txt' % (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'):
#try:
#difficult = obj.find('difficult').text
#except AttributeError:
# 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()
print(wd)
for image_set in sets:
if not os.path.exists(path+'labels/'):
os.makedirs(path+'labels/')
image_ids = open(path+'ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
#print(111,image_ids)
list_file = open(path+'%s.txt' % (image_set), 'w')
for image_id in image_ids:
list_file.write(path+'images/%s.jpg\n' % (image_id))
convert_annotation(image_id)
list_file.close()
第二步,把一个整个的数据集进行切割,比如你有100张数据,80张用来训练,20张用来测试。
# -*- coding: utf-8 -*-
import os
import random
trainval_percent = 0.2
train_percent = 0.8
xmlfilepath = 'hat_data/Annotations'
txtsavepath = 'hat_data/ImageSets/Main/'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
ftrainval = open(txtsavepath+'trainval.txt', 'w')
ftest = open(txtsavepath+'test.txt', 'w')
ftrain = open(txtsavepath+'train.txt', 'w')
fval = open(txtsavepath+'val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
这样会生成几个文件
第三步,按照文件把文件进行划分,
在yolov5中标准对应的是images和labels,你可以修改成自己的文件名字,但是那样子你得在/data/dataset.py中进行修改代码,反正都可以,
# -*- coding: utf-8 -*-
import os
import shutil
def locate(path):
temp = []
with open(path+'val.txt','rb') as f:
#r = f.readlines()
for line in f.readlines():
#print(str(line.strip()).split("'")[1])
temp.append(str(line.strip()).split("'")[1])
return temp
def object_save(path,pic,pic_save):
temp = locate(path)
#print(temp)
if not os.path.exists(pic_save+'val'):
os.makedirs(pic_save+'val')
if not os.path.exists(pic_save+'train'):
os.makedirs(pic_save+'train')
for i in os.listdir(pic):
if i[:-4] in temp:
print(i)
shutil.copyfile(pic+i,pic_save+'val/'+i)
else:
shutil.copyfile(pic+i,pic_save+'train/'+i)
if __name__ == '__main__':
ImageSets_path = './ImageSets/Main/'
pic_path = './JPEGImages/'
pic_save_path = './images/'
object_save(ImageSets_path,pic_path,pic_save_path)
labels_path = './Annotations/'
labels_save_path = './labels/'
object_save(ImageSets_path,labels_path,labels_save_path)
(3)修改train.py
(4)python train.py
各种BUG
1.AssertionError: train: No labels in images/train.cache. Can not train without labels. See https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data
查了网上很多资料,出现这个问题都在数据格式转换上面,我再三检查,我没什么问题。
改来改去,把yaml中路径换成了绝对路径,可以了。
老人,地铁,手机