在darknet版的yoloV4中。data文件中train.txt中只提供了图像的路径,那标签文件是怎么对应读取的呢?
在源码中,找到下面这个函数可以看到:
void replace_image_to_label(const char* input_path, char* output_path)
{
find_replace(input_path, "/images/train2014/", "/labels/train2014/", output_path); // COCO
find_replace(output_path, "/images/val2014/", "/labels/val2014/", output_path); // COCO
find_replace(output_path, "/JPEGImages/", "/labels/", output_path); // PascalVOC
find_replace(output_path, "\\images\\train2014\\", "\\labels\\train2014\\", output_path); // COCO
find_replace(output_path, "\\images\\val2014\\", "\\labels\\val2014\\", output_path); // COCO
find_replace(output_path, "\\JPEGImages\\", "\\labels\\", output_path); // PascalVOC
//find_replace(output_path, "/images/", "/labels/", output_path); // COCO
//find_replace(output_path, "/VOC2007/JPEGImages/", "/VOC2007/labels/", output_path); // PascalVOC
//find_replace(output_path, "/VOC2012/JPEGImages/", "/VOC2012/labels/", output_path); // PascalVOC
//find_replace(output_path, "/raw/", "/labels/", output_path);
trim(output_path);
// replace only ext of files
find_replace_extension(output_path, ".jpg", ".txt", output_path);
find_replace_extension(output_path, ".JPG", ".txt", output_path); // error
find_replace_extension(output_path, ".jpeg", ".txt", output_path);
find_replace_extension(output_path, ".JPEG", ".txt", output_path);
find_replace_extension(output_path, ".png", ".txt", output_path);
find_replace_extension(output_path, ".PNG", ".txt", output_path);
find_replace_extension(output_path, ".bmp", ".txt", output_path);
find_replace_extension(output_path, ".BMP", ".txt", output_path);
find_replace_extension(output_path, ".ppm", ".txt", output_path);
find_replace_extension(output_path, ".PPM", ".txt", output_path);
find_replace_extension(output_path, ".tiff", ".txt", output_path);
find_replace_extension(output_path, ".TIFF", ".txt", output_path);
// Check file ends with txt:
if(strlen(output_path) > 4) {
char *output_path_ext = output_path + strlen(output_path) - 4;
if( strcmp(".txt", output_path_ext) != 0){
fprintf(stderr, "Failed to infer label file name (check image extension is supported): %s \n", output_path);
}
}else{
fprintf(stderr, "Label file name is too short: %s \n", output_path);
}
}
以PascalVOC数据集为例,程序会自动把图像路径中的/JPEGImages/ 替换为 /labels/
然后把文件扩展名替换为txt 就得到对应的标签文件路径了
所以我们在任一路径下可以新建两个文件夹
-JPEGImages #放入所有的训练图片文件
-labels #放入所有的txt文件,会自动生成此文件夹
后来想想,只要得到图像的全路径就可以,文件夹都不用创建,标签文件也不用分开,直接放在一个文件夹,执行下面的程序,会自动给你划分出训练集和验证集,更简单!
执行下面的Python程序
import os
# iter floder
def iter_files(rootDir, extend_name):
file_list = []
fileName = []
#Iterate over the roots
for root,dirs,files in os.walk(rootDir):
for file_name in files:
root = os.path.normpath(root) #格式化路径 斜杠问题 / -> \
file_path = os.path.join(root, file_name) # 连接路径
file_path = file_path.replace("\\", "/")
flag = file_path.endswith(extend_name)
if flag:
file_list.append(file_path)
fileName.append(os.path.splitext(file_name)[0])
return file_list, fileName
# split train and val
def split_train_val(fileList):
trainFile = open('train.txt', 'a')
validFile = open('val.txt', 'a')
num = 0
for files in fileList:
num = num + 1
if num % 4 == 0:
validFile.write(files + '\n')
else:
trainFile.write(files + '\n')
trainFile.close()
validFile.close()
if __name__ == '__main__':
root = 'D:/Python/images/JEPGImages' #训练图像的路径
[fileList, fileName] = iter_files(root, 'png')
split_train_val(fileList)
这样我们就直接得到了训练集和验证集的txt文件,前提是你直接有txt格式的标注文件,不是xml的。不然还是需要之前的那篇教程。
后面就简简单单改几个地方,就能训练起来了!
新建obj.names
复制data目录下的voc.name,改为obj.name,里面写标签的名字,每行一个
新建obj.data
复制cfg文件夹下的voc.data,重命名为obj.data
classes= 1 # 类别的数量
train = train.txt # 上一步生成的train.txt的相对路径或绝对路径
valid = val.txt # 上一步生成的val.txt的相对路径或绝对路径
names = data/obj.names # 保存的类别标签
backup = backup/ # 权重保存的位置
修改cfg文件
把第三行batch改为batch=64
把subdivisions那一行改为 subdivisions=16
将max_batch更改为(数据集标签种类数(classes)*2000 但不小于训练的图片数量以及不小于6000)
将第20的steps改为max_batch的0.8倍和0.9倍
把位于8-9行设为width=416 height=416 或者其他32的倍数:
将classes=80 改为你的类别数 (有三个地方,969行,1056行,1143行)
改正[filters=255] 为 filters=(classes + 5)x3 (位置为查找yolo,每个yolo前的[convolutional]里,注意只修改最接近yolo的那个filters需要修改,一共应该有三处)
如果使用 [Gaussian_yolo] 层,修改 filters=(classes + 9)x3 (位置为CRRL+F查找Gaussian_yolo,每个Gaussian_yolo前的[convolutional]里,注意只修改最接近Gaussian_yolo的那个filters需要修改,一共应该有三处)
训练数据
开始训练
yolov4.conv.137为预训练权重,没有的话会随机初始化权重
预训练权重,密码:jirs
darknet.exe detector train data/obj.data yolov-obj.cfg yolov4.conv.137 -map
mAP(均值平均精度) = 所有类别的平均精度求和除以所有类别
每4个Epochs计算一次map
训练生成的权重文件在<backup>目录下:
last_weights 每迭代100次保存一次
xxxx_weights 每迭代1000次保存一席
继续训练
每迭代100步可以手动停止,下次训练加载此次的权重文件便可以接着训练。
eg:从2000步停止训练后,可以使用如下命令继续训练
darknet.exe detector train data/obj.data yolo-obj.cfg backup\yolo-obj_2000.weights
停止训练
停止训练的条件:
训练过程中如果 avg出现nan,训练可能出错,需要停止
如果nan出现在其他行,训练正常
如果迭代很多次后avg补再下降,需要停止
avg越低越好—,也要防止过拟合
对小的模型、简单的数据集,avg一般为0.05
对大的模型、复杂的数据集,avg一般为3
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210626103746201.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NodWFpamllZXI=,size_16,color_FFFFFF,t_70)