Yolo模型部署的两种方法

2023-11-04

目录

1 需求描述

第1种:封装darknet框架

第2种:weights模型转pb模型

2 weights模型转pb模型方法

3 重要备注

(1)关于预处理:

(2)关于模型输入输出的数据结构和节点名称:

(3)关于NMS


1 需求描述

工程部署使用的C++,模型用darknet(AB版)YoloV3训练的,格式为weights。目前已实测通过了两种方式调用yoloV3模型。

第1种:封装darknet框架

将darknet框架封装成dll,在C++中通过非常简单易懂的语法直接调用weights,cfg这两个原生文件。

优点:

编译非常简单:darknet(AB版)自带编译成dll的方法,操作过程也很简单,没有各种版本兼容性问题。

dll非常小:darknet框架编译出来的dll只有1.7MB。

C++语法非常精简易懂:完成模型调用和输出只有5行代码左右。

第2种:weights模型转pb模型

如果已经将tensorflow框架封装成dll,那么也可以将weights模型转成能供tensorflow直接使用的pb模型。

优点:使用tensorflow部署还是更可靠点,而且有时候一个项目不仅用一个算法,所有框架的模型都可以用tensorflow去实现。

2 weights模型转pb模型方法

darknet框架实现的yolo3有两个版本,一个是yolo3作者原版,还有一个是yolo4作者优化后的版本(AB版),虽然两者的cfg文件中内容一模一样,但是使用GitHub上找的不同版本的weights模型转pb轮子,将会出现异常。即,使用原版darknet yolo3的weights转pb的代码去转AB版yolo3 weights,虽然能转换成功,但是这个pb模型的精度几乎为0。

原因据查是AB版对yolo3算法做了模型结构之外的一些改进,这可能导致weights转pb的源代码不通用。

由于AB版darknet相对原版做了很多优化,而且为了能够在未来部署AB版的yolo4算法,这次仅记录下AB版yolo3的转换和部署方法。

weights转pb

转换代码在https://github.com/hunglc007/tensorflow-yolov4-tflite开源项目中,1100星,作者使用TF2.0框架将AB版darknet的yolo3和4复现了,里面有yolo3,yolo4转pb,转tensorflow lite(移动部署),转tensorRT模型的轮子。

步骤1:下载上述项目。(TF2.3版以上)

步骤2:CMD中执行如下指令即可转换成功:(修改你的weights模型位置,和你的输入大小)

python save_model.py --weights ./data/yolov3.weights --output ./checkpoints/yolov3-608 --input_size 608 --model yolov3

程序将会在当前项目路径内,生成一个./checkpoints/yolov3-608/文件夹,里面存放了如下转换结果:

步骤3:将saved_model.pb和variables两个东西放到你C++项目工程中就行了。

步骤4:C++中的模型调用和结果解析语法,可以参考如下博主的完整代码:

tensorflow C++接口调用 目标检测 pb模型代码 https://www.cnblogs.com/cnugis/p/11506767.html

tensorflow C++接口调用 图像分类 pb模型代码:https://www.cnblogs.com/cnugis/p/11507872.html

3 重要备注

(1)关于预处理

上述转换项目,仅仅是将yolo3模型原封不动的转成pb模型,这就表示,在C++工程中,还需要将输入pb模型的Mat图像先归一化,然后resize成608*608,最后才去调用pb模型进行预测。这些步骤,如果不想在C++中写,可以修改转换代码,即在python中先加一道预处理,修改模型输入的数据结构,然后再将weights转成pb。

(2)关于模型输入输出的数据结构和节点名称

在save_model.py中,作者定义的pb模型输出是:“pred = tf.concat([boxes, pred_conf], axis=-1)”,即所有检测框坐标和预测值全部由一个输出变量表示。所以,C++那边就只要定义一个输出节点的名称。

pb模型输入输出节点的名称,以及输入输出的数据结构,可以在save_model.py中去寻找踪迹,也可用使用Netron软件打开pb模型去找到,比如:

例子1:yolo3一个输入(float32,表示接受float格式图像,大概率是要提前归一化后才能输入!),2个输出节点:

例子2:yolo3一个输入(uint8,表示图像是0-255,接受非归一化图像!),4个输出节点:

关于模型输入输出为什么是这个英文名,应该是程序默认的,除非自己定义了。

关于节点名称后面新增的“:0, :1”什么的,就是模型给予的默认的防止同名的输入输出节点。

(3)关于NMS

使用上述项目转换,模型的预测结果并没有经过NMS处理,这导致输出里面有很多近乎重叠的检测框。在C++中写NMS算法来筛选pb模型的检测结果可能比较麻烦,我们可以在转换模型过程中,将NMS也写进去,这样pb模型的输出就直接是经过NMS操作后的结果。

方法:

①在上述开源项目中,打开detect.py文件。

②复制其中的:boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression(......)这行代码。

③将上述代码粘贴在save_model.py中的“pred = tf.concat([boxes, pred_conf], axis=-1)”之前,并注释“pred = tf.concat([boxes, pred_conf], axis=-1)”,替换成“pred = (boxes, scores) ”,如下所示:

1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Yolo模型部署的两种方法 的相关文章

  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • C++:无法使用scoped_allocator_adaptor传播polymorphic_allocator

    我有一个vector
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • 我的 strlcpy 版本

    海湾合作委员会 4 4 4 c89 我的程序做了很多字符串处理 我不想使用 strncpy 因为它不会终止 我不能使用 strlcpy 因为它不可移植 只是几个问题 我怎样才能让我的函数正常运行 以确保它完全安全稳定 单元测试 这对于生产来
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐