根据导师的项目要求,需要快速完成一个简单的水下目标神经网络,在做了一些基础调研之后决定使用yolov3(darknet)来实现。
整个工作流程主要按照以下的顺序展开:
- 制作水下目标数据集,从开源数据集中寻找合适的数据集。
- 选用并配置GPU服务器。
- 根据网上的darknet迁移学习相关博客完成神经网络的训练。
本文章主要记载一些整个过程中碰见的各种小问题。
1.寻找整理数据集
在最初的寻找过程当中,发现github上已经有人对水下数据集进行过了一个整理,网址是:
其中个人感觉下载看过的主要是以下两个:
Fish Recognition Ground-Truth data :这个数据集包含了23种鱼类的原始图片以及mask图片,可以用来做分割,也可以自行借助opencv提取以下矩形框用来做常规的YOLO之类的目标检测算法。
Labeled Fishes in the Wild :这个数据集相比上一个更清晰而且对背景进行了处理,但是由于数据集提供的标注文件不会用所以最后没有选用。文件大概如下。
Openimage:openimage是一个具有超过600个种类的大型数据集,其中的每个种类基本都有完整的标注,可以借助下载工具分别下载。
本项目中最后是选用了Openimage dataset作为训练的数据集。
1.1Openimage鱼类数据集的下载与整理
可以使用github上的开源工具进行下载(开源下载工具),下载完成后可以使用工具自带的可视化工具检查筛选数据集。完成筛选后,还需要生成yolo网络所需的labels文件,可以使用开源工具(转换工具)。转换原理是检索种类名,根据文件名和种类名在对应CSV文件中提取,并将矩形框的标注方法(Xmin,Xmax,Ymin,Ymax)转换为yolo的标注方法(中心点x,中心点y,框宽w,框高h)。在具体操作过程中发现,工具的方法转换后生成的txt文件会有双倍的标注信息,因此用panda简单处理了一下。
import os
rootdir = os.listdir("")
#labels所在的文件夹目录
path = ""
#labels所在的文件夹目录
newpath = ""
#去重后放入新文件夹
for file in rootdir:
position = path+'\\'+ file #构造绝对路径,"\\",其中一个'\'为转义符
print (position)
data = pd.read_table(position,sep=' ',header=None) #读取文件
data.drop_duplicates(keep='first',inplace=True)
data.to_csv(newpath+'\\'+ file,index=False, header=None,sep=" ")
print(data)
#在windows下实现,Linux中使用需修改'\\'为'/'
1.2 数据集处理
数据集处理主要有几个过程,切片,文件名校对还有写入图片地址到train.txt和val.txt中,用于训练时提供引导。
数据集本身提供了train、vaild和test数据集,但由于都需要分别操作,因此只使用了train数据集本身,按比例切分了一下作为实际训练的train和validation数据集。
在使用darknet训练时发现,yolocv3.cfg的配置需要将labels与img放在同一个文件夹中,因此在切片之前先检查一次有无单个的文件。
#检查文件夹内labels和image是否一一对应,匹配后切片分别写入train.txt和val.txt
import os
import random
file_list = []
file_path = '/home/featurize/data/Image'
rootdir = os.listdir(file_path)
for filename in os.listdir(file_path):
file_list.append(filename.split('.')[0])
print(len(file_list))
list_one = list(set(file_list)) #去重
print(len(list_one)) #判断file_list数量是否是list_one的两倍
from collections import Counter
single = Counter(file_list)
print(single)
#把单独出现的文件手动处理一下
数据集切片:
num = int(0.16*len(list_one)) #分配抽样数
print(random_num)
random.shuffle(list_one) #打乱列表
val_list = list_one[0:num] #取valid
train_list = list_one[(num):(len(rootdir)+2)] #取train
print(len(choice_list))
print(len(train_list))
x = [k for k in choice_list if k in train_list] #判断一下两个数据集中有无重复的文件
print(x)
#生成train和val的txt
txt_path = '/home/featurize/data' #保存train.txt和val.txt的目录
image_path = '/home/featurize/data/Image' #图片引导目录
for num in range(len(choice_list)):
with open(txt_path +"/"+"val.txt",'a') as f:
f.write(image_path +"/"+val_list[num]+'.jpg'+'\n')
#print(path +"\\"+choice_list[num])
f.close()
for num2 in range(len(train_list)):
with open(txt_path +"/"+"train.txt",'a') as f:
f.write(image_path +"/"+train_list[num2]+'.jpg'+'\n')
#print(path +"\\"+choice_list[num])
f.close()
#在featurize GPU服务器中实现,基于ubuntu
#推荐一下 featurize算力共享平台 (https://featurize.cn?s=e456c1d684fb4a17ab5816bb9f556af1)