6.6.tensorRT高级(1)-mmdetection框架下yolox模型导出并推理

目录

    • 前言
    • 1. yolox导出
    • 2. yolox推理
    • 3. 补充知识
      • 3.1 知识点
      • 3.2 mmdetection
    • 总结

前言

杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记。

本次课程学习 tensorRT 高级-mmdetection 框架下 yolox 模型导出并推理

课程大纲可看下面的思维导图

在这里插入图片描述

1. yolox导出

这节课我们主要学习 mmdetection 案例

这节课的主要目的是:通过调试分析 mmdet 代码,把 yolox 模型导出,并在 tensorrt 上推理得到结果

其中涉及到调试和分析的方法技巧

mmdetection 导出 onnx 还是比较费尽的,封装得太死了,但是你习惯了之后问题总是可以解决的,不至于说束手无策,代码下载于 2023/3/27日,mmdetection-2.21.0,代码相对来说比较老了,最新版本的 yolox 导出可能略有差别

Note:博主为了配合该案例的成功,配置了一个相关的虚拟环境,其中 mmcv-full-1.4.8、torch-1.9.0,大家直接按照目前的 mmdetection 配置即可,直接可导出 master 中的 yolox 就行,关于相关环境配置可参考 mmdetecion环境安装

先验证下整个项目是否能成功,新建一个 predict.py 文件,内容如下:

from mmdet.apis import init_detector, inference_detectorconfig_file = 'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
device = 'cuda:0'
# init a detector
model = init_detector(config_file, checkpoint_file, device=device)
# inference the demo image
inference_detector(model, 'demo/demo.jpg')

二话不说,先去执行 predict.py 遇到如下问题:

在这里插入图片描述

图1-1 执行predict问题

创建 checkpoints 文件夹然后通过提供的 url 链接下载权重就行,再执行下 predict.py 如下所示:

在这里插入图片描述

图1-2 执行predict成功

执行成功了,我们把它换成 yolox 的模型试试,首先下载 yolox 的模型(选择的是tiny模型),在 https://github.com/open-mmlab/mmdetection/tree/v2.21.0/configs/yolox 可以找到模型,注意这是2.21.0版本的模型,下载完成后放入到 checkpoints 文件夹中

然后选择下 yolox 的 config 文件,它是一个 py 文件,用于描述模型的组成部分,包括 backbone、neck 等

在这里插入图片描述

图1-3 model下载

修改下 predict.py 文件,重新指定 config 和 checkpoint 文件,如下所示:

from mmdet.apis import init_detector, inference_detectorconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
# init a detector
model = init_detector(config_file, checkpoint_file, device=device)
# inference the demo image
inference_detector(model, 'demo/demo.jpg')

再去执行下 predict.py 文件,如下图所示:

在这里插入图片描述

图1-4 执行predict成功(yolox model)

执行成功了,接下来我们就要去分析它,导出我们想要的 onnx,它的 model 是一个正常的 torch.model 的模型,因此我们直接导出看能不能成功,代码如下:

from mmdet.apis import init_detector, inference_detector
import torchconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
# init a detector
model = init_detector(config_file, checkpoint_file, device=device)
# inference the demo image
# inference_detector(model, 'demo/demo.jpg')torch.onnx.export(model, (torch.zeros(1, 3, 416, 416),), "out.onnx", opset_version=11
)

执行后出现如下问题:

在这里插入图片描述

图1-5 yolox导出问题

可以看到提示需要一个 img_metas 的参数,img_metas 是什么呢?不清楚,很烦,这玩意没那么容易导出来,所以需要我们来进行分析,

经过一顿调试分析(具体参照视频😄),我们知道模型中是需要 self.backbone、self.neck、self.bbox_head 这三项来完成推理的,所以我们完全可以自己来构建网络嘛,具体代码如下:

from mmdet.apis import init_detector, inference_detector
import torchconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
# init a detector
model = init_detector(config_file, checkpoint_file, device=device)
x = torch.zeros(1, 3, 416, 416, device=device)
x = model.backbone(x)
x = model.neck(x)
x = model.bbox_head(x)
print(type(x))# inference the demo image
# inference_detector(model, 'demo/demo.jpg')# torch.onnx.export(
#     model, (torch.zeros(1, 3, 416, 416),), "out.onnx", opset_version=11
# )

运行如下:

在这里插入图片描述

图1-6 yolox导出

x 是一个 tuple,其实就是三个特征层的输出,到这里我们就可以考虑写一个 class 导出 onnx 了,具体代码如下:

from mmdet.apis import init_detector, inference_detector
import torchconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
# init a detector
# model = init_detector(config_file, checkpoint_file, device=device)class MyModel(torch.nn.Module):def __init__(self):super().__init__()self.model = init_detector(config_file, checkpoint_file, device=device)def forward(self, x):x = self.model.backbone(x)x = self.model.neck(x)x = self.model.bbox_head(x)return x     model = MyModel().eval()x = torch.zeros(1, 3, 416, 416, device=device)
# inference the demo image
# inference_detector(model, 'demo/demo.jpg')torch.onnx.export(model, (x,), "out.onnx", opset_version=11
)

导出的 onnx 如下所示:

在这里插入图片描述

图1-7 yolox.onnx

可以看到输入只有一个,而输出存在多个,这不是我们想要的结果,我们希望将后处理放到 onnx 中,输入输出都只有一个,这样可以让问题更简单

经过调试分析(具体参照视频)我们知道在 yolox_head.py 文件中的 get_bboxes() 函数完成了我们想要的后处理,如处理 anchor 的 grid,对输出乘以 anchor,对输出进行拼接,恢复成 cx、cy、w、h,代码需要我们去解读它,然后按照自己的理解去实现它,实现代码如下:

from mmdet.apis import init_detector, inference_detector
import torchconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# download the checkpoint from model zoo and put it in `checkpoints/`
# url: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
# init a detector
# model = init_detector(config_file, checkpoint_file, device=device)class MyModel(torch.nn.Module):def __init__(self):super().__init__()self.model = init_detector(config_file, checkpoint_file, device=device)def forward(self, x):ib, ic, ih, iw = map(int, x.shape)x = self.model.backbone(x)x = self.model.neck(x)clas, bbox, objness = self.model.bbox_head(x)output_x = []for class_item, bbox_item, objness_item in zip(clas, bbox, objness):hm_b, hm_c, hm_h, hm_w = map(int, class_item.shape)stride_h, stride_w = ih / hm_h, iw / hm_wstrides = torch.tensor([stride_w, stride_h], device=device).view(-1, 1, 2)prior_y, prior_x = torch.meshgrid(torch.arange(hm_h), torch.arange(hm_w))prior_x = prior_x.reshape(hm_h * hm_w, 1).to(device)prior_y = prior_y.reshape(hm_h * hm_w, 1).to(device)prior_xy = torch.cat([prior_x, prior_y], dim=-1)class_item = class_item.permute(0, 2, 3, 1).reshape(-1, hm_h * hm_w, hm_c)bbox_item  = bbox_item.permute(0, 2, 3, 1).reshape(-1, hm_h * hm_w, 4)objness_item = objness_item.reshape(-1, hm_h * hm_w, 1)pred_xy = (bbox_item[..., :2] + prior_xy) * stridespred_wh = bbox_item[..., 2:4].exp() * stridespred_class = torch.cat([objness_item, class_item], dim=-1).sigmoid()output_x.append(torch.cat([pred_xy, pred_wh, pred_class], dim=-1))return torch.cat(output_x, dim=1)     model = MyModel().eval()x = torch.zeros(1, 3, 416, 416, device=device)
# inference the demo image
# inference_detector(model, 'demo/demo.jpg')torch.onnx.export(model, (x,), "out.onnx", opset_version=11
)

重新执行导出 onnx,如下所示:

在这里插入图片描述

图1-8 yolox.onnx1

可以看到此刻的 onnx 输入输出都只有一个了,符合我们的预期,整个模型的导出还剩下动态 batch 需要设置一下,完整的 onnx 导出代码如下:

import torch
from mmdet.apis import init_detector, inference_detectorconfig_file = 'configs/yolox/yolox_tiny_8x8_300e_coco.py'
# 从 model zoo 下载 checkpoint 并放在 `checkpoints/` 文件下
# 网址为: http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
checkpoint_file = 'checkpoints/yolox_tiny_8x8_300e_coco_20211124_171234-b4047906.pth'
device = 'cuda:0'
#初始化检测器
# model = init_detector(config_file, checkpoint_file, device=device)
# # 推理演示图像
# print(inference_detector(model, 'demo/demo.jpg'))class Model(torch.nn.Module):def __init__(self):super().__init__()self.model = init_detector(config_file, checkpoint_file, device=device)def forward(self, x):ib, ic, ih, iw = map(int, x.shape)x = self.model.backbone(x)x = self.model.neck(x)clas, bbox, objness = self.model.bbox_head(x)output_x = []for class_item, bbox_item, objness_item in zip(clas, bbox, objness):hm_b, hm_c, hm_h, hm_w = map(int, class_item.shape)stride_h, stride_w = ih / hm_h, iw / hm_wstrides = torch.tensor([stride_w, stride_h], device=device).view(-1, 1, 2)prior_y, prior_x = torch.meshgrid(torch.arange(hm_h), torch.arange(hm_w))prior_x = prior_x.reshape(hm_h * hm_w, 1).to(device)prior_y = prior_y.reshape(hm_h * hm_w, 1).to(device)prior_xy = torch.cat([prior_x, prior_y], dim=-1)class_item = class_item.permute(0, 2, 3, 1).reshape(-1, hm_h * hm_w, hm_c)bbox_item  = bbox_item.permute(0, 2, 3, 1).reshape(-1, hm_h * hm_w, 4)objness_item = objness_item.reshape(-1, hm_h * hm_w, 1)pred_xy = (bbox_item[..., :2] + prior_xy) * stridespred_wh = bbox_item[..., 2:4].exp() * stridespred_class = torch.cat([objness_item, class_item], dim=-1).sigmoid()output_x.append(torch.cat([pred_xy, pred_wh, pred_class], dim=-1))return torch.cat(output_x, dim=1)m = Model().eval()
image = torch.zeros(1, 3, 416, 416, device=device)
torch.onnx.export(m, (image,), "yolox.onnx",opset_version=11, input_names=["images"],output_names=["output"],dynamic_axes={"images": {0: "batch"},"output": {0: "batch"}}
)
print("Done.!")

导出的 onnx 如下所示:

在这里插入图片描述

图1-9 完整yolox.onnx

可以看到 batch 动态,输出是框的 85 个维度,一切准备就绪,yolox 的前处理和 yolov5 有些许差别,其它包括后处理和 yolov5 完全一样,

那有人可能会有疑问,为什么要这么麻烦还要去解读代码,自己写代码去实现导出呢?其实这种解决问题的方式有一个好处,那就是无论你的框架有多复杂,无论你的模型是什么乱七八糟的东西,我都有一个通用的思路去解决你,这个通用的思路就是分析代码并理解然后找到我所需要的部分,而把不需要的部分全部干掉,什么 image_metas、get_bboxes 全部干掉,把模型的 onnx 导出来,导出来后再想办法把前后处理加进去,使得模型更加简洁,达到我们的目的

另外你可能好奇 mmdetection 本身没有提供 onnx 导出的脚本吗?其实是有的,只不过它的 onnx 导出是非常非常不完善的 (截止至2022/3/27,目前不知道是否完善

onnx 导出成功了,我们可以去 C++ 上进行推理了

2. yolox推理

预处理部分和 yolov5 一样,只是没有除以 255.0,所以这个需要去掉,同时 bgr 也没有调换顺序,后处理直接没动,照搬 yolov5

因此,我们尽量遵循一个原则,那就是如果你已经实现了一个任务,对于同类的任务我们尽量采用之前已实现的方式,这样工作量就会减少很多,流程也会标准化,节省时间

我们直接执行下 make run,运行如下:

在这里插入图片描述

图2-1 make run执行

yolox 预处理后的图片如下:

在这里插入图片描述

图2-2 yolox预处理

模型推理的效果如下:

在这里插入图片描述

图2-3 yolox模型推理效果

整个 yolox 模型的导出和推理我们都实现了,我们还是需要具备一定的 pytorch 功底,否则像后处理的修改还是存在困难的,首先你需要对模型有一定的了解,其次你需要对代码做一定的解读

针对 mmdetection 框架还是比较复杂的,它的 onnx 导出十分不完善,你想要灵活的导出 onnx 比较困难,通过自己在 mmdeteciton 练手可以极大的锻炼你的动手能力

3. 补充知识

3.1 知识点

1. yolox 的预处理部分,使用了仿射变换,请参照仿射变换原理,使用仿射变换实现 letterbox 的理由是

  • 便于操作,得到变换矩阵即可
  • 便于逆操作,实则是逆矩阵映射即可
  • 便于 cuda 加速,cuda 版本的加速已经在 cuda 系列中提到了 warpaffine 实现
  • 该加速可以允许 warpaffine、normalize、除以 255、减均值除以标准差、变换 RB 通道等等在一个核中实现,性能最好

2. 后处理部分,反算到图像坐标,实际上是乘以逆矩阵

  • 而由于逆矩阵实际上有效自由度是 3,也就是 d2i 中只有 3 个数是不同的,其他都一样。也因此你看到的是 d2i[0]、d2i[2]、d2i[5] 在作用

3.2 mmdetection

MMDetection 是由香港中文大学和商汤针对目标检测任务推出的一个开源项目,它基于 Pytorch 实现了大量的目标检测算法,把数据集构建、模型搭建、训练策略等过程都封装成了一个个模块,通过模块调用的方式,我们能够以很少的代码量实现一个新算法,大大提高了代码复用率

MMDetection 包含了丰富的目标检测、实例分割、全景分割算法以及相关组件和模块。它由 7 个主要部分组成,apis、structures、datasets、models、engine、evaluation 和 visualization

  • apis 为模型推理提供高级 API
  • structures 提供 bbox、mask 和 DecDataSample 等数据结构
  • datasets 支持用于目标检测、实例分割和全景分割的各种数据集
  • models 是检测器最重要的部分,包含检测器的不同组件
  • engine 是运行时组件的一部分
  • evaluation 为评估模型性能提供不同的指标
  • visualization 用于可视化检测结果

Github:https://github.com/open-mmlab/mmdetection

官方文档:https://mmdetection.readthedocs.io/zh_CN/dev-3.x/overview.html

总结

本次课程学习了 yolox 模型的导出和推理,我们在一个复杂的框架 mmdetection 中通过代码分析、解读以及结合自己的理解成功完成了 yolox 模型的导出,因此,无论遇到多么复杂的框架、代码,我们首先需要对模型有一定了解,同时具备一定的代码功底,能完成解读、按照自己的理解重写,这样将大大锻炼你的动手能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/78394.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从 GPU 到 ChatGPT,一文带你理清GPU/CPU/AI/NLP/GPT之间的千丝万缕【建议收藏】

目录 硬件 GPU 什么是 GPU? GPU 是如何工作的? GPU 和 CPU 的区别 GPU 厂商 海外头部 GPU 厂商: 国内 GPU 厂商: nvidia 的产品矩阵 AI 什么是人工智能 (Artificial Intelligence-AI)? 人工智能细分领域 …

ROS添加发布者和订阅者机制实现

一. ROS的节点和包 ✨Node: ROS的基本单位,实现某个功能的节点。比如实现超声波传感器就是一个节点,雷达传感器就可以是一个节点 ✨Package: 多个有联系的节点组成的单位,比如你要控制无人机姿态,可能需要…

Crowd-Robot Interaction 论文阅读

论文信息 题目:Crowd-Robot Interaction:Crowd-aware Robot Navigation with Attention-based Deep Reinforcement Learning 作者:Changan Chen, Y uejiang Liu 代码地址:https://github.com/vita-epfl/CrowdNav 来源:arXiv 时间…

ES新特性部分

文章目录 Symbol创建使用拓展对象的方法直接添加 控制对象控制类型检查控制是否展开 遍历迭代器自定义遍历 生成器函数(实现异步编程)解决回调地狱 Promise连续读文件 SetMap类静态属性继承ES5ES6 GET与SET 数值Object方法模块化导入另一种导入 babel ES…

2023华数杯数学建模竞赛选题建议

提示&#xff1a;DS C君认为的难度&#xff1a;C<B<A&#xff0c;开放度&#xff1a;B<A<C 。 A题&#xff1a;隔热材料的结构优化控制研究 A题是数模类赛事很常见的物理类赛题&#xff0c;需要学习不少相关知识。 其中第一问需要建立平纹织物整体热导率与单根纤…

力扣 -- 467. 环绕字符串中唯一的子字符串

一、题目 二、解题步骤 下面是用动态规划的思想解决这道题的过程&#xff0c;相信各位小伙伴都能看懂并且掌握这道经典的动规题目滴。 三、参考代码 class Solution { public:int findSubstringInWraproundString(string s) {int ns.size();vector<int> dp(n,1);int re…

Android 刷新与显示

目录 屏幕显示原理&#xff1a; 显示刷新的过程 VSYNC机制具体实现 小结&#xff1a; 屏幕显示原理&#xff1a; 过程描述&#xff1a; 应用向系统服务申请buffer 系统服务返回一个buffer给应用 应用开始绘制&#xff0c;绘制完成就提交buffer&#xff0c;系统服务把buffer数据…

移动开发最佳实践:为 Android 和 iOS 构建成功应用的策略

您可以将本文作为指南&#xff0c;确保您的应用程序符合可行的最重要标准。请注意&#xff0c;这份清单远非详尽无遗&#xff1b;您可以加以利用&#xff0c;并添加一些自己的见解。 了解您的目标受众 要制作一个成功的应用程序&#xff0c;你需要了解你是为谁制作的。从创建…

接口自动化测试Mock Get和Post请求

Mock可以模拟一个http接口的后台响应&#xff0c;可以模拟request&#xff0c;response 下载 moco-runner-0.11.0-standalone.jar 下载链接: https://pan.baidu.com/s/1bmFzvJPRnDlQ-cmuJ_3iRg 提取码: kpjv 确保安装了jdk,cmd下可以运行java -version 一、模拟不带参的get请求…

AQL品质抽样标准

AQL抽样标准 - 百度文库 Acceptance Quality Limit 接收质量限的缩写&#xff0c;即当一个连续系列批被提交验收时&#xff0c;可允许的最差过程平均质量水平。 AQL普遍应用于各行业产品的质量检验&#xff0c;不同的AQL标准应用于不同物质的检验上。在AQL 抽样时&#xff0c;…

VUE框架:vue2转vue3全面细节总结(3)路由组件传参

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

idea添加翻译插件并配置有道翻译

1、安装Translation插件 2、 创建有道云应用 有道智云控制台 3、设置idea 4、效果&#xff08;选中文本右键翻译&#xff0c;默认快捷键CtrlShiftY&#xff09;

图文演示:如何三分钟极速搭建一个元宇宙3D虚拟展厅

引言&#xff1a; 元宇宙3D虚拟展厅时代已经来临。元宇宙是一个虚拟的、立体的数字空间&#xff0c;可以让用户沉浸在其中进行交互操作&#xff0c;并体验无限可能。如何快速搭建一个属于自己的虚拟展厅则受到越来越多人的关注。 一&#xff0e;虚拟展厅类型 1.党建展馆 实现…

Linux 匿名页的生命周期

目录 匿名页的生成 匿名页生成时的状态 do_anonymous_page缺页中断源码 从匿名页加入Inactive lru引出 一个非常重要内核patch 匿名页何时回收 本文以Linux5.9源码讲述 匿名页的生成 用户空间malloc/mmap(非映射文件时&#xff09;来分配内存&#xff0c;在内核空间发生…

前端笔记html-layer使用

layer.open方法 layer.open({type:2, //可传入的值有&#xff1a;0&#xff08;信息框&#xff0c;默认&#xff09;1&#xff08;页面层&#xff09;2&#xff08;iframe层&#xff09;3&#xff08;加载层&#xff09;4&#xff08;tips层&#xff09;title: title,content:[…

网络安全之原型链污染

目录&#xff1a; 目录&#xff1a; 一、概念 二、举例 三、 实操了解 总结 四、抛出原题&#xff0c;历年原题复现 第一题&#xff1a; 五、分析与原理 第二题&#xff1a; 八、分析与原理 九、具体操作&#xff0c;payload与结果 结果&#xff1a; 一、概念 Java…

《面试1v1》ElasticSearch基础

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

阿里云快速部署开发环境 (Apache + Mysql8.0)

本文章的内容截取于云服务器管理控制台提供的安装步骤&#xff0c;再整合前人思路而成&#xff0c;文章末端会提供原文连接 ApacheMysql 8.0部署MySQL数据库&#xff08;Linux&#xff09;步骤一&#xff1a;安装MySQL步骤二&#xff1a;配置MySQL步骤三&#xff1a;远程访问My…

Redis压缩列表

区分一下 3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表 3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的…

vue整合脑图编辑管理系统-kitymind百度脑图

前言 项目为前端vue项目&#xff0c;把kitymind百度脑图整合到前端vue项目中&#xff0c;显示了脑图的绘制&#xff0c;编辑&#xff0c;到处为json&#xff0c;png&#xff0c;text等格式的功能 文章末尾有相关的代码链接&#xff0c;代码只包含前端项目&#xff0c;在原始的…