最近在梳理手头工作,回顾去年整个虎年,堪称YOLO内卷元年,各路YOLO系列神仙打架,各显神通。
一开始大部分用户做项目做实验还是使用的YOLOv5,然后YOLOv6、YOLOv7、PP-YOLOE+、DAMO-YOLO、RTMDet就接踵而至,
于是就在自己的数据集逐一尝试,好不容易把这些下饺子式的YOLO模型训练完测试完,忙完工作准备回家过年时,YOLOv8又闪电发布,YOLOv6又更新了3.0版本…用户还得跟进继续训练测试,其实很多时候就是重复工作。
此外换模型训练调参也会引入更多的不确定性,而且往往业务数据集大则几十万张图片,重训成本很高,但训完了新的精度不一定更高,速度指标在特定机器环境上也未必可观,参数量、计算量的变化尤其在边缘设备上也不能忽视。
所以在这样的内卷期,作为开发者,或者研究者的我们,应该怎么样去做一个关于不同网络模型结构的性能结果对比呢?
刚好那段时间的契机是,在折腾YOLOv8_Efficient这个项目,拿到了YOLOv8的模型权重,于是就准备开始动手做这么一个工具。
其实动手做这个项目最初的想法是,希望能够做一个绘制多个神经网络模型性能指标的一个对比图工具,
发现很多论文作者都会选择用python程序来做一个图形绘制,但自己去github上到处找了一圈,也在各个群里问了一遍都没有找到比较合适的工具。
似乎他们都是直接用list存储数据丢到matplotlib里面来做专门的图形绘制,最后还是决定动手去撸一个工具,来满足自己的需求。
考虑到开发语言使用的是Python,那么作为主流的Matplotlib库便成为了作为绘制图像的优先选择。
在引入了Matplotlib之后,简单地学习使用了它的一些绘制工具和用法,就开始试着去各个开源repo和YOLO系列的论文下面把主要关心的几个维度给记录下来,然后保存到python的list数组里面去,再传给Matplotlib去绘制图形。但是随之而来的问题是,每个模型系列都包括着不同的分支,且对应着不同的指标参数,同时最终还需要将不同的模型系列下的不同分支也做一个对比,就相当于是不仅要对比不同模型系列的性能指标,还需要将同一模型下的不同分支也做一个对比。例如Yolov5下面就有n、s、m、l、x等多个分支。
因此,结合之前做数据分析处理的经验,意识到可以自己定义数据结构来满足Matplotlib的参数输入,那么如何设计多个模型指标参数的数据结构就成为一个思考的问题,又考虑到多模型多分支的因素,于是建立了下面这张表格。
将记录完成的数据,整理保存为**.CSV**文件,自然而然的,后面引入了Pandas来做一个数据处理和读取的工具。
至此,这个绘图小工具的设计与选型基本完成。
最后还需要加(亿)一点点小细节!
实现方式是用math来进行转换计算
def fps_to_ms(fps: int) -> int:
'''
Convert FPS to a millisecond interval.
Args:
fps: Input FPS as integer.
Returns:
Interval in milliseconds as integer number.
'''
return math.floor((1 / fps) * 1000)
目前支持修改和调整的参数如下,数据格式可以参考上面的介绍。
def parse_opt(known=False):
parser = argparse.ArgumentParser(description="Quick use model-metrics-plot")
parser.add_argument('-c', '--csv', default='data/Pytorch_models_data.csv', help="csv path")
parser.add_argument('-n', '--fig_path', default='output/plot_metrics.jpg', help="figure path")
parser.add_argument('-p', '--plot_type', default='line', help="i.e line, bar, scatter")
parser.add_argument('-t', '--title_name', default='MS COCO Object Detection', help="title name")
parser.add_argument('-x', '--xlabel_name', default='PyTorch FP16 RTX3080(ms/img)', help="xlabel name")
parser.add_argument('-y', '--ylabel_name', default='COCO Mask AP val', help="ylabel name")
parser.add_argument('-g', '--is_grid', default=False, help="is grid")
parser.add_argument('-f', '--font_size', default=10, help="font_size")
parser.add_argument('-v', '--value_type', default='mAP', help="value type,i.e mAP, FPS, ms")
parser.add_argument('-r', '--colors', default='#0000FF', help="colors")
return parser.parse_known_args()[0] if known else parser.parse_args()
于是开始了漫长的调试与测试…
但是仅能绘制模型的速度和精度显然是不够,同时绘制折线图也有一定的局限性。
于是又引入了条形图,来辅助绘制单个指标参数的模型性能对比。
终于在某个周末的早上,把所有的数据和实例都跑通了。
目前代码已开源在Github,链接为:https://github.com/isLinXu/model-metrics-plot
上面讲了那么多有的没的废话,talk is cheap,show me the code,不妨直接来动手实操一下。
目前数据已上传到本项目的work目录下,可自行参考修改或创建自己的数据表。
项目代码也开源到github上了,直接clone下来即可。
本来是打算上传到pypi的源仓库,让大家直接pip install来安装使用的,后面发现想到的比较好的名字全部都被注册占用了。
于是没办法,大家还是直接软链接的形式来安装使用吧。
最后,大家觉得好用的话,欢迎给本项目打Star和forks,谢谢大家的支持。
!git clone https://github.com/isLinXu/model-metrics-plot.git
正克隆到 'model-metrics-plot'...
remote: Enumerating objects: 242, done.[K
remote: Counting objects: 100% (17/17), done.[K
remote: Compressing objects: 100% (14/14), done.[K
remote: Total 242 (delta 5), reused 13 (delta 3), pack-reused 225[K
接收对象中: 100% (242/242), 2.98 MiB | 1.65 MiB/s, 完成.
处理 delta 中: 100% (108/108), 完成.
检查连接... 完成。
%cd model-metrics-plot
/home/aistudio/model-metrics-plot
!ls
configs LICENSE mmplot_test.py README.md setup.cfg
data main.py output README.zh-CN.md setup.py
img mmplot plots requirements.txt utils
!pip install -e .
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Obtaining file:///home/aistudio/model-metrics-plot
Preparing metadata (setup.py) ... [?25ldone
[?25hInstalling collected packages: mmplot
Running setup.py develop for mmplot
Successfully installed mmplot-0.1.7
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m A new release of pip available: [0m[31;49m22.1.2[0m[39;49m -> [0m[32;49m23.0.1[0m
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m To update, run: [0m[32;49mpip install --upgrade pip[0m
ll --upgrade pip[0m
!pip install omegaconf
import mmplot
import pandas
csv_path = '/home/aistudio/work/PaddleYOLO_model_data.csv'
df = pandas.read_csv(csv_path)
df
model | branch | ms | fps | mAP | maker | |
---|---|---|---|---|---|---|
0 | YOLOv5 | n | 2.6 | -1 | 28.0 | . |
1 | YOLOv5 | s | 3.2 | -1 | 37.6 | . |
2 | YOLOv5 | m | 5.2 | -1 | 45.4 | . |
3 | YOLOv5 | l | 7.9 | -1 | 48.9 | . |
4 | YOLOv5 | x | 13.7 | -1 | 50.6 | . |
5 | YOLOv6 | n | 1.3 | -1 | 36.1 | . |
6 | YOLOv6 | t | 2.1 | -1 | 40.7 | . |
7 | YOLOv6 | s | 2.6 | -1 | 43.4 | . |
8 | YOLOv6 | m | 5.0 | -1 | 49.0 | . |
9 | YOLOv6 | l | 7.9 | -1 | 51.0 | . |
10 | YOLOv6 | l-silu | 9.6 | -1 | 51.7 | . |
11 | YOLOv7 | l | 7.4 | -1 | 51.0 | . |
12 | YOLOv7 | x | 12.2 | -1 | 53.0 | . |
13 | YOLOv8 | n | 2.4 | -1 | 37.3 | . |
14 | YOLOv8 | s | 3.4 | -1 | 44.9 | . |
15 | YOLOv8 | m | 6.5 | -1 | 50.2 | . |
16 | YOLOv8 | l | 10.0 | -1 | 52.8 | . |
17 | YOLOv8 | x | 15.1 | -1 | 53.8 | . |
18 | YOLOX | s | 3.0 | -1 | 40.4 | . |
19 | YOLOX | m | 5.8 | -1 | 46.9 | . |
20 | YOLOX | l | 9.3 | -1 | 50.1 | . |
21 | YOLOX | x | 16.6 | -1 | 51.8 | . |
22 | RTMDet | t | 2.8 | -1 | 40.9 | . |
23 | RTMDet | s | 3.3 | -1 | 44.5 | . |
24 | RTMDet | m | 6.4 | -1 | 49.1 | . |
25 | RTMDet | l | 10.2 | -1 | 51.2 | . |
26 | RTMDet | x | 18.0 | -1 | 52.6 | . |
27 | PP-YOLOE+ | s | 2.9 | -1 | 43.7 | * |
28 | PP-YOLOE+ | m | 6.0 | -1 | 49.8 | * |
29 | PP-YOLOE+ | l | 8.7 | -1 | 52.9 | * |
30 | PP-YOLOE+ | x | 14.9 | -1 | 54.7 | * |
%matplotlib inline
from mmplot.plots import plot_metrics
from mmplot.utils.dataloader import pd_read_csv
if __name__ == '__main__':
csv_path = '/home/aistudio/work/PaddleYOLO_model_data.csv'
fig_path = 'plot_metrics.jpg'
df = pd_read_csv(csv_path)
plot_metrics(df, fig_path)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYktgbwe-1677392126014)(main_files/main_18_0.png)]
import pandas
csv_path = '/home/aistudio/work/MMYOLO_model_data.csv'
df = pandas.read_csv(csv_path)
df
model | branch | ms | fps | mAP | |
---|---|---|---|---|---|
0 | YOLOv5 | n | -1 | -1 | 28.0 |
1 | YOLOv5 | s | -1 | -1 | 37.7 |
2 | YOLOv5 | m | -1 | -1 | 45.3 |
3 | YOLOv5 | l | -1 | -1 | 48.8 |
4 | YOLOv6 | n | -1 | -1 | 36.2 |
5 | YOLOv6 | t | -1 | -1 | 41.0 |
6 | YOLOv6 | s | -1 | -1 | 44.0 |
7 | YOLOv6 | m | -1 | -1 | 48.4 |
8 | YOLOv6 | l | -1 | -1 | 51.0 |
9 | YOLOv7 | tiny | -1 | -1 | 37.5 |
10 | YOLOv7 | l | -1 | -1 | 50.9 |
11 | YOLOv8 | x | -1 | -1 | 52.8 |
12 | PP-YOLOE | s | -1 | -1 | 43.5 |
13 | PP-YOLOE | m | -1 | -1 | 49.5 |
14 | PP-YOLOE | l | -1 | -1 | 52.6 |
15 | PP-YOLOE | x | -1 | -1 | 54.2 |
%matplotlib inline
from mmplot.utils.dataloader import pd_read_csv
from plots.bar_chart_plot import bar_chart_plot
from plots.line_metrics_plots import plot_metrics
if __name__ == '__main__':
csv_path = '/home/aistudio/work/MMYOLO_model_data.csv'
fig_path = 'plot_line_metrics.jpg'
title_name = 'MS COCO Object Detection'
xlabel_name = 'PyTorch FP16 RTX3080(ms/img)'
colors = '#0000FF'
value_type = 'mAP'
is_grid = False
df = pd_read_csv(csv_path)
bar_chart_plot(df, fig_path, value_type, title_name, xlabel_name, colors, is_grid)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRqW0WM0-1677392126015)(main_files/main_21_0.png)]
自己造轮子是一件很折腾,但也很有意思的事情。
可以培养自己除了开发之外,关于产品和用户角度的一些思维。
关于这个工具,后续也会引入和支持更多的绘图方式来辅助算法选型和科研需要。
最后,也在PFCC的推荐下,给PaddleYOLO和PaddleDetection提交了相应的PR,目前已被合入,后面又做了微调。