本文最后更新于:2022年3月7日 下午
极本穷源:YOLO篇Ⅲ
YOLOV4-tiny源码解读
有了基本概念的理解,接着深入源码一步一步学习。在开始之前先做下回顾,小目标&&配置文件参数解读
小目标识别检测中”小目标”尺寸占原始图片的比例:
ubuntu下安装个labelImg,查看下标注目标时的尺寸。labelImg图片标注工具安装 从 PyPI 获取,但只有 python3.0 或更高版本,这是现代Linux发行版(如Ubuntu和Fedora)上最简单的(单命令)安装方法。
| pip3 install labelImg labelImg labelImg [IMAGE_PATH] [PRE-DEFINED CLASS FILE]
|
经不完全统计。本次数据集目标尺寸大致如下:
|
大部分尺寸 |
最大 |
最小 |
肉眼看不见 |
目标尺寸 |
170x151 |
1200x2356 |
47x82 |
167x95 |
图片尺寸 |
5472x3648 |
5472x3648 |
5472x3648 |
5472x3648 |
yolov4-tiny.cfg配置文件解读
训练开始之前根据自己的显卡性能调整btach以及subdivisions的大小,普遍以batch = 64,subdivisions = 16设置。显卡差点的subdivisions设置成64。
整个训练样本会被分成若干个batch,网络中每个batch积累64个样本后会进行一次正向传播(在训练的过程中将一次性加载64张图片进内存)。subdivisions表示每个batch会分16次完成前向传播,前向传播的循环过程中累加loss求平均,待64张图片都完成前向传播后,再一次性后传更新参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| [net]
batch=64 subdivisions=16
width=416 height=416 channels=3 momentum=0.9 decay=0.0005
angle=0 saturation = 1.5 exposure = 1.5 hue=.1
learning_rate=0.00261 burn_in=1000
max_batches = 3000 policy=steps
steps=1600000,1800000 scales=.1,.1
|
convolutional
在训练数据前要修改每个yolo下的classes类别数,以及每个yolo上的第一个filters卷积核个数(等于输出的特征图的维度):filters=(classes + 5)x3。
q:公式中的5是怎么来的?
这5个数分别包括:pc,bx, by, bh, bw。其中pc 为标志位,代表检测框中是否包含对象,框中包含任一目标对象 时pc = 1,反之只有背景没有目标时pc = 0。后面四个为bounding box的边界参数,分别是对象的中心位置x和y 坐标,对象的高和宽。参考博客理解,后面乘以3就很容易理解,rgb三个通道的意思吧,红绿蓝三个通道各卷 一次。
每个卷积层之后包含一个批量归一化处理(BN)和一个激活函数(Leaky),YOLOv4的主干网络CSPDarknet53中,使用Mish代替了原来的Leaky ReLU。常见的激活函数:Sigmoid、tanh、Leaky ,ReLU、Mish。
batch、上采样(下采样)、卷积核和激活函数的概念,卷积核(filters)和滤波器(kernels)的区别。详细参考极本穷源2
|
[convolutional]
batch_normalize=1
filters=18
size=3
stride=2
pad=1
activation=leaky
|
route
route应该就是全连接层,起到连接的作用,将不同卷积层输出的特征进行连接。本质上它是一个融合层,它的作用是在当前层引出之前卷积所得到的特征层。全连接层的作用就是将网络学到分布式特征映射到样本标记空间。
参考YOLO中的route层
layers = -6,-1表示将向前数的第6层与第1层相连接,完成特征的传递。
layer = -2 ,表示引出前两层的conv输出的特征图。
maxpool (池化层)
网络模型的构建
当然,只有cfg配置文件是远远不够的。配置文件本质上调用了一大堆定义好的函数,改变传入函数的参数实现不同的功能及效果。这些函数主要包括 /src下的
我们从最常用的 detector命令切入,简单分析下调用规则。从以下命令不难发现,这些命令是运行了当前文件夹下的darknet.c文件。
| ./darknet detector train
./darknet detector map
./darknet detector test
./darknet detector calc_anchors
./darknet detector demo
|
打darknet.c看下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 1.先看main函数 #先是一堆#ifndef防止多重定义,接下来就是一大堆if else if
else if (0 == strcmp(argv[1], "detector")){ run_detector(argc, argv); 当./darknet后面的命令为 detector 时,调用函数run_dector()
2.右键这个函数转到定义: void run_detector(int argc, char **argv) 和main.c一样先定义一大堆,然后就是if else if
直接找到关键词 test train map... if (0 == strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, dont_show, ext_output, save_labels, outfile, letter_box, benchmark_layers); else if (0 == strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear, dont_show, calc_map, thresh, iou_thresh, mjpeg_port, show_imgs, benchmark_layers, chart_path); else if (0 == strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile); else if (0 == strcmp(argv[2], "recall")) validate_detector_recall(datacfg, cfg, weights); else if (0 == strcmp(argv[2], "map")) validate_detector_map(datacfg, cfg, weights, thresh, iou_thresh, map_points, letter_box, NULL); else if (0 == strcmp(argv[2], "calc_anchors")) calc_anchors(datacfg, num_of_clusters, width, height, show);
|
果然都能找到定义了好的detector函数:(参考已有资料理解)
| 3.右键test_detector找到函数定义:
void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh,float hier_thresh, int dont_show, int ext_output, int save_labels, char *outfile, int letter_box, int benchmark_layers)
void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear, int dont_show, int calc_map, float thresh, float iou_thresh, int mjpeg_port, int show_imgs, int benchmark_layers, char* chart_path)
float validate_detector_map(char *datacfg, char *cfgfile, char *weightfile, float thresh_calc_avg_iou, const float iou_thresh, const int map_points, int letter_box, network *existing_net)
void calc_anchors(char *datacfg, int num_of_clusters, int width, int height, int show)
void validate_detector(char *datacfg, char *cfgfile, char *weightfile, char *outfile)
|
以 train_detector()为例:
|
list *options = read_data_cfg(datacfg);
char *train_images = option_find_str(options, "train", "data/train.txt");
char *valid_images = option_find_str(options, "valid", train_images);
char *backup_directory = option_find_str(options, "backup", "/backup/");
|
大概就是从这里调的cfg配置文件吧,其他命令也是类似的。参考yolov3网络模型构建。