darkent是个轻量级深度学习训练框架,用c和cuda编写,支持GPU加速。你可以理解为darknet和tensorflow, pytorch, caffe, mxnet一样,是用于跑模型的底层,像resnet、yolo是模型结构,是一种训练网络
darknet是YOLO作者自己写的一个深度学习框架(见YOLO原文2.2部分),后来在YOLO9000中又提了一个基于ResNet魔改的19层卷积网络,称为Darknet-19,在YOLOv3中又提了一个更深的Darknet-53,这两个都是用于提取特征的主干网络。像yolov2、v3、v4、v7都可以在Darknet框架上实现(yolov5是用pytorch)。其主要特点就是容易安装,没有任何依赖项(OpenCV都可以不用),移植性非常好,支持CPU与GPU两种计算方式。
采用底层C语言有利于运行效率的提高,对一些算法库依赖有利于减轻体量,移植性独立性好可以多用于嵌入式等小算力小成本板子(不包括训练)。
相比于TensorFlow与pytorch这些大框架来说,darknet并没有那么强大,但darknet也有自己的优势:
1.易于安装:在makefile里面选择自己需要的附加项(cuda,cudnn,opencv等)直接make即可,几分钟完成安装;
2.没有任何依赖项:整个框架都用C语言进行编写,可以不依赖任何库,连opencv作者都编写了可以对其进行替代的函数;
3.结构明晰,源代码查看、修改方便:其框架的基础文件都在src文件夹,而定义的一些检测、分类函数则在example文件夹,可根据需要直接对源代码进行查看和修改;
4.友好python接口:虽然darknet使用c语言进行编写,但是也提供了python的接口,通过python函数,能够使用python直接对训练好的.weight格式的模型进行调用;
5.易于移植:该框架部署到机器本地十分简单,且可以根据机器情况,使用cpu和gpu,特别是检测识别任务的本地端部署,darknet会显得异常方便。
一些非本文重点但会用到的:
NoMachine安装与使用
NoMachine用于远程连接服务器,前提是你的服务器允许外网连接。
FileZilla安装与使用
FileZilla用于本地与服务器连接进行文件传输,前提是你的服务器允许外网连接。
服务器使用多用户,避免影响主用户。
github官网AB版
make
来源:第十五届中国计算机设计大赛智慧导盲组基线系统
结构:
WisdomGuide______annotations______train_list.txt
| |___val_list.txt
| |___instance_train.json
| |___instance_val.json
|___train______JPECImges___图片png
| |___labels___标签txt
|___val______JPECImges___图片png
|___labels___标签txt
修改数据集的分布,新建train、val、JPECImges和labels文件夹,其中train是存放训练集,val存放测试集,JPECImges放图片,labels放标签文件,train_list.txt是所有训练图片路径,val_list.txt是所有测试图片路径。这些文件的建立与分布是有规律有原因的,如果不想修改代码就用这个数据集格式。
train_list.txt、val_list.txt、标签txt文件由下面的脚本生成。
json_txt.py:
更改成自己的路径
import os
import json
from tqdm import tqdm
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--json_path', default='/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/instance_val.json', type=str, help="input: coco format(json)")
parser.add_argument('--save_path', default='/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/val_txt', type=str, help="specify where to save the output dir of labels")
arg = parser.parse_args()
def convert(size, box):
dw = 1. / (size[0])
dh = 1. / (size[1])
x = box[0] + box[2] / 2.0
y = box[1] + box[3] / 2.0
w = box[2]
h = box[3]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
if __name__ == '__main__':
json_file = arg.json_path # COCO Object Instance 类型的标注
ana_txt_save_path = arg.save_path # 保存的路径
data = json.load(open(json_file, 'r'))
if not os.path.exists(ana_txt_save_path):
os.makedirs(ana_txt_save_path)
id_map = {} # coco数据集的id不连续!重新映射一下再输出!
for i, category in enumerate(data['categories']):
id_map[category['id']] = i
# 通过事先建表来降低时间复杂度
max_id = 0
for img in data['images']:
max_id = max(max_id, img['id'])
# 注意这里不能写作 [[]]*(max_id+1),否则列表内的空列表共享地址
img_ann_dict = [[] for i in range(max_id + 1)]
for i, ann in enumerate(data['annotations']):
img_ann_dict[ann['image_id']].append(i)
for img in tqdm(data['images']):
filename = img["file_name"]
img_width = img["width"]
img_height = img["height"]
img_id = img["id"]
head, tail = os.path.splitext(filename)
ana_txt_name = head + ".txt" # 对应的txt名字,与jpg一致
f_txt = open(os.path.join(ana_txt_save_path, ana_txt_name), 'w')
'''for ann in data['annotations']:
if ann['image_id'] == img_id:
box = convert((img_width, img_height), ann["bbox"])
f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))'''
# 这里可以直接查表而无需重复遍历
for ann_id in img_ann_dict[img_id]:
ann = data['annotations'][ann_id]
box = convert((img_width, img_height), ann["bbox"])
f_txt.write("%s %s %s %s %s\n" % (id_map[ann["category_id"]], box[0], box[1], box[2], box[3]))
f_txt.close()
path_synthesis.py:
更改成自己的路径
# -*- coding: utf-8 -*-
import time
import os
import shutil
# 获取所有文件路径集合
def readFilename(path, allfile):
filelist = os.listdir(path)
for filename in filelist:
filepath = os.path.join(path, filename)
if os.path.isdir(filepath):
readFilename(filepath, allfile)
else:
allfile.append(filepath)
return allfile
if __name__ == '__main__':
# 文件夹路径
path1 = "/home/nh666/llw/ORB_FAR/WisdomGuide/val"
allfile1 = []
allfile1 = readFilename(path1, allfile1)
allname1 = []
# 文件路径
txtpath = "/home/nh666/llw/ORB_FAR/WisdomGuide/annotations/val_list.txt"
for name in allfile1:
print(name)
file_cls = name.split("/")[-1].split(".")[-1]
# 后缀名
if file_cls == 'png':
print(name.split("/")[-1])
with open(txtpath, 'a+') as fp:
fp.write("".join(name) + "\n")
复制一份darknet/data/voc.names文件并重命名为voc_blind.names,里面存放的是训练的类别,不过在训练时不会真的标注为什么什么东西,而是标注为01234序号,所以文件中的类别名的排序是很重要的,要对应你的标签txt文件。
复制一份darknet/cfg/voc.data文件并重命名为voc_blind.data,里面存放的是classes类别数、train/valid数据集路径、names类别名路径、backup模型路径,需要根据自己的位置修改。
前段日子yolov7发布了,发现darknet也有实现,本来打算用v7的,但是训练时发现训练不了,报错
cuDNN status Error in: file: ./src/convolutional_kernels.cu : () : line: 555 : build time: Oct 26 2022 - 16:19:38
cuDNN Error: CUDNN_STATUS_BAD_PARAM
Darknet error location: ./src/dark_cuda.c, cudnn_check_error, line #204
cuDNN Error: CUDNN_STATUS_BAD_PARAM: Resource temporarily unavailable
查了一下github里的讨论区,似乎需要改cuDNN版本,但是我是在服务器训练,不能随便改,所以退而求次用yolov4。
复制一份darknet/cfg/yolov4-tiny.cfg文件并重命名为yolov4_blind.cfg,更改设置:
subdivisions为8的倍数,如果 GPU 显存大 subdivisions 可以 填 8,显存小时可以填 32。
max_batches为最大训练次数,与样本数量无直接关系,建议是样本数×2000,避免拟合问题。
steps改为 max_batches 的 80% and 90%。
subdivisions=8
max_batches = 10000
steps=8000,9000
ctrl+F搜索“yolo”关键字,有几个改几个,继续更改:
filters=30 //公式计算(5+类别数)×3
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=5
进入darknet文件夹,进入终端,执行以下命令:
sudo ./darknet detector train cfg/voc_blind.data cfg/yolov4_blind.cfg -map
sudo ./darknet detector test cfg/voc_blind.data cfg/yolov4_blind.cfg backup/yolov4_blind_best.weights
sudo ./darknet detector valid cfg/voc_blind.data cfg/yolov4_blind.cfg backup/yolov4_blind_best.weights
源码