深度学习中的ONNX模型部署(打包为exe独立运行)详细教程

news2024/9/21 22:27:09

摘要:在本教程中,详细介绍了如何将ONNX模型部署为独立的可执行文件。从环境准备开始,介绍了ONNX Runtime及其GPU版本的安装,确定CUDA和cuDNN版本的兼容性。给出了使用ONNX Runtime加载和推理模型,处理输入和输出数据的脚本示例。最后使用PyInstaller将推理脚本打包为可执行文件,并提供了应对常见错误的解决方案。


引言

在深度学习领域,主流框架如PyTorch和TensorFlow尽管功能强大,但它们的库往往庞大且复杂,这给模型的部署和跨平台应用带来了麻烦。为了解决这一问题,ONNX(Open Neural Network Exchange)应运而生。ONNX是由Facebook和微软最初开发的一个社区项目,目前由IBM、亚马逊(AWS)、谷歌等多家组织共同支持和开发ONNX项目。ONNX旨在创建一种开放的文件格式,使机器学习模型能够在不同的AI框架和硬件之间通用。

通过ONNX,可以轻松地在不同框架之间转换模型。例如,一个在PyTorch中训练的深度学习模型可以导出为ONNX格式,然后轻松导入到TensorFlow中,或者PyTorch转到ONNX。

在这里插入图片描述

除了在框架间的转换外,ONNX模型还可以与ONNX Runtime一起使用。ONNX Runtime是一个兼容多个框架的跨平台加速器,支持PyTorch、TensorFlow、TFLite、scikit-learn等框架ONNX Runtime。通过利用硬件特定的加速功能,ONNX Runtime优化了ONNX模型的执行效率,使模型能够在各种硬件平台(包括CPU、GPU和专用加速器)上高效运行ONNX Runtime硬件支持。

为了进一步提升模型的可移植性,并使其能够在没有Python环境的系统上独立运行,将模型打包为可执行文件是一个有效的解决方案。在本博客教程中,我们将使用PyInstaller,这是一款能够将Python脚本打包为独立可执行文件的工具。通过这一过程,将能够简化模型的发布和应用,使其在多种环境中轻松运行。


1. 环境准备

首先说明一下,如果不使用GPU,只是用CPU运行那么可以不太关注CUDA的版本,这种情况基本坑就比较少了。但在使用ONNX模型进行GPU推理时,选择正确的ONNX Runtime版本并确保与CUDA和cuDNN的兼容性是最重要的。博主见过很多到后面打包出各种错误折腾的,大多是在版本兼容上没有注意,埋下地雷而不自知。

1.1 安装ONNX Runtime-GPU的注意事项

ONNX Runtime的GPU加速依赖于CUDA和cuDNN,因此这些库的版本必须正确匹配。

  • CUDA版本兼容性

    • ONNX Runtime是基于特定的CUDA版本编译的。根据Nvidia CUDA的次版本兼容性原则,使用CUDA 11.8编译的ONNX Runtime版本兼容任何CUDA 11.x版本,而使用CUDA 12.x编译的ONNX Runtime版本则兼容任何CUDA 12.x版本【参考官方文档】ONNX Runtime GPU执行提供程序。
  • cuDNN版本兼容性

    • ONNX Runtime与cuDNN的版本需要精确匹配。例如,使用cuDNN 8.x编译的ONNX Runtime不兼容cuDNN 9.x,反之亦然。因此,需要根据CUDA和cuDNN的主版本来选择合适的ONNX Runtime包。例如,PyTorch 2.3使用cuDNN 8.x,而PyTorch 2.4或更高版本则使用cuDNN 9.x【参考官方文档】ONNX Runtime与cuDNN兼容性。

以上的话简单说起来就是,onnxruntime对于CUDA、cuDNN的支持是按版本来的。如下图所示,基本上onnxruntime1.18支持的只有CUDA11.8及以上版本,如果CUDA是11.6,那么最好装onnxruntime-1.14版本。

在这里插入图片描述
这个表格来自ONNX Runtime官方文档,所以建议像下面的安装方式。

  1. CUDA 11.x 用户

    • 如果使用CUDA 11.8,建议安装ONNX Runtime 1.18.x版本,兼容cuDNN 8.x。
    • 对于CUDA 11.6,建议使用ONNX Runtime 1.14或1.13版本。
  2. CUDA 12.x 用户

    • 如果使用CUDA 12.x和cuDNN 9.x,安装ONNX Runtime 1.18.1。
    • 如果使用CUDA 12.x和cuDNN 8.x,选择ONNX Runtime 1.18.0或1.17.x。

选择跟你系统中CUDA和cuDNN版本匹配的ONNX Runtime版本,以确保最佳兼容性和性能。


1.2 查看CUDA和cuDNN的版本

在Windows上,可以使用以下方法来查看CUDA和cuDNN的版本:

  1. 使用命令行
    打开命令提示符(Cmd)并输入以下命令:

    nvcc --version
    

    这将显示CUDA编译器驱动程序的版本信息。我这里的CUDA版本是11.8(目前服务器用的比较多的型号,兼容很多框架)

在这里插入图片描述

在Windows的命令提示符中,可以用下面的命令查看cuDNN的版本系列:

for /d %i in ("C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v*") do findstr /C:"CUDNN_MAJOR" "%i\include\cudnn_version.h"

在这里插入图片描述

此命令将遍历C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\目录下的所有版本目录,并在每个版本目录中的cudnn_version.h文件中查找CUDNN_MAJOR的定义。可以从图上看到我的CUDNN版本是8.x的,你可以核对一下自己的版本是否正确。


1.3 安装ONNX Runtime-GPU

为了成功运行和部署ONNX模型,首先需要正确安装ONNX Runtime。这里我们先用conda创建一个名为deploy_onnx的Python环境:

# name 环境名、3.x Python的版本
conda create -n deploy_onnx python==3.10
# 激活环境
activate deploy_onnx

根据硬件配置和需求,可以选择安装CPU版本或GPU版本的ONNX Runtime。以下是参考官网的详细安装步骤:

1. 安装 ONNX Runtime CPU 版本

如果只需要在CPU上运行ONNX模型,可以安装CPU版本的ONNX Runtime。该版本适用于没有GPU或者不需要GPU加速的情况。

pip install onnxruntime

2. 安装 ONNX Runtime GPU 版本

如果需要利用GPU进行加速推理,需要安装GPU版本的ONNX Runtime。根据所使用的CUDA版本,安装过程有所不同。

(1)安装 ONNX Runtime GPU (CUDA 11.x):如果你的系统使用CUDA 11.x,默认推荐使用CUDA 11.8进行安装。这个版本的ONNX Runtime已经预编译好,并且兼容CUDA 11.8。

pip install onnxruntime-gpu==1.18.0

(2)安装 ONNX Runtime GPU (CUDA 12.x):如果使用的是CUDA 12.x,并且cuDNN是8.x的,那么你可以安装onnxruntime-gpu==1.18.0。需要使用特定的安装源来获取支持CUDA 12.x的ONNX Runtime版本:

pip install onnxruntime-gpu==1.18.0 --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/
  • 如果使用的是CUDA 12.x,并且cuDNN是9.x的,那么你可以安装onnxruntime-gpu==1.18.1或更高版本。需要使用特定的安装源来获取支持CUDA 12.x的ONNX Runtime版本:
pip install onnxruntime-gpu==1.18.1 --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/

3. 验证安装

安装完成后,可以通过以下的Python命令检查ONNX Runtime是否安装成功,并确认其是否正确配置:

import onnxruntime as ort
print(ort.get_device())  # 输出 'CPU' 或 'GPU' 以确认设备

如果输出为’GPU’,则表明ONNX Runtime已正确配置为使用GPU进行推理。

4. 其他依赖库安装

在部署和打包ONNX模型时,还需要安装其他一些依赖库。以下是一些常见的库安装步骤:

  • 安装PyInstaller:PyInstaller是用于将Python脚本打包成独立可执行文件的工具,适合在没有Python环境的系统上运行。

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyInstaller
    
  • 安装Pillow:Pillow是一个强大的图像处理库,许多与图像相关的任务都会用到它。因为项目涉及图像处理,所以需要安装这个库。

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Pillow
    

这些依赖库的安装可以根据项目的具体需求来选择,确保所有必要的库都已安装,这样才能顺利进行模型的部署和打包。


2. ONNX 模型部署示例

在成功安装了ONNX Runtime及其他必要的依赖库之后,接下来我们将介绍如何加载ONNX模型并进行推理。以下是一个完整的代码示例,通过该示例,可以搞定使用ONNX Runtime加载模型、进行图像预处理、执行推理并处理推理结果。

1. 导入必要的库

首先,我们需要导入一些关键的Python库,这些库包括onnxruntime用于加载和运行ONNX模型,numpy用于数据处理,cv2(OpenCV)用于图像处理,os用于文件路径操作,以及time用于计算推理时间。

import os
import onnxruntime as ort
import numpy as np
import time
import cv2

2. 初始化模型路径和类别标签

我们需要指定ONNX模型的路径以及类别标签。这些标签用于标识模型可以检测到的物体类别。在这个例子中,我们使用了YOLOv8模型,并定义了一组常见物体的类别标签。

model_path = 'yolov8n.onnx'

names = [
    "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
    # (此处省略部分类别以节省篇幅)
    "vase", "scissors", "teddy bear", "hair drier", "toothbrush"
]

params = {
    'conf_thres': 0.5,  # 置信度阈值
    'iou_thres': 0.4,   # 非极大值抑制(NMS)的IoU阈值
}

3. 加载并验证输入图像路径

为了确保用户输入的图像路径是有效的,我们循环检查用户输入的路径,直到输入有效路径为止。

while True:
    input_image_path = input("请输入图像文件的路径: ")
    if os.path.isfile(input_image_path):
        break
    else:
        print("文件路径不存在,请重新输入。")
output_image_path = 'output.jpg'

4. 加载ONNX模型

根据设备类型(CPU或GPU),我们选择合适的执行提供程序(Execution Provider)来加载ONNX模型。在这里,我们首先检查设备类型,并使用CUDAExecutionProvider加载GPU模型或CPUExecutionProvider加载CPU模型。

providers = ["CUDAExecutionProvider"] if ort.get_device() == "GPU" else ["CPUExecutionProvider"]
session = ort.InferenceSession(model_path, providers=providers)
model_inputs = session.get_inputs()
input_width = model_inputs[0].shape[2]
input_height = model_inputs[0].shape[3]

5. 预处理输入图像

为了将图像输入到模型中,需要对其进行预处理。主要步骤包括:读取图像、调整大小、归一化、变换维度等。

img = cv2.imread(input_image_path)
img_height, img_width = img.shape[:2]
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_resized = cv2.resize(img_rgb, (input_width, input_height))
img_normalized = img_resized / 255.0
img_transposed = np.transpose(img_normalized, (2, 0, 1))
img_expanded = np.expand_dims(img_transposed, axis=0).astype(np.float32)

6. 模型推理

加载和预处理完图像后,我们将图像输入到ONNX模型中进行推理,并记录推理所需的时间。

start = time.time()
prediction = session.run(None, {model_inputs[0].name: img_expanded})
end = time.time()
print("Inference Time: {:.4f} seconds".format(end - start))

7. 后处理推理结果

推理完成后,我们需要对模型输出进行后处理。主要步骤包括:提取边界框、筛选有效检测结果、以及应用非极大值抑制(NMS)以去除重复的检测。

outputs = np.transpose(np.squeeze(prediction[0]))
rows = outputs.shape[0]

boxes = []
scores = []
class_ids = []

x_factor = img_width / input_width
y_factor = img_height / input_height

for i in range(rows):
    classes_scores = outputs[i][4:]
    max_score = np.amax(classes_scores)

    if max_score >= params['conf_thres']:
        class_id = np.argmax(classes_scores)
        x, y, w, h = outputs[i][0], outputs[i][1], outputs[i][2], outputs[i][3]
        left = int((x - w / 2) * x_factor)
        top = int((y - h / 2) * y_factor)
        width = int(w * x_factor)
        height = int(h * y_factor)
        
        class_ids.append(class_id)
        scores.append(max_score)
        boxes.append([left, top, width, height])

indices = cv2.dnn.NMSBoxes(boxes, scores, params['conf_thres'], params['iou_thres'])

8. 绘制和保存检测结果

最终,我们将检测结果绘制在原始图像上,并将处理后的图像保存到指定路径。

print("Detection Results:")
for i in indices.flatten():
    box = boxes[i]
    score = scores[i]
    class_id = class_ids[i]
    print(f"Class: {names[class_id]}, Score: {score:.2f}, Box: {box}")

for i in indices.flatten():
    box = boxes[i]
    score = scores[i]
    class_id = class_ids[i]
    left, top, width, height = box
    cv2.rectangle(img, (left, top), (left + width, top + height), (255, 178, 102), 2)
    cv2.putText(img, f"{names[class_id]}: {score:.2f}", (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 178, 102), 2)

cv2.imshow("Detection Results", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite(output_image_path, img)
print(f"Output saved to {output_image_path}")

以上代码是使用ONNX Runtime加载并推理ONNX模型的完整流程。运行一下效果如下:

在这里插入图片描述

这样检测出来的图像结果如下:

在这里插入图片描述


3. 将ONNX脚本打包为独立的可执行文件

在成功开发并测试了ONNX模型推理脚本后,接下来我们将考虑如何将该脚本打包为独立的可执行文件(.exe),以便在没有Python环境的系统上运行。可以使用PyInstaller工具来完成这项任务。为了确保打包后的可执行文件能够正常运行,这里尽量减少使用重度依赖库,并手动添加所需的动态链接库(DLL)。

1. 准备工作

首先,确保脚本尽可能少地依赖重度的第三方库。上面我们已经展示了如何编写一个依赖较少的ONNX模型推理脚本。接下来,我们将使用PyInstaller来打包该脚本。

2. 创建 .spec 文件

PyInstaller 通过使用 .spec 文件来定制打包过程。我们可以指定哪些文件、库、以及DLL需要包含在打包的可执行文件中。以下是一个完整的 .spec 文件,我命名为了onnx_to_exe.spec,用于打包我们的ONNX推理脚本。

# -*- mode: python ; coding: utf-8 -*-

a = Analysis(
    ['onnx_to_exe.py'],  # 你的要打包的Python脚本名称
    pathex=['I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages'],  # 指定Python环境的路径
    binaries=[],  # 包含CUDA和onnxruntime的DLL文件
    datas=[
        ('I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_cuda.dll','onnxruntime\\capi'),
        ('I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_shared.dll','onnxruntime\\capi'),
        ('I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_tensorrt.dll', 'onnxruntime\\capi'),
        ('C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v11.8\\bin\\zlibwapi.dll', 'onnxruntime\\capi'),
    ],
    hiddenimports=['cv2', 'onnxruntime', 'numpy', 'numpy.core._multiarray_umath'],  # 手动指定隐式导入的库
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],  # 可以在此排除不需要的库
    noarchive=False,
    optimize=0,
)

pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='onnx_to_exe',  # 生成的可执行文件的名称
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,  # 如果需要使用UPX压缩可执行文件
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,  # 如果需要在控制台运行该程序
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

在使用PyInstaller打包ONNX模型推理脚本时,要正确指定DLL文件的路径,没有指定在后面运行exe会出问题。以下是如何找到这些DLL文件路径并在.spec文件中进行修改的简要说明:

onnxruntime_providers_cuda.dll

  • 路径:该文件通常位于的Python环境中site-packages目录下的onnxruntime子目录中。
  • 查找方法:在命令行中导航到Python环境的site-packages目录,然后进入onnxruntime/capi文件夹,即可找到onnxruntime_providers_cuda.dll文件。
    • 示例路径I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_cuda.dll

onnxruntime_providers_shared.dll

  • 路径:与onnxruntime_providers_cuda.dll位于同一目录,通常在onnxruntime/capi文件夹中。
  • 查找方法:与上述方法相同,查找site-packages/onnxruntime/capi目录下的onnxruntime_providers_shared.dll文件。
    • 示例路径I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_shared.dll

onnxruntime_providers_tensorrt.dll

  • 路径:同样位于site-packages/onnxruntime/capi目录中。
  • 查找方法:进入onnxruntime/capi目录查找onnxruntime_providers_tensorrt.dll文件。
    • 示例路径I:\\CondaEnv\\gpu\\yolov8_gpu\\Lib\\site-packages\\onnxruntime\\capi\\onnxruntime_providers_tensorrt.dll

zlibwapi.dll(CUDA相关文件)

  • 路径:该文件通常位于CUDA安装目录下的bin文件夹中。
  • 查找方法:导航到CUDA安装目录(如C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8),然后进入bin文件夹查找zlibwapi.dll文件。
    • 示例路径C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v11.8\\bin\\zlibwapi.dll

请你按照上面的介绍修改你的spec文件中的路径!


3. 打包脚本

在创建好 .spec 文件后,可以使用PyInstaller来执行打包过程。使用以下命令来生成可执行文件:

pyinstaller onnx_to_exe.spec

这个命令会读取 onnx_to_exe.spec 文件中的配置,并生成独立的可执行文件。默认情况下,生成的文件会放置在 dist 文件夹中。

在这里插入图片描述
我们将onnx模型文件和jpg文件都复制到dist文件夹中,然后双击onnx_to_exe.exe运行:
在这里插入图片描述
此时运行如下的界面

在这里插入图片描述

这样表明打包和运行成功了。这里注意的是,我们添加了多个dll文件,是为了在其他没有进行配置的电脑上仍然能够使用GPU运行。你可以不打包其中的dll文件,即在spec文件中删除那些dll的路径,这样打包后的exe文件会比较小。具体在其他电脑上运行的情况,根据是否有提示问题再解决。


4. 常见问题解决

(1)解决Could not load library cudnn_cnn_infer64_8.dll. Error code 193问题

在使用onnxruntime-gpu进行推理时,有时会遇到以下错误:

Could not load library cudnn_cnn_infer64_8.dll. Error code 193

也就是下面图中出现的:

在这里插入图片描述

这个错误通常是由于onnxruntime-gpu在运行时依赖的cudnn_cnn_infer64_8.dll文件无法加载,而这个文件需要zlibwapi.dll库的支持。对于使用CUDA 11的版本,cuDNN特别需要依赖这个库。然而,许多教程在安装cuDNN时并没有提及要补充安装zlibwapi.dll,因此可能导致这个问题的出现。

(2)下载并安装zlibwapi.dll

要解决这个问题,首先需要确保系统中安装了正确的zlibwapi.dll文件。以下是下载和安装步骤:

  • 下载zlibwapi.dll(64位版本)

    • 请从以下链接之一下载适用于64位系统的zlibwapi.dll
      • zlib for Windows - 在页面底部的“Related External Links”部分,找到“zlib for Windows 9x/NT/2000/XP/2003 (DLL version, plus related utilities)”的链接下载。找不到的话,也可以在DLL‑files.com下载。

      • 直接下载:

        • 64位版本下载
        • 32位版本下载(注意,如果使用的是32位系统,需要使用此链接)
  • 解压并复制zlibwapi.dll

    • 下载完成后,解压文件,将其中的zlibwapi.dll(64位系统请从dll_x64文件夹中获取,32位系统请从dll32文件夹中获取)复制到以下目录:
  1. 复制到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin(请根据实际安装的CUDA版本号调整路径)

在这里插入图片描述
2. 复制到C:\Windows\System32(可以确保系统全局可访问)

在这里插入图片描述

  • 添加系统环境变量
    • 确保将C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin路径添加到系统的Path环境变量中。这样可以确保系统在运行时能够找到并加载zlibwapi.dll

在这里插入图片描述

这样再次运行exe应该就能解决上面那个问题了。如果确认zlibwapi的操作和复制没有问题,还是出现这个问题,那么就可能是CUDA和cuDNN的版本没有匹配了,按照前面说的版本检查方法再查看一下。


总结

ONNX模型的高效部署和独立运行对于生产环境中的深度学习应用还是很重要得。通过本教程,可以掌握以下关键步骤:

  1. 环境准备:要正确安装ONNX Runtime,并确保CUDA和cuDNN版本的兼容性,尤其是在使用GPU加速时的细节处理。

  2. 模型部署:通过实际的代码示例,加载ONNX模型、进行推理,并对结果进行后处理。这个过程不仅涵盖了代码的编写,还涉及如何优化推理效率。

  3. 打包成可执行文件:使用PyInstaller将Python脚本打包成独立的可执行文件,以便在没有Python环境的系统上运行。博主定制了.spec文件,并解决在打包过程中可能遇到的问题。

  4. 问题解决:针对常见的运行时错误,如Could not load library cudnn_cnn_infer64_8.dll. Error code 193,我们提供了详细的解决方案,包括如何正确配置和安装所需的DLL文件。

通过以上这些步骤,将能够顺利地将ONNX模型从开发环境部署到生产环境,并在多种硬件平台上实现高效运行。在开发应用程序还是在优化深度学习模型的运行效率,上面这些技巧和工具希望有所参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国电子学会Python3级等级考试202403客观题解析3

18、 在 Python 中 print(tuple(range(0,8,3)))语句,执行的结果是?( ) A (0,3,6) B (0,2,4,6) C (0,2,4,6) D (0,4) 答案:A range(0,8,3)生成的数据包括0,3,6;tuple()函数将其…

HarmonyOS开发实战( Beta5版)延迟加载lazy-import实践使用指导

随着应用功能持续增加,应用规模不断扩大,依赖的模块文件逐渐变多,应用冷启动加载模块的时间也越来越长。而在实际冷启动过程中执行了很多应用整体依赖但当前未使用的文件,此时可以通过延迟加载 lazy-import 的方法延缓对这些冗余文…

独立产品灵感周刊 DecoHack #066 – 下周苹果发布会要来了

本周刊记录有趣好玩的独立产品/设计/开发相关内容,每周一发布,往期内容同样精彩,感兴趣的伙伴可以到 官网查看更多内容。可以 邮件订阅或 RSS订阅本周刊。欢迎通过 Twitter 私信推荐或投稿。 💻 产品推荐 1. Apple Bento Slides…

基于C++实现(MFC界面)家谱管理系统

一、题目:家谱管理系统 二、内容: 2.1 概述 2.1.1 选题原因 做此题的原因是因为可以比较方便的记录家族历代成员的情况与关系,能很好的保存家族每一代的信息,而不用人工纸质的方式来存取家谱,更便于人们保存和使用…

青蓝智慧科技:京津冀氢能与绿色低碳创新应用场景发布

8月29日,北京成功举办了京津冀(唐山)氢能与绿色低碳创新应用场景的发布及供需对接活动。 在此活动中,唐山市科技局推出了涉及氢能与绿色低碳的创新应用方案,这些方案旨在抓住京津冀氢燃料电池汽车示范城市群、碳达峰试…

java后端开发-Mybatis连接数据库步骤

🤹‍♀️潜意识起点:个人主页 🎙座右铭:得之坦然,失之淡然。 💎擅长领域:前端 是的,我需要您的: 🧡点赞❤️关注💙收藏💛 是我持…

软通动力子公司鸿湖万联重磅发布SwanLinkOS 5,擘画开源鸿蒙AI PC新篇章

在刚刚落下帷幕的首届H•I AI 探索峰会上,软通动力再次于鸿蒙生态领域实现突破。此次活动中,软通动力高级副总裁、鸿湖万联总经理秦张波发布SwanLinkOS 5(天鸿操作系统),并联合软通计算(同方计算机&#xf…

Qt 样式表、选择器、盒子模型

1、两种样式表的写法 方式一(普通写法): this->setStyleSheet("QPushButton""{""background:yellow;""font:bold 14px;""color: red;""}""QPushButton:hover"&quo…

【Day07】

目录 MySQL-DQL- 基本查询 MySQL-DQL- 条件查询 MySQL-DQL- 聚合函数 MySQL-DQL- 分组查询 MySQL-DQL- 排序查询 MySQL-DQL- 分页查询 MySQL-DQL- 案例 MySQL-多表设计-一对多 MySQL-多表设计-一对多-外键约束 MySQL-多表设计-一对一&多对多 MySQL-多表设计-案例…

【MA35D1】buildroot 编译使用经验

文章目录 芯片介绍Buildroot开发Linux实践环境搭建代码获取编译执行步骤(仅适用于我公司产品) 后续有需要更改的输出文件目录 芯片介绍 NuMicro MA35D1系列为一颗异核同构的多核心微处理器,适用于高端 Edge IIoT Gateway。它是基于双核 64 位…

【OpenWrt(3)】内网搭建iperf3测速服务器

下载的iperf3 网站:https://iperf.fr/iperf-download.php Window地址:https://github.com/ar51an/iperf3-win-builds 安卓:https://gitee.com/hiyanyx/magic-i-perf 文章目录 下载的iperf3Windows 服务器启动安卓客户端启动参考 Windows 服务…

简单的EasyCaptcha图片验证码学习

简单的EasyCaptcha图片验证码学习 1. 需求 图片验证码是一种常见的验证形式,它通过生成一串随机数字或符号,并加入一些干扰像素,最终生成用于验证的图片。这种验证码的设计旨在增加破解难度,主要通过加大干扰强度来提高安全性。…

如何在 Vue 中创建一个带有表格和表单的弹窗

本文将通过一个具体的示例来介绍如何在 Vue 应用中实现一个带有表格和表单功能的弹窗组件。我们将使用 Element UI 库中的 el-dialog 组件来构建这个弹窗,并结合 el-table 和 el-form 来展示数据并允许用户进行编辑。 效果图: 完整代码最底部&#xff0…

火语言RPA流程组件介绍--文件系统监控

🚩【组件功能】:监控指定文件夹或文件的创建、变更删除等事件 配置预览 配置说明 事件类型 “异步回调处理”、“同步等待”2种类型供选择。流程是否等待发生监控文件的创建、变更、删除事件,异步不等待,同步则等待。 监控文件…

MySQL创建数据库和表应用教程

前言 MySQL 是一种流行的关系型数据库管理系统(RDBMS),广泛应用于 web 应用开发中。以下是一个简单的 MySQL 创建数据库和表的教程,涵盖了基本步骤。假设你已经安装了 MySQL 并且能够通过命令行或 MySQL Workbench 等工具访问它。…

【网络安全】服务基础第一阶段——第五节:Windows系统管理基础---- DHCP部署与安全

目录 一、DHCP协议 理解DHCP握手: 分配IP地址方式: DHCP协议报文的种类: DHCP协议工作过程: ​编辑DHCP四个阶段: 续约租期: 重新连接使用IP地址: DHCP安全性: 二、DHCP中继…

海龟交易系统所代表的传统CTA策略是不是过时了?

原创内容第639篇,专注量化投资、个人成长与财富自由。 量化投资具体步骤:数据、指标(因子),信号规则或因子合成,策略,绩效评估,风控。 其实所有的策略都可以归结为以上的步骤。 我…

Redis 篇-深入了解查询缓存与缓存所带来的问题(读写不一致、缓存穿透、缓存雪崩、缓存击穿)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 本章目录 1.0 什么是缓存 2.0 项目中具体如何添加缓存 3.0 添加缓存后所带来的问题 3.1 读写不一致问题 3.1.1 缓存更新策略 3.1.2 具体实现缓存与数据库的双写一致 3.2 缓存穿…

DAC专用功能芯片TI DAC8562/8563

DAC8563具有 2.5V、4ppm/C 基准的 16 位、双通道、低功耗、超低短时脉冲波形干扰、缓冲电压输出 DAC。 DAC8562是一款16位、双通道、串行接口的DAC,采用SPI接口进行通信,具有内部参考电压、软件可编程增益和输出保护等功能。 一、DAC8563的主要参数 供…

JVM面试(二)内存区域划分

内存区划分 Java虚拟机在执行Java程序的过程中会把它锁管理的内存划分为若干个不同的数据区域。 这些区域有各自不同的用途,以及创建和销毁的时间。 有的区域随着虚拟机的进程一直存在,有的区域依赖用户线程的启动和结束而建立和销毁。 根据《Java虚拟…