当前位置: 首页 > news >正文

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

    • 一、TFLM是什么?
    • 二、TFLM开源项目
      • 2.1 下载TFLM源代码
      • 2.2 TFLM基准测试说明
      • 2.3 TFLM基准测试命令
    • 三、TFLM初步体验
      • 3.1 PC上运行Keyword基准测试
      • 3.2 PC上运行Person detection基准测试
      • 3.3 No module named 'numpy'问题解决
    • 四、TFLM源码浅析
      • 4.1 编译生成的.o文件
      • 4.2 基准测试的构建目标
      • 4.3 基准测试的构建规则
      • 4.4 TFLM库的构建规则
    • 五、TFLM主体移植
      • 5.1 实现TFLM库的构建
      • 5.2 实现辅助函数microlite_test
      • 5.3 实现keyword基准测试的构建
      • 5.4 实现Person detection基准测试的构建
      • 5.5 实现基准测试依赖的功能——计时和日志
    • 六、参考链接

本系列将介绍如何将TensorFlow Lite for Microcontrollers一直到STM32H7S78-DK上。由于整个过程较为繁琐,本系列将分为上下两篇进行介绍。本文为系列内容的上篇,主要分为TFLM是什么、TFLM初步体验、TFLM源码浅析、TFLM主体移植几个部分。其中,TFLM初步体验部分将会介绍如何在PC上运行TFLM基准测试,TFLM源码浅析部分主要介绍TFLM源码是如何进行构建的,TFLM主体移植主要介绍如何在基于CMake的STM32项目中构建TFLM库和基准测试。

一、TFLM是什么?

你或许都听说过TensorFlow——由谷歌开发并开源的一个机器学习库,它支持模型训练和模型推理。

今天介绍的TFLM,全称是TensorFlow Lite for Microcontrollers,翻译过来就是“针对微控制器的TensorFlow Lite”。那TensorFlow Lite又是什么呢?

TensorFlow Lite(通常简称TFLite)其实是TensorFlow团队为了将模型部署到移动设备而开发的一套解决方案,可以简单理解为TensorFlow的手机版。下面是TensorFlow官网上关于TFLite的一段介绍:

TensorFlow Lite 是一组工具,可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型,以便实现设备端机器学习。

而我们今天要介绍的TensorFlow Lite for Microcontrollers(TFLM)则是 TensorFlow Lite的微控制器版本。这里是官网上的一段介绍:

TensorFlow Lite for Microcontrollers (以下简称TFLM)是 TensorFlow Lite 的一个实验性移植版本,它适用于微控制器和其他一些仅有数千字节内存的设备。 它可以直接在“裸机”上运行,不需要操作系统支持、任何标准 C/C++ 库和动态内存分配。核心运行时(core runtime)在 Cortex M3 上运行时仅需 16KB,加上足以用来运行语音关键字检测模型的操作,也只需 22KB 的空间。

这三者一脉相承,都出自谷歌,区别是TensorFlow同时支持训练和推理,而后两者只支持推理。TFLite主要用于支持手机、平台等移动设备,TFLM则可以支持单片机。从发展历程上来说,后两者都可以说是TensorFlow项目的“支线项目”。或者说这三者是一个树形的发展过程,目前是三个并进发展的。

简单总结: TensorFlow Lite是 TensorFlow的移动版,少了训练功能,TensorFlow Lite for Microcontrollers 是 TensorFlow Lite 的MCU优化版。这三者,CPU推理的代码基本上完全一致,后两者也可以理解为TensorFlow 的裁剪版。

二、TFLM开源项目

TFLM代码仓链接:https://github.com/tensorflow/tflite-micro

2.1 下载TFLM源代码

下载TFLM需要使用如下git命令:

 git clone https://github.com/tensorflow/tflite-micro.git

TFLM顶层目录下的文件和目录,如下图所示:

image-20240915212410086

2.2 TFLM基准测试说明

TFLM顶层目录有README.md文件,其Additional Documentation节列出来Benchmark说明,Benchmark(基准测试)用于衡量关键模型和工作负载的性能。

README.md前一半内容为:

image-20240915212828124

完整内容参考: tflite-micro/tensorflow/lite/micro/benchmarks/README.md at main · tensorflow/tflite-micro (github.com)

2.3 TFLM基准测试命令

从README的”Run on x86”可以看到,在x86 PC上运行关键词基准测试的命令是:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

在x86 PC上运行人体检测基准测试的命令是:

make -f tensorflow/lite/micro/tools/make/Makefile run_person_detection_benchmark

以上两个命令都会调用make命令,并以tensorflow/lite/micro/tools/make/Makefile为构建规则,分别构建run_keyword_benchmarkrun_person_detection_benchmark两个目标。

查阅tensorflow/lite/micro/tools/make/Makefile文件夹内容,可以看到:

image-20240915213658373

这段代码中的 595行、601行、605行、612行、613行 分别会下载一些文件,具体下载的是tflm依赖的库和测试数据集;

而执行上面两个make命令,实际上会依次执行如下步骤:

  1. 下载依赖库和数据集;
  2. 编译测试程序;
  3. 运行测试程序;

必须至少一遍make命令,才会下载测试数据集,才能进行后续的移植步骤。

三、TFLM初步体验

由于TFLM开源项目依赖部分三方软件代码没有直接放在TFLM源码仓中,需要运行一次基准测试才会下载下拉进行编译。因此,我们需要先在PC上体验一下TFLM基准测试。

PC上运行TFLM推荐使用Ubuntu系统,其他操作系统运行可能会有些问题。

3.1 PC上运行Keyword基准测试

PC Linux系统上,运行如下命令,可以执行Keyword基准测试:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

命令执行完毕,最后输出如下:

image-20240915220542913

PC上运行10次耗时3毫秒。

3.2 PC上运行Person detection基准测试

make -f tensorflow/lite/micro/tools/make/Makefile run_person_detection_benchmark命令执行完毕,最后输出如下:

image-20240915220904048

image-20240915220841572

PC上运行10次,有人的耗时343毫秒,无人的耗时337毫秒。

3.3 No module named 'numpy’问题解决

make命令报错:

image-20240915214404249

解决方法:

pip install numpy

四、TFLM源码浅析

开始移植TFLM之前,需要清楚TFLM整个源码项目是如何构建的(也就是构建规则)。

4.1 编译生成的.o文件

PC上运行完基准测试命令过程中,会执行源码编译命令。运行完成后,使用如下命令,可以找到所有.o文件:

find . -name '*.o'

部分输出如下图所示:

image-20240918205828262

通过该命令的输出,我们可以知道刚刚的两个命令一共有多少源文件参与了编译。

4.2 基准测试的构建目标

要移植TFLM,仅仅知道有多少源文件参与编译还不够,我们需要知道具体的构建规则。本节将通过分析Makefile解读基准测试的具体构建目标(target)。

从前面的PC端运行Keyword基准测试的输出可以看到,可执行程序名称为keyword_benchmark,通过搜索源码,可以找到对应的Makefile构建规则代码为:

image-20240918213031151

这里调用了Makefile的宏函数microlite_test,并传递了4个参数,分别为:

  • 参数1:keyword_benchmark
  • 参数2:$(KEYWORD_BENCHMARK_SRCS)
  • 参数3:$(KEYWORD_BENCHMARK_HDRS)
  • 参数4:$(KEYWORD_BENCHMARK_GENERATOR_INPUTS)

4.3 基准测试的构建规则

下面以keyword_benchmark为例分析具体构建规则。

宏函数microlite_test的具体定义为:

image-20240918214047186

image-20240918215156216

前面我们执行了如下命令:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

这个命令指定的目标名称为run_keyword_benchmark,对应到helper_function.inc文件中的84行,参数1为keyword_benchmark,下方规则的TEST_SCRIPT变量的值定义在tensorflow/lite/micro/tools/make/Makefile文件中为空白字符串,因此不起作用;

84行还可以看到run_keyword_benchmark目标依赖$(keyword_benchmark_BINARY)目标,回看到52行,可以知道:

  • $(keyword_benchmark_BINARY)目标表示可执行程序文件路径,:

  • $(keyword_benchmark_BINARY)目标依赖$(keyword_benchmark_LOCAL_OBJS)目标;

  • $(keyword_benchmark_BINARY)目标依赖$(MICROLITE_LIB_PATH)目标;

  • $(keyword_benchmark_BINARY)目标的构建规则为:

    $$(CXX) $$(CXXFLAGS) $$(INCLUDES) \-o $$(keyword_benchmark_BINARY) $$(keyword_benchmark_LOCAL_OBJS) \$$(MICROLITE_LIB_PATH) $$(LDFLAGS) $$(MICROLITE_LIBS)
    

根据传参,可以知道,一些变量的值为:

  • keyword_benchmark_LOCAL_SRCS的初始值为: tensorflow/lite/micro/benchmarks/keyword_benchmark.cc

  • keyword_benchmark_LOCAL_HDRS的值为:tensorflow/lite/micro/benchmarks/micro_benchmark.h

  • 得到GEN_RESULTS的命令为: python3 tensorflow/lite/micro/tools/generate_cc_arrays.py gen/linux_x86_64_default_gcc/genfiles tensorflow/lite/micro/models/keyword_scrambled.tflite,该命令会将模型文件转为.h.cc文件,其中.h为声明,.cc为数据:

    #include <cstdint>constexpr unsigned int g_keyword_scrambled_model_data_size = 34576;
    extern const unsigned char g_keyword_scrambled_model_data[];
    

    命令的输出为:gen/linux_x86_64_default_gcc/genfiles/tensorflow/lite/micro/models/keyword_scrambled_model_data.cc

  • keyword_benchmark_LOCAL_SRCS值会变为包含刚刚生成的模型keyword_scrambled_model_data.cc

  • keyword_benchmark_LOCAL_OBJS的值是:先将keyword_benchmark_LOCAL_SRCS值中所有.cc替换为.o,再给每个值添加前缀gen/linux_x86_64_default_gccobj/core/

  • MICROLITE_LIB_PATH的值为库文件libtensorflow-microlite.a的完整路径: gen/linux_x86_64_default_gcc/lib/libtensorflow-microlite.a

好了,到这里就可以看到$(keyword_benchmark_BINARY)目标构建规则下方命令的主要参数了:

  • -o选项为gen/linux_x86_64_default_gcc/bin/keyword_benchmark

  • $(keyword_benchmark_LOCAL_OBJS)为所有目标文件(.o)列表;

  • $(MICROLITE_LIB_PATH)是链接的库文件(.a)路径;

  • $(LDFLAGS)是链接器命令行选项;

  • $(MICROLITE_LIBS)是额外库选项,实际为 -lm

    到这里,Keyword基准测试的构建规则以及分析清楚了。

4.4 TFLM库的构建规则

接下来,我们分析keyword链接的库文件libtensorflow-microlite.a(简称TFLM库)的链接规则。

该目标的定义为:

image-20240918223607739

这里可以看到,该库是由以下目标文件列表归档(使用ar命令)而来:

  • $(MICROLITE_LIB_OBJS)
  • $(MICROLITE_KERNEL_OBJS)
  • $(MICROLITE_THIRD_PARTY_OBJS)
  • $(MICROLITE_THIRD_PARTY_KERNEL_OBJS)
  • $(MICROLITE_CUSTOM_OP_OBJS)

其中,前四个变量的值来自:

image-20240918223939972

这里可以看到,前面的几个目标文件列表分别来自:

  • $(MICROLITE_LIB_OBJS)来自于$(MICROLITE_CC_SRCS)
  • $(MICROLITE_KERNEL_OBJS)来自于$(THIRD_PARTY_CC_SRCS)
  • $(MICROLITE_THIRD_PARTY_OBJS)来自于$(THIRD_PARTY_KERNEL_CC_SRCS)
  • $(MICROLITE_THIRD_PARTY_KERNEL_OBJS)来自于$(MICROLITE_CC_KERNEL_SRCS)
  • $(MICROLITE_CUSTOM_OP_OBJS)没有在Makefile中定义,默认为空,可以忽略(实际使用时,可以通过命令行参数指定);

经过在Makefile中加入日志打印,发现上述几个xxx_SRCS变量的值为:

image-20240919211922448

五、TFLM主体移植

从TFLM官方介绍文档、测试命令以及源码分析可以知道,在STM32H7S78-DK上移植TFLM可以分解为以下几个主要任务:

  • 实现TFLM库的构建
  • 实现CMake版的辅助函数microlite_test
  • 实现keyword基准测试的构建
  • 实现person detection基准测试(可选)的构建
  • 实现基准测试依赖的功能——计时和日志

接下来分别介绍,如何完成上述任务。

5.1 实现TFLM库的构建

有了以上分析之后,我们就可以进行今天最重要的工作,将Makefile转换为CMake构建规则文件(CMakeLists.txt)。

这部分是整个移植过程中工作量和难度最大的部分,涉及到很多CMake的语法细节,这里不详细介绍。

实现TFLM库构建的CMake代码为:

TFLM-libtflite-micro

5.2 实现辅助函数microlite_test

TFLM源码中,构建基准测试使用了GNU Make的microlite_test宏函数,实现了代码的复用和逻辑精简。和GNU Make类似的,CMake也支持函数。本节我们实现GNU Make的microlite_test宏函数的CMake移植版。

CMake具体代码如下:

TFLM-microlite_test

这部分做了几个特殊处理:

  • 目标类型从可执行程序修改为静态库,即生成文件类型由.elf文件改为.a文件;
  • 使用宏将main函数重命名为${NAME}_main

做出如上两处修改的原因是——由CubeMX生成的基础已经有main函数,并且可以生成elf文件。通过上述两个修改,我们可以将基准测试代码链接到CubeMX生成的代码中去,进而实现整个项目可以在STM32H7S78-DK上运行。

5.3 实现keyword基准测试的构建

有了CMake辅助函数microlite_test之后,实现keyword基准测试的构建就很简单了,直接看代码:

TFLM-keyword_benchmark

5.4 实现Person detection基准测试的构建

同样的,有了CMake辅助函数microlite_test之后,实现Person detection基准测试的构建也很简单,直接看代码:

TFLM-person_detection

5.5 实现基准测试依赖的功能——计时和日志

TFLM本身是一个边缘AI推理库,可以理解为一个举证向量计算库,纯CPU计算不依赖任何外设功能。但是,TFLM的基准测试则依赖计时和日志功能。在不同平台上,计时和日志功能的实现方式有所不同,对应的代码也不同(例如Linux、Windows、MacOS操作系统、STM32单片机、ESP32单片机上,实现计时和日志的代码是不是一样的)。

TFLM源码中,已经为移植进行了设计,其中两个文件名分别对应计时和日志:

  • debug_log.cc,用于实现计时功能,不同平台有不同版本;
  • micro_time.cc,用于实现计时功能,不同平台有不同版本;

默认的debug_log.cc实现为tensorflow/lite/micro/debug_log.cc,其主要代码内容为:

TFLM-debug_log_stderr

这里实现了——使用vfprintfstderr输出。借助过往经验,我们知道CubeMX生成的项目稍加修改就能够支持printf,这种方式应该也可以支持。

因此,对于STM32单片机这部分可以不用修改!

默认的micro_time.cc实现为tensorflow/lite/micro/micro_time.cc,其主要代码内容为:

TFLM-micro_time_ctime

这个文件里面提供了两种实现,通过TF_LITE_USE_CTIME宏进行切换:

  • 如果没定义TF_LITE_USE_CTIME宏,则为空实现,提供空壳函数,可以编译通过,无法正常计时;
  • 如果定义了TF_LITE_USE_CTIME宏,则为基于C标准库clock()CLOCKS_PER_SEC的计时;

对于STM32单片机,C标准库的clock()的计时不能直接使用。

因此,对于STM32单片机,需要单独实现一个micro_time.cc文件,具体代码为:

TFLM-micro_time_stm32_hal

到这里,TFLM移植的主体内容基本已经完成了,还有一些问题需要解决,我能将在下篇进行介绍,欢迎关注。

本篇内容到此为止,感谢阅读!

六、参考链接

  1. TensorFlow Lite for Microcontrollers介绍: TensorFlow Lite for Microcontrollers (google.cn)
  2. TensorFlow Lite for Microcontrollers入门: 微控制器入门 | TensorFlow (google.cn)
  3. tflite-micro 源码GitHub仓: https://github.com/tensorflow/tflite-micro
  4. CMake最新文档: CMake Reference Documentation — CMake 3.30.3 Documentation

相关文章:

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】 一、TFLM是什么&#xff1f;二、TFLM开源项目2.1 下载TFLM源代码2.2 TFLM基准测试说明2.3 TFLM基准测试命令 三、TFLM初步体验3.1 PC上运行Keyword基准测试3.2 PC上运行Person detection基准测试3.3 No module nam…...

第三方供应商不提供API接口?教你四步破解集成难题

API开放需求 在企业数字化转型过程中&#xff0c;异构系统之间的连接是信息化阶段不可或缺的一环。通过应用API&#xff0c;企业能够实现不同系统、平台和应用之间的数据交换与功能调用&#xff0c;从而形成端到端的业务流程协同。然而&#xff0c;很多企业在集成第三方供应商…...

WebAssembly 为什么能提升性能,怎么使用它 ?

文章目录 简介&#xff1a;起源&#xff1a;前端性能提升历史JIT&#xff08;Just-In-Time&#xff09;编译器(即时编译) 为什么需要WebAssembly&#xff1a;WebAssembly能做什么&#xff1a;经常说WASM的性能高&#xff0c;为什么高&#xff1f;&#xff1f;使用方法:Emscript…...

golang学习笔记13-函数(二):init函数,匿名函数,闭包,defer

注&#xff1a;本人已有C&#xff0c;C,Python基础&#xff0c;只写本人认为的重点。 这个知识点基本属于go的特性&#xff0c;比较重要&#xff0c;需要认真分析。 一、init函数 每个文件都可以定义init函数&#xff0c;它会在main函数执行前被调用&#xff0c;无论它的定义…...

HAproxy,nginx实现七层负载均衡

环境准备&#xff1a; 192.168.88.25 &#xff08;client&#xff09; 192.168.88.26 &#xff08;HAproxy&#xff09; 192.168.88.27 &#xff08;web1&#xff09; 192.168.88.28 (web2) 192.168.88.29 &#xff08;php1&#xff09; 192.168.88.30…...

ps aux | grep smart_webrtc这条指令代表什么意思

这条指令是在Linux系统中使用的命令&#xff0c;它的含义是列出所有正在运行的进程&#xff0c;并通过grep命令筛选出包含"smart_webrtc"关键字的进程。 具体解释如下&#xff1a; ps 是一个用于报告当前系统进程状态的命令。aux 是ps命令的选项&#xff0c;其中&a…...

第十三届蓝桥杯真题Python c组D.数位排序(持续更新)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;蓝桥杯关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 问题描述 小蓝对一个数的数位之和很感兴趣, 今天他要按照数位之和给数排序。…...

【RabbitMQ】RabbitMq消息丢失、重复消费以及消费顺序性的解决方案

RabbitMq消息丢失主要是有三种情况&#xff1a;生产者消息未发送到服务端、服务端消息没有做持久化导致丢失、消费端未收到消息。解决方案依次如下&#xff1a; 开启事务或使用确认机制。对于一些重要的消息&#xff0c;生产者可以开启事务&#xff0c;确保消息发送成功后再提…...

海陆钻井自动化作业机器人比例阀放大器

海陆钻井自动化作业机器人是现代海洋石油勘探与钻井领域的关键装备&#xff0c;它通过自动化和无人化技术显著提高了钻井效率和安全性。海陆钻井自动化作业机器人主要用于在海上和陆地的钻井平台上进行自动化、无人化的一体化作业。这种设备能够自动切换钻杆&#xff0c;极大地…...

golang学习笔记19-面向对象(一):面向对象的引入

注&#xff1a;本人已有C&#xff0c;C,Python基础&#xff0c;只写本人认为的重点。 这节开始就是面向对象的内容了&#xff0c;为方便复用结构体等类型&#xff0c;本人定义了一个utils包&#xff0c;用于定义这些类型&#xff0c;之后的文章也会用到&#xff0c;希望读者注意…...

【从零开始实现stm32无刷电机FOC】【实践】【7.1/7 硬件设计】

目录 stm32电路磁编码器电路电机驱动电路电流采样电路电机选择本文示例硬件说明 为了承载和验证本文的FOC代码工程&#xff0c;本节设计了一个简易的三相无刷电机 硬件套件&#xff0c;主控采用非常常用的stm32f103c8t6单片机&#xff0c;电机编码器采用MT6701&#xff0c;电机…...

unix中父进程如何获取子进程的终止状态

一、前言 本文将介绍在unix系统中&#xff0c;父进程如何获取子进程的终止状态。本文主要围绕如下函数展开&#xff1a; 1.wait 2.waitpid 3.waitid 4.wait3、wait4 在讨论这些函数前&#xff0c;先介绍一个进程从创建到释放子进程的过程。 二、子进程的创建以及终止 在unix…...

【ESP 保姆级教程】小课设篇 —— 案例:20240505_基于esp01s的局域网控制灯

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2024-09-30 ❤️❤️ 本篇更新记录 2023-09-30 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…...

Qt如何将外部窗口嵌入部件中

一、简述 今天给大家讲解的是使用QWindow类通过窗口句柄将外部的应用程序嵌入到我们的部件中来显示。在讲解之前可以延伸一下&#xff0c;当时项目中使用QProcess启动一些本地软件或者执行脚本时&#xff0c;需要将启动的第三方窗口嵌入到我们自己写的窗口中&#xff0c;此时我…...

2024年9月30日随笔

今天是国庆假期前的最后一天了&#xff0c;刚上完课&#xff0c;坐在实验室的工位前&#xff0c;感到焦虑又无奈&#xff0c;11月9号&#xff0c;网络规划工程师软考考试&#xff0c;学了一部分了&#xff0c;感觉有些难&#xff0c;还有一个月多一点点的时间&#xff0c;不知道…...

springboot+satoken实现刷新token(值变化)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 springbootsatoken实现刷新token satoken是什么&#xff1f;支持什么&#xff1f;为什么需要&…...

63.HDMI显示器驱动设计与验证-彩条实验

&#xff08;1&#xff09;常见的视频传输接口有三种&#xff1a; VGA 接口、 DVI 接口和 HDMI 接口&#xff0c;目前的显示设备都配有这三种视频传输接口。三类视频接口的发展历程为 VGA→DVI→HDMI。其中 VGA 接口出现最早&#xff0c;只能传输模拟图像信号&#xff1b; 随后…...

安卓13设置删除网络和互联网选项 android13隐藏设置删除网络和互联网选项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改4.1修改方法14.2修改方法25.编译6.彩蛋1.前言 有些客户不想让用户修改默认的网络配置,禁止用户进入里面调整网络相关的配置。 2.问题分析 像这个问题,我们有好几种方法去处理,这种需求一般…...

C++的6种构造函数

在 C 中&#xff0c;构造函数是一种特殊的成员函数&#xff0c;用于初始化类对象。在对象创建时自动调用&#xff0c;构造函数的主要作用是分配资源、初始化数据成员等。根据不同的功能和使用场景&#xff0c;C 提供了多种类型的构造函数&#xff1a; 1. 默认构造函数 (Defaul…...

【FE】NPM——概述

NPM基本使用 下载Node 老生常谈&#xff0c;选择LTS版本官网放这里&#xff1a;https://nodejs.cn/download/ 1.镜像配置&#xff1a;镜像源 镜像配置 依赖仓库&#xff1a;版本查看 //不确定仓库有哪些版本&#xff0c;列出指定包的所有版本 npm view <package-name&…...

Clipboard.js实现复制文本到剪贴板功能

一、Clipboard.js简介 Clipboard.js是一个轻量级的实现复制文本到剪贴板功能的JavaScript插件&#xff0c;该插件可以将输入框&#xff0c;文本域&#xff0c;DOM节点元素中的文本内容复制到剪贴板中。 官网地址&#xff1a;Clipboard.js 浏览器兼容性&#xff1a;兼容Chrome、…...

Harbor安装笔记

下载离线安装包 wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-offline-installer-v2.11.1.tgz 解压 tar -zxvf harbor-offline-installer-v2.11.1.tgz 复制一份配置文件出来&#xff0c;修改配置 cp harbor.yml.tmpl harbor.yml vim harbor…...

HTTP 1.0 2.0 3.0详解

HTTP HTTP全称超文本传输协议&#xff0c;是一种属于应用层的通信协议。它允许将超文本标记语言文档&#xff08;HTML&#xff09;从Web服务器传输到客户端的浏览器。 HTTP报文结构 请求报文结构 请求方法&#xff1a; GET&#xff1a;一般用来请求已被URI识别的资源&#x…...

Python操作TXT文本:从入门到精通

在数字化时代,文本处理成为了许多工作和项目的基础。Python作为一种强大且易学的编程语言,在文本处理方面展现出了无与伦比的优势。本文将通过举例的方式,向读者介绍如何使用Python来操作TXT文本,让您轻松掌握文本处理的精髓。 一、读取TXT文本内容 首先,我们需要学会如…...

开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序的数据运营策略与价值创造

一、引言 1.1 研究背景 在当今数字化时代&#xff0c;数据运营已成为企业发展的核心驱动力。开源 AI 智能名片 21 链动模式 S2B2C 商城小程序作为一种创新的营销工具&#xff0c;与数据运营紧密相连。该小程序通过集成人工智能、大数据分析等先进技术&#xff0c;能够实时收集…...

ip 地址查看cmd命令

ip 地址查看cmd命令 在不同的操作系统中&#xff0c;查看IP地址的命令可能会有所不同。以下是一些常见操作系统中查看IP地址的命令&#xff1a; Windows: 打开命令提示符&#xff08;CMD&#xff09;&#xff0c;然后输入 ipconfig 命令。 Linux/Unix: 打开终端&#xff0…...

力扣9.26

931. 下降路径最小和 给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列&#xff08;即…...

HT8731 内置自适应H类升压和防破音功能的10W D类及AB类音频功率放大器

1、特点 防削顶失真功能(防破音,Anti-Clipping Function, ACF) 免滤波器数字调制&#xff0c;直接驱动扬声器 输出功率 10W(VBAT4.2V,RL3Ω,THDN10%, fiN 1kHz) 6W(VBAT3.3~4.2V,RL4Ω,THDN<1%,20-20kHz 全频段) 3W (VBAT3.3~4.2V,RL8Ω, THDN<1%, 20- 20kHz 全频段 VB…...

webpack使用

一、简介 概述 本次使用webpack4进行构建打包 二、webpack 安装webpack、webpack-cli npm install webpack4.2.0 webpack-cli4.2.0 -D 三、loader 加载器概述 raw-loader&#xff1a;加载文件原始内容&#xff08;utf-8&#xff09; file-loader&#xff1a;把文件输出…...

高通Android 12 音量API设置相关代码

// 获取当前音量大小public static int getCurrentVolume(Context context) {AudioManager audioManager (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); // 使用 STREAM_MUSIC 作为示例…...

手机app软件开发/seo外链资源

python3正则要加括号&#xff01;&#xff01;&#xff01; 转载于&#xff1a;https://www.cnblogs.com/chuxiuhong/p/5885073.html 本文主要为没有使用正则表达式经验的新手入门所写。 转载请写明出处 引子 首先说 正则表达式是什么&#xff1f; 正则表达式&#xff0c;又…...

日本真人做爰无遮挡视频免费网站/关键词优化排名哪家好

我认为这是一套适合初学者由浅到深的文章&#xff0c;所以强烈推荐给大家&#xff0c;作者从基础讲到最近比较火的漏洞&#xff0c;可能有些人看来是浅了些&#xff0c;但是的确很适合想干点啥但又不知道怎么办的菜鸟们 。 第一节&#xff0c;伸展运动。这节操我们要准备道具&a…...

哪个网站名片做的号/网站seo方案

随机生成姓名 public function getChar($num2) // $num为生成汉字的数量{$first array(赵,钱,孙,李,周,吴,郑,王,冯,陈,褚,卫,蒋,沈,韩,杨,朱,秦,尤,许,何,吕,施,张,孔,曹,严,华,金,魏,陶,姜,戚,谢,邹,喻,柏,水,窦,章,云,苏,潘,葛,奚,范,彭,郎,鲁,韦,昌,马,苗,凤,花,方,任,袁…...

金陵热线 网站备案/站长交流平台

使用新浪SAE架构搭建自己的网站。将自己在本地编写的PHP程序上传到SAE上。如果要正常使用需要链接MySQL数据库(如果你的网站使用了MySQL数据库服务)。新浪SAE提供了对PHP访问MySQL的程序支持。所以这个过程要实现起来并不困难。只需要修改用户名和密码。创建完应用后&#xff0…...

网站建设价格请咨询兴田德润/怎么让关键词快速上首页

为什么80%的码农都做不了架构师&#xff1f;>>> 一、安装服务 本文以centos6.x系统为主在root用户或者具有root权限用户进行操作并且先改好主机名&#xff08;hostname&#xff09;&#xff0c;主要说明安装rabbitmq以及集群搭建关键性步骤. 1.准备工作去官方网站下…...

用自己的名字做网站域名/南昌关键词优化软件

记录今天遇到的一个小问题&#xff1a; AtomicInteger atomicInteger new AtomicInteger();System.out.println(atomicInteger.getAndIncrement()); 大家可以先猜想一下这个输出的是几&#xff0c;我之前一直以为是1&#xff0c;但是今天发现好像并不是。它是0。 public fina…...