【TVM教程】在支持 CMSIS-NN 的 Arm(R) Cortex(R)-M55 CPU 和 Ethos(TM)-U55 NPU 裸机上运行 TVM
Apache TVM是一个深度的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 →https://tvm.hyper.ai/
作者:Grant Watson
本节使用示例说明如何使用 TVM 在带有 CMSIS-NN 的 Arm® Cortex®-M55 CPU 和 Ethos™-U55 NPU 的裸机上运行模型。Cortex®-M55 是一款用于嵌入式设备的小型低功耗 CPU。CMSIS-NN 是针对 Arm® Cortex®-M CPU 优化的内核集合。Ethos™-U55 是一种 microNPU,专门为在资源受限的嵌入式设备中,加速机器学习的推理而设计。
在没有 Cortex®-M55 和 Ethos™-U55 开发板的情况下,若要运行 demo 程序,可在固定虚拟平台(FVP)上运行。基于 Arm® Corstone™-300 软件的 FVP,对包含 Cortex®-M55 和 Ethos™-U55 的硬件系统进行建模。它对于软件开发非常友好。
本教程将编译一个 MobileNet v1 模型并使用 TVM 尽可能将算子迁移到 Ethos™-U55。
获取 TVM
为平台获取 TVM,请访问 https://tlcpack.ai/ 并按照说明进行操作。正确安装 TVM 后,可以通过命令行访问 tvmc
。
在命令行上键入 tvmc
应显示以下内容:
usage: tvmc [-h] [-v] [--version] {tune,compile,run} ...TVM compiler driveroptional arguments:-h, --help show this help message and exit-v, --verbose increase verbosity--version print the version and exitcommands:{tune,compile,run}tune auto-tune a modelcompile compile a model.run run a compiled moduleTVMC - TVM driver command-line interface
安装额外的 Python 依赖
运行 demo 需要一些额外的 Python 包。通过下面的 requirements.txt 文件,来安装这些额外的 Python 包:
requirements.txt¶
attrs==21.2.0cloudpickle==2.0.0decorator==5.1.0ethos-u-vela==3.8.0flatbuffers==2.0.7lxml==4.6.3nose==1.3.7numpy==1.19.5Pillow==8.3.2psutil==5.8.0scipy==1.5.4tflite==2.4.0tornado==6.1
运行以下命令来安装这些软件包:
pip install -r requirements.txt
获取模型
本教程使用 MobileNet v1 模型(一种卷积神经网络,旨在对图像进行分类),该模型针对边缘设备进行了优化。要使用的模型已经预训练过,它可以可以识别 1001 个类别。该网络的输入图像大小为 224x224,任何输入图像在使用之前都需要调整到这个尺寸。
本教程使用 TFLite 格式的模型。
mkdir -p ./build
cd build
wget https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224_quant.tgz
gunzip mobilenet_v1_1.0_224_quant.tgz
tar xvf mobilenet_v1_1.0_224_quant.tar
为具有 CMSIS-NN 的 Arm® Cortex®-M55 CPU 和 Ethos™-U55 NPU 设备编译模型
下载 MobileNet v1 模型后,下一步是用 tvmc compile 进行编译。编译过程中得到的输出是模型的 TAR 包,该模型编译为 target 平台的模型库格式(MLF),能够用 TVM runtime 在 target 设备上运行该模型。
tvmc compile --target=ethos-u,cmsis-nn,c \--target-ethos-u-accelerator_config=ethos-u55-256 \--target-cmsis-nn-mcpu=cortex-m55 \--target-c-mcpu=cortex-m55 \--runtime=crt \--executor=aot \--executor-aot-interface-api=c \--executor-aot-unpacked-api=1 \--pass-config tir.usmp.enable=1 \--pass-config tir.usmp.algorithm=hill_climb \--pass-config tir.disable_storage_rewrite=1 \--pass-config tir.disable_vectorize=1 \./mobilenet_v1_1.0_224_quant.tflite \--output-format=mlf
备注
tvmc 编译参数说明:
--target=ethos-u,cmsis-nn,c
:在可能的情况下将算子迁移到 microNPU,回退到 CMSIS-NN 并最终生成 microNPU 不支持的算子的 C 代码。--target-ethos-u-accelerator_config=ethos-u55-256
:指定 microNPU 配置。--target-c-mcpu=cortex-m55
:针对 Cortex®-M55 进行交叉编译。--runtime=crt
:生成粘合代码以支持算子使用 C runtime。--executor=aot
:使用 Ahead Of Time 编译而非 Graph Executor。--executor-aot-interface-api=c
:生成一个 C 风格的接口,其结构专为在边界集成到 C 应用程序而设计。--executor-aot-unpacked-api=1
:在内部使用非压缩的 API。--pass-config tir.usmp.enable=1
:启用统一静态内存规划--pass-config tir.usmp.algorithm=hill_climb
:对 USMP 使用爬山算法--pass-config tir.disable_storage_rewrite=1
: 禁用存储重写--pass-config tir.disable_vectorize=1
:禁用向量化,因为 C 中没有标准的向量化类型。./mobilenet_v1_1.0_224_quant.tflite
:正在编译的 TFLite 模型。--output-format=mlf
:以模型库格式生成输出。
备注
若不想用 microNPU 进行迁移
仅适用于 CMSIS-NN 的算子:
- 使用
--target=cmsis-nn,c
代替--target=ethos-u,cmsis-nn,c
- 删除 microNPU 配置参数
--target-ethos-u-accelerator_config=ethos-u55-256
将生成的代码解压到当前目录
tar xvf module.tar
获取 ImageNet 标签
在图像上运行 MobileNet v1 时,输出结果是 0 到 1000 的索引。为了使应用程序对用户更加友好,将显示相关标签,而非仅显示类别索引。将图像标签下载到一个文本文件中,然后用 Python 脚本将它们包含在 C 程序中。
curl -sS https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/lite/java/demo/app/src/main/assets/labels_mobilenet_quant_v1_224.txt \
-o ./labels_mobilenet_quant_v1_224.txt
获取输入图像
本教程使用猫的图像作为输入,也可以自行替换为其他图像。
将图像下载到构建目录中,下一步用 Python 脚本,将图像转换为 C 头文件中的字节数组。
curl -sS https://s3.amazonaws.com/model-server/inputs/kitten.jpg -o ./kitten.jpg
预处理图像
以下脚本将在 src 目录中创建 2 个 C 头文件:
inputs.h
- 作为脚本参数提供的图像将被转换为整数数组,以输入到 MobileNet v1 模型。outputs.h
- 用一个全零的整数数组,为推理的输出保留 1001 个整数值。
convert_image.py¶
#!python ./convert_image.py
import os
import pathlib
import re
import sys
from PIL import Image
import numpy as npdef create_header_file(name, section, tensor_name, tensor_data, output_path):"""这个函数产生一个头文件,包含 numpy 数组提供的数据。"""file_path = pathlib.Path(f"{output_path}/" + name).resolve()# 创建带有 npy_data 的头文件作为 C 数组raw_path = file_path.with_suffix(".h").resolve()with open(raw_path, "w") as header_file:header_file.write("#include <tvmgen_default.h>\n"+ f"const size_t {tensor_name}_len = {tensor_data.size};\n"+ f'uint8_t {tensor_name}[] __attribute__((section("{section}"), aligned(16))) = "')data_hexstr = tensor_data.tobytes().hex()for i in range(0, len(data_hexstr), 2):header_file.write(f"\x{data_hexstr[i:i+2]}")header_file.write('";\n\n')def create_headers(image_name):"""此函数为运行推理所需的输入和输出数组生成 C 头文件"""img_path = os.path.join("./", f"{image_name}")# 将图像大小调整为 224x224resized_image = Image.open(img_path).resize((224, 224))img_data = np.asarray(resized_image).astype("float32")# 将输入转换为 NCHWimg_data = np.transpose(img_data, (2, 0, 1))# 创建输入头文件input_data = img_data.astype(np.uint8)create_header_file("inputs", "ethosu_scratch", "input", input_data, "./include")# 创建输出头文件output_data = np.zeros([1001], np.uint8)create_header_file("outputs","output_data_sec","output",output_data,"./include",)if __name__ == "__main__":create_headers(sys.argv[1])
用以下命令行运行脚本:
python convert_image.py ./kitten.jpg
预处理标签
以下脚本将在 src 目录中创建一个 labels.h
头文件,之前下载的 labels.txt 文件会变成字符串数组。该数组将用于显示图像分类后为的标签。
convert_labels.py¶
#!python ./convert_labels.py
import os
import pathlib
import sysdef create_labels_header(labels_file, section, output_path):"""此函数生成一个包含 ImageNet 标签的头文件作为字符串数组"""labels_path = pathlib.Path(labels_file).resolve()file_path = pathlib.Path(f"{output_path}/labels.h").resolve()with open(labels_path) as f:labels = f.readlines()with open(file_path, "w") as header_file:header_file.write(f'char* labels[] __attribute__((section("{section}"), aligned(16))) = {{')for _, label in enumerate(labels):header_file.write(f'"{label.rstrip()}",')header_file.write("};\n")if __name__ == "__main__":create_labels_header(sys.argv[1], "ethosu_scratch", "./include")
用以下命令行运行脚本:
python convert_labels.py
编写 demo
下面的 C 程序会在之前下载并转换为整数数组的图像上,运行 MobileNet v1 模型的单个推理。由于该模型是以「ethos-u …」为 target 编译的,因此需要迁移 Ethos™-U55 NPU 支持的算子,以便进行加速。一旦应用程序构建并运行,测试图像应该被正确地归类为「tabby」,并且结果会显示在控制台上。这个文件应该放在 ./src
。
demo.c¶
#include <stdio.h>#include <tvm_runtime.h>#include "ethosu_mod.h"#include "uart_stdout.h"// convert_image.py 和 convert_labels.py 生成的头文件#include "inputs.h"#include "labels.h"#include "outputs.h"int abs(int v) { return v * ((v > 0) - (v < 0)); }int main(int argc, char** argv) {UartStdOutInit();printf("Starting Demo\n");EthosuInit();printf("Allocating memory\n");StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE);printf("Running inference\n");struct tvmgen_default_outputs outputs = {.output = output,};struct tvmgen_default_inputs inputs = {.input = input,};struct ethosu_driver* driver = ethosu_reserve_driver();struct tvmgen_default_devices devices = {.ethos_u = driver,};tvmgen_default_run(&inputs, &outputs, &devices);ethosu_release_driver(driver);// 计算最大值的索引uint8_t max_value = 0;int32_t max_index = -1;for (unsigned int i = 0; i < output_len; ++i) {if (output[i] > max_value) {max_value = output[i];max_index = i;}}printf("The image has been classified as '%s'\n", labels[max_index]);// 当 FVP 在 UART 上接收到「EXITTHESIM」时,FVP 将关闭printf("EXITTHESIM\n");while (1 == 1);return 0;}
此外,需要将 github 的这些头文件放入 ./include
目录:
包含文件
备注
若要用 FreeRTOS 进行任务调度和队列,可以在 demo_freertos.c 找到示例程序。
创建链接脚本(linker script)
创建一个链接脚本,便于在下一节中构建应用程序时使用。链接脚本告诉链接器所有文件都放在内存中。下面的 corstone300.ld 链接脚本应该放在工作目录中。
查看 FVP 示例链接脚本 corstone300.ld
备注
TVM 生成的代码会将模型权重和 Arm® Ethos™-U55 命令流放在名为 ethosu_scratch
的部分中,对于 MobileNet v1 大小的模型,无法将权重和命令流全部放入 SRAM 的可用空间(因为 SRAM 空间十分有限)。因此,链接脚本将 ethosu_scratch
这部分放入 DRAM(DDR)中。
备注
在构建和运行应用程序之前,需要更新 PATH 环境变量,使其包含 cmake 3.19.5 和 FVP 的路径。例如,若已将它们安装在 /opt/arm
中,则执行以下操作:
export PATH=/opt/arm/FVP_Corstone_SSE-300_Ethos-U55/models/Linux64_GCC-6.4:/opt/arm/cmake/bin:$PATH
使用 make 构建 demo
接下来可以使用 make 构建 demo。在命令行运行 make
之前,应将 Makefile 移在工作目录中:
Makefile 示例:Makefile
备注
若使用的是 FreeRTOS,Makefile 会从指定的 FREERTOS_PATH 构建:
make FREERTOS_PATH=<FreeRTOS directory>
运行 demo
最后,使用以下命令在固定虚拟平台(Fixed Virtual Platform,简称 FVP)上运行 demo:
FVP_Corstone_SSE-300_Ethos-U55 -C cpu0.CFGDTCMSZ=15 \
-C cpu0.CFGITCMSZ=15 -C mps3_board.uart0.out_file="-" -C mps3_board.uart0.shutdown_tag="EXITTHESIM" \
-C mps3_board.visualisation.disable-visualisation=1 -C mps3_board.telnetterminal0.start_telnet=0 \
-C mps3_board.telnetterminal1.start_telnet=0 -C mps3_board.telnetterminal2.start_telnet=0 -C mps3_board.telnetterminal5.start_telnet=0 \
-C ethosu.extra_args="--fast" \
-C ethosu.num_macs=256 ./build/demo
应在控制台窗口中看到以下输出:
telnetterminal0: Listening for serial connection on port 5000
telnetterminal1: Listening for serial connection on port 5001
telnetterminal2: Listening for serial connection on port 5002
telnetterminal5: Listening for serial connection on port 5003Ethos-U rev dedfa618 --- Jan 12 2021 23:03:55(C) COPYRIGHT 2019-2021 Arm LimitedALL RIGHTS RESERVEDStarting Demo
ethosu_init. base_address=0x48102000, fast_memory=0x0, fast_memory_size=0, secure=1, privileged=1
ethosu_register_driver: New NPU driver at address 0x20000de8 is registered.
CMD=0x00000000
Soft reset NPU
Allocating memory
Running inference
ethosu_find_and_reserve_driver - Driver 0x20000de8 reserved.
ethosu_invoke
CMD=0x00000004
QCONFIG=0x00000002
REGIONCFG0=0x00000003
REGIONCFG1=0x00000003
REGIONCFG2=0x00000013
REGIONCFG3=0x00000053
REGIONCFG4=0x00000153
REGIONCFG5=0x00000553
REGIONCFG6=0x00001553
REGIONCFG7=0x00005553
AXI_LIMIT0=0x0f1f0000
AXI_LIMIT1=0x0f1f0000
AXI_LIMIT2=0x0f1f0000
AXI_LIMIT3=0x0f1f0000
ethosu_invoke OPTIMIZER_CONFIG
handle_optimizer_config:
Optimizer release nbr: 0 patch: 1
Optimizer config cmd_stream_version: 0 macs_per_cc: 8 shram_size: 48 custom_dma: 0
Optimizer config Ethos-U version: 1.0.6
Ethos-U config cmd_stream_version: 0 macs_per_cc: 8 shram_size: 48 custom_dma: 0
Ethos-U version: 1.0.6
ethosu_invoke NOP
ethosu_invoke NOP
ethosu_invoke NOP
ethosu_invoke COMMAND_STREAM
handle_command_stream: cmd_stream=0x61025be0, cms_length 1181
QBASE=0x0000000061025be0, QSIZE=4724, base_pointer_offset=0x00000000
BASEP0=0x0000000061026e60
BASEP1=0x0000000060002f10
BASEP2=0x0000000060002f10
BASEP3=0x0000000061000fb0
BASEP4=0x0000000060000fb0
CMD=0x000Interrupt. status=0xffff0022, qread=4724
CMD=0x00000006
00006
CMD=0x0000000c
ethosu_release_driver - Driver 0x20000de8 released
The image has been classified as 'tabby'
EXITTHESIM
Info: /OSCI/SystemC: Simulation stopped by user.
可以看到,输出的最后部分显示图像已被正确分类为「tabby」。
下载 Python 源代码:micro_ethosu.py
下载 Jupyter Notebook:micro_ethosu.ipynb
相关文章:
【TVM教程】在支持 CMSIS-NN 的 Arm(R) Cortex(R)-M55 CPU 和 Ethos(TM)-U55 NPU 裸机上运行 TVM
Apache TVM是一个深度的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 →https://tvm.hyper.ai/ 作者:Grant Watson 本节使用示例说明如何使用 TVM 在带有 CMSIS-NN 的 Arm Cortex-M55 CPU 和 Ethos™-U55 NPU 的…...
【Ai/Agent】Windows11中安装CrewAI过程中的错误解决记录
CrewAi是什么,可以看之下之前写的 《初识CrewAI多智能代理团队协框架》 (注:这篇是基于linux系统下安装实践的) 基于以下记录解决问题后,可以再回到之前的文章继续进行CrewAI的安装 遇到问题 在windows系统中安装 CrewAi 不管是使用 pip 或者…...
洛谷 P11962:[GESP202503 六级] 树上漫步 ← dfs + 邻接表
【题目来源】 https://www.luogu.com.cn/problem/P11962 【题目描述】 小 A 有一棵 n 个结点的树,这些结点依次以 1,2,⋯,n 标号。 小 A 想在这棵树上漫步。具体来说,小 A 会从树上的某个结点出发,每⼀步可以移动到与当前结点相邻的结点&…...
Linux shell脚本编程
什么是Shell程序设计? 也就是给计算机发命令,让它帮你做事,你通过shell 的小工具,用键盘输入指令,linux就会根据这些指令去执行任务,就像你法号一个指令一样。 shell的强大之处? 文件处理&a…...
嵌入式硬件篇---Uart和Zigbee
文章目录 前言一、UART(通用异步收发传输器)1. 基本概念2. 工作原理帧结构起始位数据位校验位停止位 异步通信波特率 3. 特点优点缺点 4. 典型应用 二、ZigBee1. 基本概念2. 技术细节工作频段2.4GHz868MHz 网络拓扑星型网络网状网络簇状网络 协议栈物理层…...
Linux Makefile-概述、语句格式、编写规则、多文件编程、Makefile变量分类:自定义变量、预定义变量
目录 1.make 1.1 make 命令格式 2.Makefile 核心概念 2.1创建并运行 Makefile步骤 3. Makefile编写 3.1最基础Makefile 3.1.1使用默认make命令 3.1.2使用make -f 命令 3.1.3 gcc编译常用组合选项 3.1.4 make 和 make all区别 3.1.4.1 all 是默认目标 3.1.4.2 al…...
Kotlin日常使用函数记录
文章目录 前言字符串集合1.两个集合的差集2.集合转数组2.1.集合转基本数据类型数组2.2.集合转对象数组 Map1.合并Map1.1.使用 操作符1.2.使用 操作符1.3.使用 putAll 方法1.4.使用 merge 函数 前言 记录一些kotlin开发中,日常使用的函数和方式之类的,…...
【JavaScript】异步编程
个人主页:Guiat 归属专栏:HTML CSS JavaScript 文章目录 1. 异步编程基础1.1 同步与异步1.1.1 同步执行1.1.2 异步执行 1.2 JavaScript 事件循环 2. 回调函数2.1 基本回调模式2.2 错误处理2.3 回调地狱 3. Promise3.1 Promise 基础3.2 Promise 链式调用3…...
批量合并多张 jpg/png 图片为长图或者 PDF 文件,支持按文件夹合并图片
我们经常会碰到需要将多张图片拼成一张图片的场景,比如将多张图片拼成九宫格图片,或者将多张图片拼成一张长图。还有可能会碰到需要将多张图片合并成一个完整的 PDF 文件来方便我们进行打印或者传输等操作。那这些将图片合并成一张图片或者一个完整的文档…...
使用docker 安装向量数据库Milvus
Miluvs 官网 www.milvus.io/ https://milvus.io/docs/zh/install_standalone-docker-compose-gpu.md 一、基本概念 向量数据库:Milvus是一款云原生向量数据库,它支持多种类型的向量,如浮点向量、二进制向量等,并且可以处理大规模…...
在线PDF文件拆分工具,小白工具功能实用操作简单,无需安装的文档处理工具
小白工具中的在线 PDF 文件拆分工具是一款功能实用、操作便捷的文档处理工具,以下是其具体介绍: 操作流程 上传 PDF 文档:打开小白工具在线PDF文件拆分工具 - 快速、免费拆分PDF文档 - 小白工具的在线 PDF 文件拆分页面,通过点击 …...
Blender画图——阵列使用
如图我需要多个图示的图形,并且排成一个阵列效果。 如图依次点击效果。不要用相对偏移,要用恒定偏移。 如图设置数量。 如图完成x方向的画图后,我们需要在y方向再用一个阵列。...
VSCode 常用快捷键
Visual Studio Code (VSCode) 提供了许多快捷键,以帮助开发者提高编码效率。以下是一些常用的 VSCode 快捷键,这些快捷键适用于大多数操作系统,但在 macOS 上可能会有所不同(通常是将 Ctrl 替换为 Cmd)。 1. 文件和编…...
缓存相关问题
Redis 持久化机制 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题 热点数据和冷数据是什么 Memcache与Redis的区别都有哪些? 单线程的redis为什么这么快 redis的数据类型,以及每种数据类型的使用场景,Redis 内部结构 redis的过期策略以及内存淘汰机制 Redis 为什么…...
每日一题(小白)暴力娱乐篇22
为什么要经常学习暴力和一些娱乐呢?因为对于我们来说,暴力是最直接的方式是肯定能满足一部分答案的方法,娱乐是为了让算法变得更有趣,你愿意多去尝试多去练习,这才是最要紧的。 由题意知,就是计算两个数字…...
深入理解 Vuex:核心概念、API 详解与最佳实践
目录 Vuex 简介核心概念与工作流程核心 API 详解模块化开发 (modules)插件(Plugins)与扩展高级技巧与最佳实践 Vuex 简介 Vuex 是 Vue.js 的官方状态管理库,专为复杂应用设计,用于集中管理所有组件的共享状…...
成为一种国家战略范畴的新基建的智慧园区开源了。
智慧园区场景视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界…...
拜特科技助力科达制造,资金管理信息化迈入新阶段
近日,拜特科技成功签约科达制造股份有限公司(以下简称“科达制造”)资金管理系统升级项目。科达制造通过资金管理系统的不断迭代升级和优化,能够更加高效地管理和运用资金,提高企业的资金利用效率,满足企业…...
每日一题(小白)暴力娱乐篇20
这个题用瞪眼法解决,snakeaekns 代码如下👇 public static void main(String[] args) {Scanner scannew Scanner(System.in);System.out.println("aekns");scan.close();} 第二种方式:将snack拆解,按照大小进行排序。…...
Flutter iOS 项目中 VolumeControllerPlugin 报错解决方案
Flutter iOS 项目中 VolumeControllerPlugin 报错解决方案 在开发 Flutter 应用时,有时会遇到 iOS 项目构建失败的情况,其中一种较为常见的错误是与 VolumeControllerPlugin 相关的报错,错误信息如下: Could not build the prec…...
Java实战报错 tcp
为什么报错tcp Preview 从图片中的错误信息来看,程序遇到了 java.net.BindException,具体错误信息是 "Address already in use: bind"。这意味着你的程序试图绑定到一个已经被其他进程占用的端口(在本例中是9999端口)。…...
【补题】P10424 [蓝桥杯 2024 省 B] 好数(数位dp)
题意: 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数,我们就称之为“好数”。 给定一个正整数 N…...
控制 ElementUI el-table 树形表格多选框的显示层级
1、你可以通过 selectable 属性来控制哪些行可以选择(显示多选框) <el-table:data"tableData"row-key"id"default-expand-all:tree-props"{children: children, hasChildren: hasChildren}"select"handleSelect&…...
今日行情明日机会——20250409
今日行情还需要考虑关税对抗~ 2025年4月8日涨停的主要行业方向分析 1. 军工(19家涨停) 细分领域:国防装备、航空航天、军民融合。催化因素:国家安全战略升级、国防预算增加、重大军工项目落地预期。 2. 免税(15家涨…...
基础知识补充篇:什么是DAPP前端连接中的provider
专栏:区块链入门到放弃查看目录-CSDN博客文章浏览阅读352次。为了方便查看将本专栏的所有内容列出目录,按照顺序查看即可。后续也会在此规划一下后续内容,因此如果遇到不能点击的,代表还没有更新。声明:文中所出观点大多数源于笔者多年开发经验所总结,如果你想要知道区块…...
47常用控件_QWidget的toolTip属性
一个 GUI 程序,界面比较复杂, 按啥的很多~~ 当你把鼠标悬停到这个控件上的时候,就能弹出一个提示~~ setToolTip:设置提示内容 setToolTipDuring:设置提示的时间 toolTip 只是给用户看的.在代码中一般不需要获取到 toolTip. 代码示例: 设置按钮的 toolT…...
解密工业控制柜:认识关键硬件(PLC)
前言 作为一名视觉开发工程师,我们不仅要做到做好自己的工作,我们更需要在工业现场学习更多知识,最近网上流传很多,“教会徒弟,饿死师傅”;在自动化行业中,在项目下来很忙的时候,我们…...
PDF编辑,小白工具功能丰富多样,在线无需下载,操作便捷,新手小白必备
在当今数字化办公和学习的时代,PDF 文件的使用极为广泛,而小白工具的在线 PDF 浏览器以其强大且丰富的功能,成为了一款不可多得的优质 PDF 阅读工具,PDF编辑,在线无需下载,操作便捷,新手小白必备以下为您详细推荐: 功能…...
网络安全公司推荐:F5荣膺IDC全球Web应用与API防护领导者
API的广泛使用正推动安全实践的重大变革。研究表明,有41%的企业管理的API数量至少与应用数量相等,因此企业亟需实现全面的API防护。近日,IDC发布《IDC MarketScape:2024年全球Web应用和API防护企业平台供应商评估报告》࿰…...
WPF轮播图动画交互 动画缩放展示图片
WPF轮播图动画交互 动画缩放展示图片 效果如下图: XAML代码: <Window x:Class"Caroursel.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/20…...
玩转Docker | 使用Docker安装FileDrop文件共享工具
玩转Docker | 使用Docker安装FileDrop文件共享工具 前言一、FileDrop介绍FileDrop简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署FileDrop服务下载镜像创建容器检查容器状态检查服务端口安全设置四、访问FileDrop应用创建名称五、测试与使用…...
实战篇-主时钟约束
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据 总结 前言 这是对B站傅里叶的猫视频时钟约束的笔记 一、主时钟约束 report_clock_networks …...
Oracle JDBC驱动 ojdbc14:使用指南与版本说明(附资源下载)
ojdbc14 是 Oracle 公司提供的 JDBC(Java 数据库连接)驱动程序,用于连接 Java 应用程序与 Oracle 数据库。 ojdbc14.jar包已下载:https://pan.quark.cn/s/5ee7841dcd9c 关键信息 用途:使 Java 应用程序能够连接 Orac…...
spring mvc 异常处理中@RestControllerAdvice 和 @ControllerAdvice 对比详解
RestControllerAdvice 和 ControllerAdvice 对比详解 1. 基本概念 注解等效组合核心作用ControllerAdviceComponent RequestMapping(隐式)定义全局控制器增强类,处理跨控制器的异常、数据绑定或全局响应逻辑。RestControllerAdviceControll…...
单元测试原则之——不要过度模拟
什么是过度模拟? 过度模拟(over-mocking)是指在单元测试中,模拟了太多依赖项,甚至模拟了本不需要模拟的简单对象或行为。过度模拟会导致: 测试代码变得复杂,难以阅读和维护。测试逻辑偏离了实际业务逻辑,无法验证真实代码的行为。忽略了被测单元与依赖项之间的真实交互…...
云轴科技ZStackCTO王为:AI Infra平台具备解决私有化AI全栈难题能力
4月1-2日,2025中国生成式AI大会在北京举办,该会议已成为国内AI领域最具影响力的产业峰会之一。云轴科技ZStack CTO王为受邀在“大模型”峰会上发表主题为《AI 原生实践:企业实际场景的 AI 赋能与 Infra 实践探索》演讲,并参加《De…...
牛客 小苯的Z串匹配
注意数组元素是0的情况 #include<iostream> using namespace std;int t; const int N2e510;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>t;while(t){long long n;cin>>n;long long a[N];for(int i0; i<n; i) cin>>a[i];stri…...
拜特科技受邀参加跨境电商行业分会,共探资金管理数字化与AI应用新路径
3月12日,由广东省首席信息官协会主办的“跨境电商行业分会——走进绿联科技”活动在深圳绿联科技圆满举行。作为专注于金融科技与资金管理数字化解决方案的领先提供商,拜特科技受邀参加此次会议,与行业精英共同探讨跨境电商企业的资金管理数字…...
贪心算法(17)(java)可被三整除的最大整数和
给你一个整数数组 nums,请你找出并返回能被三整除的元素 最大和。 示例 1: 输入:nums [3,6,5,1,8] 输出:18 解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。 …...
架构师面试(二十八):业务建模
问题 今天我们撇开纯技术,聊一下关于【业务建模】的话题。 何为业务建模?即通过易于理解的模型将业务中的关键问题准确表达出来。 业务建模是需求分析环节乃至整个软件生命周期中非常关键的一环,它几乎决定了软件的开发周期和成本。下面关…...
求教:vue中的find()函数的用法this.$set
需求:为了实现联动,当我在选择问题标题之后,后面几列的内容就会自动联动显示 方案一: 选完之后 直接 是this.questionList[index] this.selected; 这样的效果虽然改动了数组,但是页面上没有显示出来实际数组的内容 …...
常见算法模板总结
文章目录 一、二叉树1. DFS2. BFS 二、回溯模板三、记忆化搜索四、动态规划1. 01背包朴素版本滚动数组优化 2. 完全背包朴素版本滚动数组优化 3. 最长递增子序列LIS朴素版本贪心二分优化 4. 最长公共子序列5. 最长回文子串 五、滑动窗口六、二分查找七、单调栈八、单调队列九、…...
生产者消费者模型
目录 一、生产者消费者模型 1. 生产者消费者模型是什么? 2. 为什么使用生产者消费者模型? 3. 生产者消费者模型的特点(321原则) 🌵3种关系 🌵2种角色 🌵1个交易场所 二、基于BlockingQue…...
linux里怎么禁用 其他用户使用sudo添加定时器,例如创建的tomcat用户禁止使用 sudo crontab -u tomcat -e 添加定时器
要禁止 tomcat 用户通过 sudo crontab -u tomcat -e 添加定时任务,需从 sudo 权限控制和 crontab 访问限制两方面入手。以下是具体步骤: 一、核心思路 禁止 tomcat 用户使用 sudo 提权执行 crontab 修改 /etc/sudoers 配置,移除 tomcat 用户…...
函数作为返回值输出
实际上,函数当做返回值输出的应用场景也很多,也更能体现函数式变成的巧妙,让函数继续返回一个可执行的函数,意味着运算过程是可延续的。 判断数据的类型 常见的判断一个数据的类型的函数: 单例模式 下面是一个单例模…...
黑马 SpringAI+DeepSeek 实战:从对话机器人到企业级知识库的大模型开发全攻略
附完整代码 项目案例,3 天吃透大模型应用开发核心技术 需要完整项目学习视频以及源码的私信博主,谢谢~大家一起加油呐!! 01.认识AI和大模型 小结 AI的发展过程 符号主义 机器学习 深度学习——自然语言处理(NLP…...
word表格间隔设置
1.怎么解决word表格间隔达不到我们想要的要求 其实很简单, 我们直接在word表格里面, 全选表格中里面的内容。接着,我们选择自动调整---->根据内容自动调整表格,即可达到我们想要的要求...
Windows批处理脚本,bat 循环数组进入文件夹进行后续操作
文章目录 前言一、脚本功能解析1.2、定义数组1.2、遍历数组1.2、处理每个数组元素1.2、循环控制1.2、结束脚本 二、之前编写的脚本三、优化后的脚本代码四、总结五、感谢 前言 Windows批处理脚本,主要功能是遍历一个预定义的数组,并对每个数组元素执行cd…...
TurtleBot3 Package turtlebot3_drive source code read
前言 此处阅读简单的 turtlebot3_drive 代码。 从ROS的角度,作为一个demo,它足够小、简单,可以从中看见ROS的 NodeHandle如何使用。此外,我们也能简单地看到 “自动避障功能的实现”。 从C的角度,它实际上并不复杂&…...
机器学习的下一个前沿是因果关系吗?
如今,越来越多研究人员意识到,将因果关系融入机器学习,或许会是该领域实现重大突破的关键所在。 机器学习凭借先进的预测能力,已为诸多行业带来了显著变革,但也暴露出了一定的局限性。而因果关系,作为理解…...