HarmonyOS:Neural Network Runtime对接AI推理框架开发指导

场景介绍

Neural Network Runtime 作为 AI 推理引擎和加速芯片的桥梁,为 AI 推理引擎提供精简的 Native 接口,满足推理引擎通过加速芯片执行端到端推理的需求。

本文以图 1 展示的 Add 单算子模型为例,介绍 Neural Network Runtime 的开发流程。Add 算子包含两个输入、一个参数和一个输出,其中的 activation 参数用于指定 Add 算子中激活函数的类型。

图 1 Add 单算子网络示意图

环境准备

环境要求

Neural Network Runtime 部件的环境要求如下:

● 开发环境:Ubuntu 18.04 及以上。

● 接入设备:HarmonyOS 定义的标准设备,并且系统中内置的硬件加速器驱动,已通过 HDI 接口对接 Neural Network Runtime。

由于 Neural Network Runtime 通过 Native API 对外开放,需要通过 Native 开发套件编译 Neural Network Runtime 应用。

环境搭建

  1. 打开 Ubuntu 编译服务器的终端。
  2. 把下载好的 Native 开发套件压缩包拷贝至当前用户根目录下。
  3. 执行以下命令解压 Native 开发套件的压缩包。
unzip native-linux-{版本号}.zip

解压缩后的内容如下(随版本迭代,目录下的内容可能发生变化,请以最新版本的 Native API 为准):

native/
├── build // 交叉编译工具链
├── build-tools // 编译构建工具
├── docs
├── llvm
├── nativeapi_syscap_config.json
├── ndk_system_capability.json
├── NOTICE.txt
├── oh-uni-package.json
└── sysroot // Native API头文件和库

接口说明

这里给出 Neural Network Runtime 开发流程中通用的接口,具体请见下列表格。

结构体

模型构造相关接口

模型编译相关接口

执行推理相关接口

设备管理相关接口

开发步骤

Neural Network Runtime 的开发流程主要包含模型构造、模型编译和推理执行三个阶段。以下开发步骤以 Add 单算子模型为例,介绍调用 Neural Network Runtime 接口,开发应用的过程。

  1. 创建应用样例文件。

首先,创建 Neural Network Runtime 应用样例的源文件。在项目目录下执行以下命令,创建 nnrt_example/目录,在目录下创建 nnrt_example.cpp 源文件。

mkdir ~/nnrt_example && cd ~/nnrt_example
touch nnrt_example.cpp
  1. 导入 Neural Network Runtime。

在 nnrt_example.cpp 文件的开头添加以下代码,引入 Neural Network Runtime 模块。

#include <cstdint>
#include <iostream>
#include <vector>#include "neural_network_runtime/neural_network_runtime.h"// 常量,用于指定输入、输出数据的字节长度
const size_t DATA_LENGTH = 4 * 12;
  1. 构造模型。

使用 Neural Network Runtime 接口,构造 Add 单算子样例模型。

OH_NN_ReturnCode BuildModel(OH_NNModel** pModel)
{// 创建模型实例,进行模型构造OH_NNModel* model = OH_NNModel_Construct();if (model == nullptr) {std::cout << "Create model failed." << std::endl;return OH_NN_MEMORY_ERROR;}// 添加Add算子的第一个输入Tensor,类型为float32,张量形状为[1, 2, 2, 3]int32_t inputDims[4] = {1, 2, 2, 3};OH_NN_Tensor input1 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR};OH_NN_ReturnCode ret = OH_NNModel_AddTensor(model, &input1);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, add Tensor of first input failed." << std::endl;return ret;}// 添加Add算子的第二个输入Tensor,类型为float32,张量形状为[1, 2, 2, 3]OH_NN_Tensor input2 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR};ret = OH_NNModel_AddTensor(model, &input2);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, add Tensor of second input failed." << std::endl;return ret;}// 添加Add算子的参数Tensor,该参数Tensor用于指定激活函数的类型,Tensor的数据类型为int8。int32_t activationDims = 1;int8_t activationValue = OH_NN_FUSED_NONE;OH_NN_Tensor activation = {OH_NN_INT8, 1, &activationDims, nullptr, OH_NN_ADD_ACTIVATIONTYPE};ret = OH_NNModel_AddTensor(model, &activation);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, add Tensor of activation failed." << std::endl;return ret;}// 将激活函数类型设置为OH_NN_FUSED_NONE,表示该算子不添加激活函数。ret = OH_NNModel_SetTensorData(model, 2, &activationValue, sizeof(int8_t));if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, set value of activation failed." << std::endl;return ret;}// 设置Add算子的输出,类型为float32,张量形状为[1, 2, 2, 3]OH_NN_Tensor output = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR};ret = OH_NNModel_AddTensor(model, &output);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, add Tensor of output failed." << std::endl;return ret;}// 指定Add算子的输入、参数和输出索引uint32_t inputIndicesValues[2] = {0, 1};uint32_t paramIndicesValues = 2;uint32_t outputIndicesValues = 3;OH_NN_UInt32Array paramIndices = {&paramIndicesValues, 1};OH_NN_UInt32Array inputIndices = {inputIndicesValues, 2};OH_NN_UInt32Array outputIndices = {&outputIndicesValues, 1};// 向模型实例添加Add算子ret = OH_NNModel_AddOperation(model, OH_NN_OPS_ADD, &paramIndices, &inputIndices, &outputIndices);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, add operation failed." << std::endl;return ret;}// 设置模型实例的输入、输出索引ret = OH_NNModel_SpecifyInputsAndOutputs(model, &inputIndices, &outputIndices);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, specify inputs and outputs failed." << std::endl;return ret;}// 完成模型实例的构建ret = OH_NNModel_Finish(model);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed, error happened when finishing model construction." << std::endl;return ret;}*pModel = model;return OH_NN_SUCCESS;
}
  1. 查询 Neural Network Runtime 已经对接的加速芯片。

Neural Network Runtime 支持通过 HDI 接口,对接多种加速芯片。在执行模型编译前,需要查询当前设备下,Neural Network Runtime 已经对接的加速芯片。每个加速芯片对应唯一的 ID 值,在编译阶段需要通过设备 ID,指定模型编译的芯片。

void GetAvailableDevices(std::vector<size_t>& availableDevice)
{availableDevice.clear();// 获取可用的硬件IDconst size_t* devices = nullptr;uint32_t deviceCount = 0;OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&devices, &deviceCount);if (ret != OH_NN_SUCCESS) {std::cout << "GetAllDevicesID failed, get no available device." << std::endl;return;}for (uint32_t i = 0; i < deviceCount; i++) {availableDevice.emplace_back(devices[i]);}
}
  1. 在指定的设备上编译模型。

Neural Network Runtime 使用抽象的模型表达描述 AI 模型的拓扑结构,在加速芯片上执行前,需要通过 Neural Network Runtime 提供的编译模块,将抽象的模型表达下发至芯片驱动层,转换成可以直接推理计算的格式。

OH_NN_ReturnCode CreateCompilation(OH_NNModel* model, const std::vector<size_t>& availableDevice, OH_NNCompilation** pCompilation)
{// 创建编译实例,用于将模型传递至底层硬件编译OH_NNCompilation* compilation = OH_NNCompilation_Construct(model);if (compilation == nullptr) {std::cout << "CreateCompilation failed, error happened when creating compilation." << std::endl;return OH_NN_MEMORY_ERROR;}// 设置编译的硬件、缓存路径、性能模式、计算优先级、是否开启float16低精度计算等选项// 选择在第一个设备上编译模型OH_NN_ReturnCode ret = OH_NNCompilation_SetDevice(compilation, availableDevice[0]);if (ret != OH_NN_SUCCESS) {std::cout << "CreateCompilation failed, error happened when setting device." << std::endl;return ret;}// 将模型编译结果缓存在/data/local/tmp目录下,版本号指定为1ret = OH_NNCompilation_SetCache(compilation, "/data/local/tmp", 1);if (ret != OH_NN_SUCCESS) {std::cout << "CreateCompilation failed, error happened when setting cache path." << std::endl;return ret;}// 完成编译设置,进行模型编译ret = OH_NNCompilation_Build(compilation);if (ret != OH_NN_SUCCESS) {std::cout << "CreateCompilation failed, error happened when building compilation." << std::endl;return ret;}*pCompilation = compilation;return OH_NN_SUCCESS;
}
  1. 创建执行器。

完成模型编译后,需要调用 Neural Network Runtime 的执行模块,创建推理执行器。执行阶段,设置模型输入、获取模型输出和触发推理计算的操作均围绕执行器完成。

OH_NNExecutor* CreateExecutor(OH_NNCompilation* compilation)
{// 创建执行实例OH_NNExecutor* executor = OH_NNExecutor_Construct(compilation);return executor;
}
  1. 执行推理计算,并打印计算结果。

通过执行模块提供的接口,将推理计算所需要的输入数据传递给执行器,触发执行器完成一次推理计算,获取模型的推理计算结果。

OH_NN_ReturnCode Run(OH_NNExecutor* executor)
{// 构造示例数据float input1[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};float input2[12] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22};int32_t inputDims[4] = {1, 2, 2, 3};OH_NN_Tensor inputTensor1 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR};OH_NN_Tensor inputTensor2 = {OH_NN_FLOAT32, 4, inputDims, nullptr, OH_NN_TENSOR};// 设置执行的输入// 设置执行的第一个输入,输入数据由input1指定OH_NN_ReturnCode ret = OH_NNExecutor_SetInput(executor, 0, &inputTensor1, input1, DATA_LENGTH);if (ret != OH_NN_SUCCESS) {std::cout << "Run failed, error happened when setting first input." << std::endl;return ret;}// 设置执行的第二个输入,输入数据由input2指定ret = OH_NNExecutor_SetInput(executor, 1, &inputTensor2, input2, DATA_LENGTH);if (ret != OH_NN_SUCCESS) {std::cout << "Run failed, error happened when setting second input." << std::endl;return ret;}// 设置输出的数据缓冲区,OH_NNExecutor_Run执行计算后,输出结果将保留在output中float output[12];ret = OH_NNExecutor_SetOutput(executor, 0, output, DATA_LENGTH);if (ret != OH_NN_SUCCESS) {std::cout << "Run failed, error happened when setting output buffer." << std::endl;return ret;}// 执行计算ret = OH_NNExecutor_Run(executor);if (ret != OH_NN_SUCCESS) {std::cout << "Run failed, error doing execution." << std::endl;return ret;}// 打印输出结果for (uint32_t i = 0; i < 12; i++) {std::cout << "Output index: " << i << ", value is: " << output[i] << "." << std::endl;}return OH_NN_SUCCESS;
}
  1. 构建端到端模型构造-编译-执行流程。

步骤 3-步骤 7 实现了模型的模型构造、编译和执行流程,并封装成 4 个函数,便于模块化开发。以下示例代码将 4 个函数串联成完整的 Neural Network Runtime 开发流程。

int main()
{OH_NNModel* model = nullptr;OH_NNCompilation* compilation = nullptr;OH_NNExecutor* executor = nullptr;std::vector<size_t> availableDevices;// 模型构造阶段OH_NN_ReturnCode ret = BuildModel(&model);if (ret != OH_NN_SUCCESS) {std::cout << "BuildModel failed." << std::endl;OH_NNModel_Destroy(&model);return -1;}// 获取可执行的设备GetAvailableDevices(availableDevices);if (availableDevices.empty()) {std::cout << "No available device." << std::endl;OH_NNModel_Destroy(&model);return -1;}// 模型编译阶段ret = CreateCompilation(model, availableDevices, &compilation);if (ret != OH_NN_SUCCESS) {std::cout << "CreateCompilation failed." << std::endl;OH_NNModel_Destroy(&model);OH_NNCompilation_Destroy(&compilation);return -1;}// 创建模型的推理执行器executor = CreateExecutor(compilation);if (executor == nullptr) {std::cout << "CreateExecutor failed, no executor is created." << std::endl;OH_NNModel_Destroy(&model);OH_NNCompilation_Destroy(&compilation);return -1;}// 使用上一步创建的执行器,执行单步推理计算ret = Run(executor);if (ret != OH_NN_SUCCESS) {std::cout << "Run failed." << std::endl;OH_NNModel_Destroy(&model);OH_NNCompilation_Destroy(&compilation);OH_NNExecutor_Destroy(&executor);return -1;}// 释放申请的资源OH_NNModel_Destroy(&model);OH_NNCompilation_Destroy(&compilation);OH_NNExecutor_Destroy(&executor);return 0;
}

调测验证

  1. 准备应用样例的编译配置文件。

新建一个 CMakeLists.txt 文件,为开发步骤中的应用样例文件 nnrt_example.cpp 添加编译配置。以下提供简单的 CMakeLists.txt 示例:

cmake_minimum_required(VERSION 3.16)
project(nnrt_example C CXX)add_executable(nnrt_example./nnrt_example.cpp
)target_link_libraries(nnrt_exampleneural_network_runtime.z
)
  1. 编译应用样例。

执行以下命令,在当前目录下新建 build/目录,在 build/目录下编译 nnrt_example.cpp,得到二进制文件 nnrt_example。

mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE={交叉编译工具链的路径}/build/cmake/ohos.toolchain.cmake -DOHOS_ARCH=arm64-v8a -DOHOS_PLATFORM=OHOS -DOHOS_STL=c++_static ..
make
  1. 执行以下代码,将样例推送到设备上执行。
# 将编译得到的 `nnrt_example` 推送到设备上,执行样例。
hdc_std file send ./nnrt_example /data/local/tmp/.# 给测试用例可执行文件加上权限。
hdc_std shell "chmod +x /data/local/tmp/nnrt_example"# 执行测试用例
hdc_std shell "/data/local/tmp/nnrt_example"

如果样例执行正常,应该得到以下输出。

Output index: 0, value is: 11.000000.
Output index: 1, value is: 13.000000.
Output index: 2, value is: 15.000000.
Output index: 3, value is: 17.000000.
Output index: 4, value is: 19.000000.
Output index: 5, value is: 21.000000.
Output index: 6, value is: 23.000000.
Output index: 7, value is: 25.000000.
Output index: 8, value is: 27.000000.
Output index: 9, value is: 29.000000.
Output index: 10, value is: 31.000000.
Output index: 11, value is: 33.000000.
  1. 检查模型缓存(可选)。

如果在调测环境下,Neural Network Runtime 对接的 HDI 服务支持模型缓存功能,执行完 nnrt_example, 可以在 /data/local/tmp 目录下找到生成的缓存文件。

说明

模型的 IR 需要传递到硬件驱动层,由 HDI 服务将统一的 IR 图,编译成硬件专用的计算图,编译的过程非常耗时。Neural Network Runtime 支持计算图缓存的特性,可以将 HDI 服务编译生成的计算图,缓存到设备存储中。当下一次在同一个加速芯片上编译同一个模型时,通过指定缓存的路径,Neural Network Runtime 可以直接加载缓存文件中的计算图,减少编译消耗的时间。

检查缓存目录下的缓存文件:

ls /data/local/tmp

以下为打印结果:

# 0.nncache  cache_info.nncache

如果缓存不再使用,需要手动删除缓存,可以参考以下命令,删除缓存文件。

rm /data/local/tmp/*nncache

为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙 (Harmony OS)开发学习手册》

入门必看:https://qr21.cn/FV7h05

  1. 应用开发导读(ArkTS)
  2. 应用开发导读(Java)

HarmonyOS 概念:https://qr21.cn/FV7h05

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. 构建第一个JS应用
  4. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

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

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

相关文章

轻量封装WebGPU渲染系统示例<50>- Json数据描述材质等3D渲染场景信息

本示例中的3d渲染场景由Json数据来描述。 包含3个主要部分: 1. Json描述渲染器的基本信息。 2. Json描述渲染场景的环境信息,包括全局的灯光、阴影、雾等。 3. Json描述构成场景的各个可选人实体&#xff0c;包括几何信息、transform、材质、渲染状态等。 当前示例源码git…

开启创意之旅:免费、开源的噪波贴图(noise texture)生成网站——noisecreater.com详细介绍

在当今数字创意领域&#xff0c;噪波贴图&#xff08;Noise Texture&#xff09;是游戏渲染、游戏开发、美术设计以及影视制作等行业不可或缺的艺术素材之一。为了满足广大创作者的需求&#xff0c;noisecreater.com应运而生&#xff0c;成为一款免费、开源的噪波贴图生成工具。…

保护IP地址免受盗用的有效方法

IP地址是互联网通信的基础&#xff0c;然而&#xff0c;由于其重要性&#xff0c;IP地址的盗用成为一种潜在的网络威胁。本文将深入探讨防止IP地址被盗用的方法&#xff0c;以维护网络的安全性。 第一部分&#xff1a;IP地址盗用的威胁与风险 1.1 IP地址盗用的定义 IP地址盗…

数据可视化---离群值展示

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

操作系统系列:Unix进程系统调用fork,wait,exec

操作系统系列&#xff1a;Unix进程系统调用 fork系统调用fork()运用的小练习 wait系统调用Zombiesexec 系列系统调用 开发者可以查看创建新进程的系统调用&#xff0c;这个模块会讨论与进程相关的Unix系统调用&#xff0c;下一个模块会讨论Win32 APIs相关的进程。 fork系统调用…

java参数校验

引入依赖 <!--参数效验--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!--Length参数效验--><dependency><groupId>org.hib…

【python基础】-- yarn add 添加依赖的各种类型

目录 1、安装 yarn 1.1 使用npm安装 1.2 查看版本 1.3 yarn 淘宝源配置 2、安装命令说明 2.1 yarn add&#xff08;会更新package.json和yarn.lock&#xff09; 2.2 yarn install 2.3 一些操作 2.3.1 发布包 2.3.2 移除一个包 2.3.3 更新一个依赖 2.3.4 运行脚本 …

【设计模式--行为型--备忘录模式】

设计模式--行为型--备忘录模式 备忘录模式定义结构案例实现白箱备忘录模式黑箱备忘录模式 优缺点使用场景 备忘录模式 定义 又叫快照模式&#xff0c;在不破坏封装性的前提下&#xff0c;捕获一个对象的对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便…

Java 自定义注解

Java 自定义注解&#xff0c; 以及interface Target Retention Around Before After ProceedingJoinPoint JoinPoint 等用法 注解应用非常广泛&#xff0c;我们自定义注解能简化开发各种各种业务 一、关键字解释 (1) 定义注解时&#xff0c;关键字 interface 来表示注解类的类…

Spring Boot学习随笔- 实现AOP(JoinPoint、ProceedingJoinPoint、自定义注解类实现切面)

学习视频&#xff1a;【编程不良人】2021年SpringBoot最新最全教程 第十一章、AOP 11.1 为什么要使用AOP 问题 现有业务层开发存在问题 额外功能代码存在大量冗余每个方法都需要书写一遍额外功能代码不利于项目维护 Spring中的AOP AOP&#xff1a;Aspect 切面 Oriented 面向…

竞赛保研 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

【Python 基础】-- 在 mac OS 中安装 多个 python 版本

目录 1、需求 2、实现 2.1 安装 pyenv 2.2 安装 pyenv-virtualenv 2.3 配置环境变量 2.4 创建 python 3.9.9 的环境 2.5 激活环境&#xff0c;在当前项目目录中使用&#xff0c;即执行 python 1、需求 由于项目所依赖的 python 版本有多个&#xff0c;需要在不同的 pyth…

主从reactor多线程实现

现场模型图片&#xff0c;从网上找的 出于学习的目的实现的&#xff0c;如有不对的地方欢迎留言知道&#xff0c;简单实现了http的请求&#xff0c;可通过postman进行访问 启动项目&#xff1a; 返回数据示例 postman请求 附上源码&#xff0c;有问题直接看源码吧

智能优化算法应用:基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于闪电连接过程算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.闪电连接过程算法4.实验参数设定…

Flink实时电商数仓(二)

GitLab的用户创建和推送 在root用户-密码界面重新设置密码添加Leader用户和自己使用的用户使用root用户创建相应的群组使用Leader用户创建对应的项目设置分支配置为“初始推送后完全保护”设置.gitignore文件&#xff0c;项目配置文件等其他非通用代码无需提交安装gitlab proj…

(JAVA)-创建多线程的方式

1.继承Thread类 1.创建一个继承字Thread类的子类 2.重写Thread类的run方法 public class MyThread extends Thread{Overridepublic void run() {for (int i 0; i < 100; i) {System.out.println(getName()"hello");}} }3.创建Thread类的子类对象 4.通过子类对象调…

HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】

一.HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】 1.1 项目背景 HarmonyOS(鸿蒙操作系统)是华为公司推出的一种分布式操作系统。它被设计为一种全场景、全连接的操作系统,旨在实现在各种设备之间的无缝协同和共享,包括智能手机、平板电脑、智能…

轻量级购物小程序H5产品设计经典样例

主要是看到这个产品设计的不错值得借鉴特记录如下&#xff1a; 不过大多数购物app都大致相同&#xff0c;这个算是经典样例&#xff0c;几乎都可以复制&#xff0c;我第一次使用&#xff0c;感觉和顺畅。看上去产品是经过打磨的&#xff0c;布局非常好。内容也很丰富。支持异业…

Leetcode—128.最长连续序列【中等】

2023每日刷题&#xff08;六十四&#xff09; Leetcode—128.最长连续序列 实现代码 class Solution { public:int longestConsecutive(vector<int>& nums) {unordered_set<int> s;for(auto num: nums) {s.insert(num);}int longestNum 0;for(auto num: s) …

LeetCode day27

LeetCode day27 —今天做到树&#xff0c;&#xff0c;&#xff0c;对不起我的数据结构老师啊~~~ 7. 整数反转 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] &#xff0c…