OpenHarmony AI框架开发指导

news2024/11/25 13:47:08

一、概述

1、功能简介

AI 业务子系统是 OpenHarmony 提供原生的分布式 AI 能力的子系统。AI 业务子系统提供了统一的 AI 引擎框架,实现算法能力快速插件化集成。

AI 引擎框架主要包含插件管理、模块管理和通信管理模块,完成对 AI 算法能力的生命周期管理和按需部署。插件管理主要实现插件的生命周期管理及插件的按需部署,快速集成 AI 能力插件;模块管理主要实现任务的调度及管理客户端的实例;通信管理主要实现客户端和服务端之间的跨进程通信管理及 AI 服务与插件之间的数据传输。后续,会逐步定义统一的 AI 能力接口,便于 AI 能力的分布式调用。同时,框架提供适配不同推理框架层级的统一推理接口。

AI 引擎框架结构如下图所示。

图 1 AI 引擎框架

2、搭建环境

  1. 准备开发板:Hi3516DV300 或 Hi3518EV300

  2. 下载源码

二、技术规范

1、代码管理规范

AI 引擎框架包含 client、server 和 common 三个主要模块,其中 client 提供 server 端连接管理功能,OpenHarmony SDK 在算法对外接口中需封装调用 client 提供的公共接口;server 提供插件加载以及任务管理等功能,各 Plugin 实现由 server 提供的插件接口,完成插件接入;common 提供与平台相关的操作方法、引擎协议以及相关工具类,供其他各模块调用。AI 引擎框架各模块之间的代码依赖关系如下图所示:

图 2 AI 引擎代码依赖关系

建议:插件与 OpenHarmony SDK 在 AI 引擎指定的路径下进行代码开发

在 AI 引擎框架的整体规划中,OpenHarmony SDK 属于 client 端的一部分,插件由 server 端调用,属于 server 端的一部分,因此 AI 引擎框架为接入的插件与 OpenHarmony SDK 规划的路径:

SDK 代码路径://foundation/ai/engine/services/client/algorithm_sdk 示例 1://foundation/ai/engine/services/client/algorithm_sdk/cv 示例 2://foundation/ai/engine/services/client/algorithm_sdk/nlu

插件代码路径://foundation/ai/engine/services/server/plugin 示例 1://foundation/ai/engine/services/server/plugin/cv 示例 2://foundation/ai/engine/services/server/plugin/nlu

规则:插件提供的全部对外接口,统一存放在 AI 业务子系统 interfaces/kits 目录

OpenHarmony SDK 对外接口是 AI 业务子系统提供能力的对外暴露方式,按照 OpenHarmony 的接口管理要求,需统一存放在各子系统的 interfaces/kits 目录中。当前 AI 业务子系统插件对外接口路径为//foundation/ai/engine/interfaces/kits,不同插件可在该路径下添加目录,比如增加 cv 插件,则在路径//foundation/ai/engine/interfaces/kits/cv 下面存放接口文件。

规则:插件编译输出路径必须是在/usr/lib

server 端加载插件是采用 dlopen 方式,只支持在/usr/lib 路径进行,因此插件在编译 so 时,需要在编译配置文件中指定输出路径为/usr/lib。

2、命名规范

SDK 命名规则:领域_关键词<其他信息 1_其他信息 2…>_sdk.so

关于领域,建议使用当前主流简称,比如图片视频相关的使用"cv",语音识别相关的使用“asr”,翻译相关的使用“translation”等,存在其他领域的可增加定义;关键词则需要恰当准确的描述所对应插件的算法能力,比如唤醒词识别,则使用 keyword_spotting;对于其他信息,比如插件支持的芯片类型、国内海外等信息,可在关键词与“sdk”之间依次添加,信息之间以下划线连接;SDK 命名,必须以“_sdk”结尾。

例如:唤醒词识别插件对应的 SDK,只支持麒麟 9000 芯片,适用于中国国内地区适用,则对应的 SDK 命名为:asr_keyword_spotting_kirin9000_china_sdk.so

插件命名规则:领域_关键词<其他信息 1_其他信息 2…>.so

插件与 SDK 存在一一对应的关系,故插件命名的领域、关键词、其他信息等名词解释与要求,均与 SDK 命名要求保持一致。两者唯一的不同之处在于 SDK 命名多了个“_sdk”结尾;比如插件命名为“asr_keyword_spotting.so”,则对应 SDK 命名为“asr_keyword_spotting_sdk.so”。

例如:唤醒词识别插件对应的 SDK,只支持麒麟 9000 芯片,适用于中国国内地区适用,则对应的插件命名为:asr_keyword_spotting_kirin9000_china.so

3、 接口开发规范

规则:SDK 需按算法调用顺序,封装 client 对外提供接口;对于异步插件对应的 SDK,需要实现 client 提供的回调接口 IClientCb

AI 引擎的 client 端对外提供的接口包括 AieClientInit、AieClientPrepare、AieClientSyncProcess、AieClientAsyncProcess、AieClientRelease、AieClientDestroy、AieClientSetOption、AieClientGetOption,SDK 需要根据插件的接口按照顺序至少封装 AieClientInit、AieClientPrepare、AieClientSyncProcess/AieClientAsyncProcess、AieClientRelease、AieClientDestroy 五个接口,否则会出现调用问题或者内存泄漏。比如封装过程遗漏了 AieClientPrepare 接口,则 server 端无法完成插件加载,故后面的接口都无法调用成功。

对于异步插件,SDK 需要实现 IClientCb 接口,用于接收来自 client 端的算法推理结果,并将该结果返回给三方调用者。

规则:SDK 接口实现中,需要保存与 client 交互的相关通用数据

AI 引擎将的 client 端采用单例实现,对接多个 SDK,因此各 SDK 需要保存与 client 交互的通用数据,用于连接 server 端进行任务推理、结果返回等;需保存数据包含 clientInfo、algorithmInfo、configInfo 三种数据类型,定义在 SDK 的成员变量里即可。

建议:SDK 实现 client 定义的 IServiceDeadCb 接口

Server 端是系统常驻进程,以系统能力的形式为多个 client 提供服务;client 定义的 IServiceDeadCb 接口,是在 server 端异常死亡后,会被触发调用。这种异常场景,SDK 可在死亡通知接口中,实现相关操作,比如停止调用或者再次拉起 server 端等。

IServiceDeadCb 接口实现示例:

class ServiceDeadCb : public IServiceDeadCb {public:ServiceDeadCb() = default;~ServiceDeadCb() override = default;void OnServiceDead() override{printf("[ServiceDeadCb]OnServiceDead Callback happens");}};

如上示例,SDK 可在 OnServiceDead()方法中实现自己的操作,比如停止所有的接口调用等等。

规则:SDK 与 plugin 需要使用编解码模块,将特定算法数据转换成 AI 引擎的通用数据类型

插件的推理数据,会由三方调用者通过 client、server 传递到插件中;不同的算法所需要的数据类型是不一致的,比如 cv 的需要图片数据、asr 的需要语音数据;为了适配数据类型的差异,AI 引擎对外提供了对基本数据类型的编解码能力,将不同数据类型转换为 AI 引擎可以使用的通用数据类型。

编码后的数据类型定义:

struct DataInfo {unsigned char *data;int length;} DataInfo;

如上示例,DataInfo 数据结构包括指向数据内存的指针和数据长度两个变量组成。

框架接口使用方法:

1.添加依赖的头文件:"utils/encdec/include/encdec.h"。

2.添加 build.gn 中的依赖项:

include_dirs 添加"//foundation/ai/engine/services/common"。

deps 添加"//foundation/ai/engine/services/common/utils/encdec:encdec" 。

3.编解码示例:

// 编码调用函数示例:arg1,arg2,arg3等为需编码的变量,dataInfo为编码后的结果retCode = ProcessEncode(dataInfo, arg1, arg2, arg3) //可以接收任意多个参数// 解码调用函数示例:dataInfo为需要解码的信息,arg1,arg2,arg3等为解码后的结果retCode = ProcessDecode(dataInfo, arg1, arg2, arg3) //可以接收任意多个参数

注意:

●编码和解码调用时的参数顺序需要保证一致。

● 编码后 dataInfo 的内存需要调用者手动进行释放。

● server 端和 client 端的内存是分开管理和释放的。

●如果包含共享内存的指针,不需要额外处理。

●如果其他类型的指针,则需要解引用后使用 ProcessEncode/ ProcessDecode。

● 该编解码模块未适配 class 数据类型,不建议使用。

规则:在 SDK 中,对以编解码返回的出参数据类型,需要进行内存释放,否则会出现内存泄漏

编码得到的通用数据,本质上是将不同类型数据封装在同一块内存中,然后将这块内存的首地址与长度封装到结构体中。通过编码返回到 SDK 中的出参数据,在插件中申请了内存,但插件无法释放;因此 SDK 在拿到数据之后,需要对内存进行释放,否则 SDK 将无法拿到数据。

内存释放示例:

DataInfo outputInfo = {.data = nullptr,.length = 0,};AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr);if (outputInfo.data != nullptr) {free(outputInfo.data);outputInfo.data = nullptr;outputInfo.length = 0;}

规则:plugin 需要实现 server 定义的 IPlugin 接口,并使用宏 PLUGIN_INTERFACE_IMPL 对外提供插件函数指针

Server 端管理的插件内部接口实现逻辑各不相同,为了统一插件的加载流程,AI 引擎定义了插件接口 IPlugin;在运行态,插件是以动态链接库的形式被 AI 引擎框架通过 dlopen 方式加载,各插件需要使用 PLUGIN_INTERFACE_IMPL 语句对外暴露函数指针,否则插件将无法被正常加载使用。

规则:plugin 需要使用 AI 引擎提供的统一数据通道

AI 引擎在 server 与插件之间,提供了一个统一的数据通道,用来处理来自 SDK 的推理请求和来自插件的结果返回;plugin 在推理接口中,需按数据通道完成请求数据的获取以及推理结果的封装。

数据通道使用示例:

int SyncProcess(IRequest *request, IResponse *&response){HILOGI("[IvpPlugin]Begin SyncProcess");if (request == nullptr) {HILOGE("[IvpPlugin]SyncProcess request is nullptr");return RETCODE_NULL_PARAM;}DataInfo inputInfo = request->GetMsg();if (inputInfo.data == nullptr) {HILOGE("[IvpPlugin]InputInfo data is nullptr");return RETCODE_NULL_PARAM;}
...
response = IResponse::Create(request);response->SetResult(outputInfo);return RETCODE_SUCCESS;}

示例中 request 和 response 是数据通道的内容主体。server 端会将数据封装在 request 中,传递到插件,插件进行算法处理之后,则需要将结果封装成 response 进行返回。

三、开发指导

1、开发 SDK

SDK 头文件的功能实现是基于对 SDK 的调用映射到对客户端的调用。Client 端提供的接口如下表所示。

表 1 Client 端提供的接口

其中,ConfigInfo,ClientInfo,AlgorithmInfo,DataInfo 的数据结构如下表所示。

表 2 ConfigInfo,ClientInfo,AlgorithmInfo,DataInfo 的数据结构

具体开发过程可参考唤醒词识别 SDK 开发示例

2、开发插件

AI 引擎框架规定了一套算法插件接入规范,各插件需实现规定接口以实现获取插件版本信息、算法推理类型、同步执行算法、异步执行算法、加载算法插件、卸载算法插件、设置算法配置信息、获取指定算法配置信息等功能。(同步算法实现 SyncProcess 接口,异步算法实现 AsyncProcess 接口)。

算法插件类 IPlugin 接口设计如下表所示。

表 3 算法插件类 IPlugin 接口设计

算法插件类接口:

Prepare、SyncProcess、AsyncProcess、Release、SetOption、GetOption 分别于客户端接口 AieClientPrepare、AieClientSyncProcess、AieClientAsyncProcess、AieClientRelease、AieClientSetOption、AieClientGetOption 一一对应;GetInferMode 接口用于返回算法执行类型——同步或异步。

算法插件回调类 IPluginCallback 接口设计如下表所示。

表 4 算法插件回调类 IPluginCallback 接口设计

Request、Response 是 AI 引擎服务端与算法插件进行通信的对象。Request 封装了调用方的请求、输入数据等,而插件主要通过 Response 将运算之后的结果返回给 AI 引擎服务端。

Request 类的属性如下表所示。

表 5 Request 类的属性

Response 类的属性如下表所示。

表 6 Response 类的属性

具体开发过程可参考唤醒词识别插件开发示例

3、开发配置文件

开发者开发的 SDK 通过 AlgorithmInfo 结构体中 algorithmVersion 以及 algorithmType 识别出具体的插件类型,实现插件能力的调用。因此开发者需完成以下步骤:

  1. 代码路径//foundation/ai/engine/services/common/protocol/plugin_config/plugin_config_ini/中添加插件的配置文件。

  2. 代码路径//foundation/ai/engine/services/common/protocol/plugin_config/中的 aie_algorithm_type.h 文件添加算法类型。

  3. 代码路径//foundation/ai/engine/services/server/plugin_manager/include/中的 aie_plugin_info.h 文件添加唤醒词识别的算法名称及其在 ALGORITHM_TYPE_ID_LIST 中的序号。

具体开发过程可参考唤醒词识别配置文件开发示例

四、开发实例

1、唤醒词识别 SDK 的开发示例

  1. 在//foundation/ai/engine /interfaces/kits 目录中添加唤醒词识别 SDK 的 API 接口定义,该接口可用三方应用进行调用。如下代码片段即为唤醒词识别定义的 API 接口示例,其相关代码参考路径为://foundation/ai/engine/interfaces/kits/asr/keyword_spotting。

class KWSSdk {public:    KWSSdk();    virtual ~KWSSdk();
    // 定义创建唤醒词检测工具包的方法    int32_t Create();
    // 定义同步执行唤醒词检测任务的方法    int32_t SyncExecute(const Array<int16_t> &audioInput);
    // 定义设置唤醒词检测回调器的方法。    int32_t SetCallback(const std::shared_ptr<KWSCallback> &callback);
    // 定义销毁唤醒词工具包的方法,释放与插件的会话信息    int32_t Destroy();};

2.在//foundation/ai/engine/services/client/algorithm_sdk 目录中增加 SDK 中 API 接口的具体实现,调用 client 端提供的接口,实现算法插件能力的使用。如下代码片段即为唤醒词识别的 API 接口中 create 方法的具体实现示例,更多详细代码请参考://foundation/ai/engine/services/client/algorithm_sdk/asr/keyword_spotting。

int32_t KWSSdk::KWSSdkImpl::Create(){    if (kwsHandle_ != INVALID_KWS_HANDLE) {        HILOGE("[KWSSdkImpl]The SDK has been created");        return KWS_RETCODE_FAILURE;    }    if (InitComponents() != RETCODE_SUCCESS) {        HILOGE("[KWSSdkImpl]Fail to init sdk components");        return KWS_RETCODE_FAILURE;    }    // 调用client端提供的AieClientInit接口,实现初始化引擎服务,激活跨进程调用    int32_t retCode = AieClientInit(configInfo_, clientInfo_, algorithmInfo_, nullptr);    if (retCode != RETCODE_SUCCESS) {        HILOGE("[KWSSdkImpl]AieClientInit failed. Error code[%d]", retCode);        return KWS_RETCODE_FAILURE;    }    if (clientInfo_.clientId == INVALID_CLIENT_ID) {        HILOGE("[KWSSdkImpl]Fail to allocate client id");        return KWS_RETCODE_FAILURE;    }    DataInfo inputInfo = {        .data = nullptr,        .length = 0,    };    DataInfo outputInfo = {        .data = nullptr,        .length = 0,    };    // 调用client端提供的AieClientPrepare接口,实现加载算法插件    retCode = AieClientPrepare(clientInfo_, algorithmInfo_, inputInfo, outputInfo, nullptr);    if (retCode != RETCODE_SUCCESS) {        HILOGE("[KWSSdkImpl]AieclientPrepare failed. Error code[%d]", retCode);        return KWS_RETCODE_FAILURE;    }    if (outputInfo.data == nullptr || outputInfo.length <= 0) {        HILOGE("[KWSSdkImpl]The data or length of output info is invalid");        return KWS_RETCODE_FAILURE;    }    MallocPointerGuard<unsigned char> pointerGuard(outputInfo.data);    retCode = PluginHelper::UnSerializeHandle(outputInfo, kwsHandle_);    if (retCode != RETCODE_SUCCESS) {        HILOGE("[KWSSdkImpl]Get handle from inputInfo failed");        return KWS_RETCODE_FAILURE;    }    return KWS_RETCODE_SUCCESS;}

上述代码为 API 接口的具体实现。在示例代码中,SDK 中 create 接口的具体实现即为上述示例代码中 create 方法,该方法调用了 AI 引擎框架 client 端提供的 AieClientInit 及 AieClientPrepare 接口,从而实现与 server 端建立连接及加载算法模型的能力。

说明:SDK 调用 AI 引擎 client 端接口应遵循 AieClientInit->AieClientPrepare->AieClientSyncProcess/AieClientAsyncProcess->AieClientRelease->AieClientDestroy 顺序,否则调用接口会返回错误码。

2、唤醒词识别插件的开发示例

在代码路径//foundation/ai/engine/services/server/plugin 中添加唤醒词识别插件的接口定义(IPlugin),并实现 AI 能力的调用。如下代码片段即实现唤醒词识别的算法插件的接口定义。更多插件开发的相关代码参考路径如下://foundation/ai/engine/services/server/plugin/asr/keyword_spotting

#include "plugin/i_plugin.hclass KWSPlugin : public IPlugin {public:    KWSPlugin();    ~KWSPlugin();    const long long GetVersion() const override;    const char* GetName() const override;    const char* GetInferMode() const override;    int32_t Prepare(long long transactionId, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;    int32_t SetOption(int optionType, const DataInfo &amp;amp;inputInfo) override;    int32_t GetOption(int optionType, const DataInfo &amp;amp;inputInfo, DataInfo &amp;amp;outputInfo) override;    int32_t SyncProcess(IRequest *request, IResponse *&amp;amp;response) override;    int32_t AsyncProcess(IRequest *request, IPluginCallback*callback) override;    int32_t Release(bool isFullUnload, long long transactionId, const DataInfo &amp;amp;inputInfo) override;};

上述代码实现 server 提供的 IPlugin 接口。唤醒词识别的 sample 中调用的 client 端接口与插件中的接口对应关系及其实现功能如下表所示。

表 7 唤醒词识别中 client 端接口与插件中的接口对应关系

注意:

1.接口 AieClientInit、AieClientDestroy 分别用于与 server 端建立和断开连接,未调用到插件算法中,因此插件中无需定义与之对应的接口。

2.唤醒词识别插件需要使用 PLUGIN_INTERFACE_IMPL 语句对外暴露函数指针,否则插件将无法被正常加载使用。

PLUGIN_INTERFACE_IMPL(KWSPlugin);

3、唤醒词识别配置文件的开发示例

  1. 在代码路径//foundation/ai/engine/services/common/protocol/plugin_config/plugin_config_ini/中添加唤醒词识别的配置文件。

[base]supported_boards = hi3516dv300related_sessions = asr_keyword_spotting+20001002
//[asr_keyword_spotting+20001002]的命名规则为[算法名称+算法version][asr_keyword_spotting+20001002]AID         = asr_keyword_spottingVersionCode = 20001002VersionName = 2.00.01.002XPU         = NNIEDistrict    = China// 编译出的插件so文件所在的位置FullPath    = /usr/lib/libasr_keyword_spotting.soChipset     = ALLChkSum      = ''Key         = ''

  1. 在代码路径//foundation/ai/engine/services/common/protocol/plugin_config/中的 aie_algorithm_type.h 文件添加唤醒词识别算法类型 id。

// 唤醒词识别的算法类型id与唤醒词识别在ALGORITHM_TYPE_ID_LIST中的序号一一对应const int ALGORITHM_TYPE_KWS = 3;

3.在代码路径//foundation/ai/engine/services/server/plugin_manager/include/中的 aie_plugin_info.h 文件添加唤醒词识别算法名称及在 ALGORITHM_TYPE_ID_LIST 中的序号。

const std::string ALGORITHM_ID_SAMPLE_1 = "sample_plugin_1";const std::string ALGORITHM_ID_SAMPLE_2 = "sample_plugin_2";const std::string ALGORITHM_ID_IVP = "cv_human_detect";// 添加唤醒词识别的算法名称asr_keyword_spotting// 算法的变量名称与ALGORITHM_TYPE_ID_LIST中算法typeId命名相同,例如:ALGORITHM_ID_KWS const std::string ALGORITHM_ID_KWS = "asr_keyword_spotting";const std::string ALGORITHM_ID_IC = "cv_image_classification";const std::string ALGORITHM_ID_INVALID = "invalid algorithm id";
const std::vector<std::string> ALGORITHM_TYPE_ID_LIST = {    ALGORITHM_ID_SAMPLE_1,    ALGORITHM_ID_SAMPLE_2,    ALGORITHM_ID_IVP,    // 添加唤醒词识别在ALGORITHM_TYPE_ID_LIST中的序号,通过该序号可获得唤醒词识别的算法名称    // 唤醒词识别的算法名称和唤醒词识别在ALGORITHM_TYPE_ID_LIST中的序号顺序需保持一致    ALGORITHM_ID_KWS,    ALGORITHM_ID_IC,};

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

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

相关文章

用katalon解决接口/自动化测试拦路虎--参数化

不管是做接口测试还是做自动化测试&#xff0c;参数化肯定是一个绕不过去的坎。 因为我们要考虑到多个接口都使用相同参数的问题。所以&#xff0c;本文将讲述一下katalon是如何进行参数化的。 全局变量 右侧菜单栏中打开profile&#xff0c;点击default&#xff0c;打开之后…

微信小程序实现删除功能

1. 前端 项目列表展示是使用的wx&#xff1a;for遍历 每个项目展示有3个模块 1. project-title 2. project-content 3. project-foot 全部代码如下 <t-sticky><view class"search"><t-search model:value"{{conditions.keyword}}" pl…

adb shell命令查看当前屏幕可见最顶层Activity和Fragment及其调用栈

adb shell命令查看当前屏幕可见最顶层Activity和Fragment及其调用栈 &#xff08;1&#xff09;当前屏幕可见页面最顶层是哪个Activity: adb shell "dumpsys activity top | grep ACTIVITY | tail -n 1"&#xff08;2&#xff09;当前屏幕可见页面最顶层是哪个Fragm…

mac使用指南

新公司给配备了mac&#xff0c;可惜土鳖的我不会用&#xff0c;所以特地写了一篇文章记录学习mac的过程 快捷键 删除&#xff1a;commanddelete 光标移至最右/左&#xff1a;command右/左箭头 截图&#xff1a;commandshift3/4/5&#xff0c;3代表截全屏&#xff0c;4代表选…

PDF合并和拆分软件 PDF Merge PDF Splitter mac中文版v6.3.9

PDF Merge PDF Splitter mac是一款用于合并和拆分PDF文件的工具。它可以将多个PDF文件合并为一个&#xff0c;也可以将一个PDF文件拆分为多个文件。 合并PDF文件&#xff1a;用户可以将多个PDF文件合并为一个文件。合并后的PDF文件保留原有的文档结构和格式&#xff0c;包括书签…

Winform直接与Wpf交互

Winform项目中&#xff0c;可以直接使用wpf中的自定义控件和窗体 测试环境&#xff1a; vistual studio 2017 window 10 一 winform直接使用wpf的自定义控件 步骤如下&#xff1a; 1 新建winfrom项目&#xff0c;名为WinFormDemo&#xff0c;默认有一个名为Form1的窗体…

方案:基于AI烟火识别与视频技术的秸秆焚烧智能化监控预警方案

一、方案背景 为严控秸秆露天焚烧&#xff0c;改善环境空气质量&#xff0c;各省相继发布秸秆禁烧工作内容。以安徽省为例&#xff0c;大气污染防治联席会议下发了该省2020年秸秆禁烧工作部署通知。2020年起&#xff0c;气象局将对全省秸秆焚烧火点实施卫星全年全时段监测&…

Ruijie未授权访问

本文由掌控安全学院 - 杳若 投稿 漏洞成因 没进行权限校验。 影响范围 Ruijie 发现方式 一、fofa发现 1. title"Ruijie Easy-Smart Switch"利用方式 访问之后直接是进入后台的样子~ 实战 修复方式 对于鉴权类型的漏洞&#xff0c;主要的修复方式是全局增加…

BUUCTF:[GYCTF2020]FlaskApp

Flask的网站&#xff0c;这里的功能是Base64编码解码&#xff0c;并输出 并且是存在SSTI的 /hint 提示PIN码 既然提示PIN&#xff0c;那应该是开启了Debug模式的&#xff0c;解密栏那里随便输入点什么报错看看&#xff0c;直接报错了&#xff0c;并且该Flask开启了Debug模式&am…

[PyTorch][chapter 55][GAN- 3]

前言&#xff1a; 这里面主要结合GAN 损失函数&#xff0c;讲解一下JS散度缺陷问题。 目录&#xff1a; GAN 优化回顾 JS 散度缺陷 一 GAN 优化回顾 1.1 GAN 损失函数 1.2 固定生成器G,最优鉴别器 为 此刻优化目标为 1.3 得到最优鉴别器后&#xff0c;最优编码器G为 优化目标…

机器学习算法基础--逻辑回归简单处理mnist数据集项目

目录 1.项目背景介绍 2.Mnist数据导入 3.数据标签提取且划分数据集 4.数据特征标准化 5.模型建立与训练 6.后验概率判断及预测 7.处理模型阈值及准确率 8.阈值分析的可视化绘图 9.模型精确性的评价标准 1.项目背景介绍 """ MNIST数据集是美国国家标准与…

【论文阅读 08】Adaptive Anomaly Detection within Near-regular Milling Textures

2013年&#xff0c;太老了&#xff0c;先不看 比较老的一篇论文&#xff0c;近规则铣削纹理中的自适应异常检测 1 Abstract 在钢质量控制中的应用&#xff0c;我们提出了图像处理算法&#xff0c;用于无监督地检测隐藏在全局铣削模式内的异常。因此&#xff0c;我们考虑了基于…

with ldid... /opt/MonkeyDev/bin/md: line 326: ldid: command not found

吐槽傻逼xcode 根据提示 执行了这个脚本/opt/MonkeyDev/bin/md 往这里面添加你brew install 安装文件的目录即可

ETLCloud工具让美团数据管理更简单

美团为第三方开发者和商家提供了一系列开放的API接口和工具&#xff0c;使其可以与美团的业务进行对接和集成&#xff0c;从而获得更多的业务机会和增长空间。 通过美团开放平台&#xff0c;第三方开发者和商家可以实现以下功能&#xff1a; 开放接口&#xff1a;美团开放平台…

联想y7000 y7000p 2018/2019 不插电源 不插充电器, 直接关机 ,电量一直89%/87%/86%,V0005如何解决?

这种问题&#xff0c;没有外力破坏的话&#xff0c;电池不可能突然出事。这种一般是联想的固件问题&#xff0c;有可能发生在系统更新&#xff0c;或者突然的不正常关机或长时间电池过热&#xff0c;原因我不是很清楚。 既然发生了&#xff0c;根据我收集的解决方法&#xff0c…

软件测试-基本概念

软件测试-基本概念 1.什么是软件测试 测试指的是对我们生产出来的产品特性进行一些校验&#xff0c;例如对传感器、手机等的测试&#xff0c;而软件测试是对我们开发出的软件进行校验是否存在问题&#xff0c;测试软件特性是否符合用户需求。 2.软件测试的基本概念 软件测试…

Itsycal for Mac: 精美日历软件的魅力之旅

在这个数字化时代&#xff0c;管理时间和日程变得尤为重要。macOS 平台上的 Itsycal 日历软件可以帮助你有效管理你的日程和时间。 Itsycal 是一款轻量级且直观的日历应用程序&#xff0c;专门为 macOS 用户设计。通过这款软件&#xff0c;你可以轻松查看、管理和跟踪你的日常…

分布式多级缓存SDK设计的思考

分布式多级缓存SDK设计的思考 背景整体架构多层级组装回调埋点分区处理一致性问题缓存与数据库之间的一致性问题不同层级缓存之间的一致性问题不同微服务实例上&#xff0c;非共享缓存之间的一致性问题 小结 之前实习期间编写过一个简单的多级缓存SDK&#xff0c;后面了解到一些…

Postman脚本——断言测试

pm对象提供了测试相关功能&#xff1a; pm.test(testName:String, specFunction:Function):Function&#xff1a;测试函数。pm.expect(assertion:*):Function → Assertion&#xff1a;允许在响应数据上做测试&#xff0c;使用ChaiJS expect BDD语法。 可以使用pm.response.t…

SQL模板-用户留存率计算

在这段实习中&#xff0c;我遇到了用户留存率计算的需求&#xff0c;这里做个总结。 首先来讲下&#xff0c;什么是用户留存&#xff1f; 在互联网行业中&#xff0c;用户在某段时间内开始使用应用&#xff0c;经过一段时间后&#xff0c;仍然继续使用该应用的用户。用户留存一…