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

mnn-llm: 大语言模型端侧CPU推理优化

a3940bf5bfe6c0fb9f24351c2ccd892d.gif

在大语言模型(LLM)端侧部署上,基于 MNN 实现的 mnn-llm 项目已经展现出业界领先的性能,特别是在 ARM 架构的 CPU 上。目前利用 mnn-llm 的推理能力,qwen-1.8b在mnn-llm的驱动下能够在移动端达到端侧实时会话的能力,能够在较低内存(<2G)的情况下,做到快速响应。

39f17e5071e7fa7de353c87a595a45b5.png

背景

在大型语言模型(LLM)领域的迅猛发展背景下,开源社区已经孵化了众多优异的 LLM 模型。这些模型在自然语言处理的各个领域展现出了强大的能力,但同时也带来了一个挑战,即如何有效地将这些模型部署到端侧设备上。为此,原来只支持特定模型的 ChatGLM-MNN 项目已升级并更名为 mnn-llm,并集成到了MNN项目中;该项目支持多个目前主流的开源LLM模型的部署。与此同时,为了简化不同 LLM 模型向 ONNX 格式导出的流程,我们推出了 llm-export 项目。该项目为多种 LLM 模型提供了统一的导出方案,大大地降低了从预训练模型导出的复杂度。在本文中,我们将介绍LLM模型的导出与部署支持与MNN针对LLM端侧CPU推理的性能优化方案。

mnn-llm地址:https://github.com/wangzhaode/mnn-llm

llm-export地址:https://github.com/wangzhaode/llm-export

b0db3f2e39830b8d4ecd83da14b0c382.png

模型导出

在将深度学习模型从研究原型转换为实际可部署的产品时,模型导出阶段的顺畅与否对于整个工作流程至关重要。通常,这个过程涉及将模型从训练框架中导出到一个中间表示,如 ONNX(开放神经网络交换格式),然后再转换为目标部署框架——在本例中为 MNN格式。为了简化并标准化这一过程,我们开发了一个名为 llm-export 的工具。

llm-export 工具的核心思想在于对大型语言模型(LLM)进行了高度抽象,建立了一个统一化的导出框架。这个项目的目标是消除将各种 LLM 模型导出到 ONNX 格式的障碍,确保无论是何种架构的 LLM 都能通过一个清晰定义的接口进行处理。在 llm-export 中,我们定义了一套公用的导出逻辑,这意味着对于任何特定的 LLM,开发者只需实现模型的加载逻辑。这极大地减少了从多样化的训练环境向 ONNX 模型迁移的复杂性,并显著提高了整个导出过程的易用性。模型一旦被成功导出至 ONNX,即可利用现有的mnnconver工具转换到 MNN 格式,从而使用MNN完成llm模型的推理。

cd8a6a13d412e5e05eec75a903951fc3.jpeg

llm-export中将llm模型抽象为4部分:tokenizer, embedding, blocks, lm;主要代码如下:

class LLM(torch.nn.Module):def __init__(self, args):super().__init__()# load tokenizer, embed, blocks, lmself.load_model(args.path)def forward(self, input_ids, attention_mask, position_ids, past_key_values):hidden_states = self.embed(input_ids)presents = []for i in range(self.block_nums):hidden_states, kv = self.blocks[i](hidden_states, attention_mask,position_ids, past_key_values[i])presents.append(kv)token_id = self.lm(hidden_states).view(1)presents = torch.stack(presents)return token_id, presentsdef export(self):# export llm to onnx and mnn...class Chatglm2_6b(LLM):def load_model(self, model_path: str):# chatglm2 load impl...class Qwen_7b(LLM):def load_model(self, model_path: str):# qwen load impl...

881ae57456327a886344e164ade920c7.png

模型部署

在部署大型语言模型(LLM)时,兼容性和易用性是关键因素。为了解决这一挑战,我们开发了一个名为 mnn-llm 的项目。考虑到MNN在跨平台上支持上的优秀表现,该项目基于 MNN 构建,旨在为各种平台提供一个统一的 LLM 模型部署解决方案。mnn-llm 项目使得从 llm-export 导出的模型能够无缝进行端到端的推理,并为开发者提供了一个简易的文本到文本(txt2txt)调用接口。

在mnn-llm中我们移植实现了目前主流的tokenizer工具:Sentencepiece 和 Tiktoken。这些 tokenizer 组件是处理自然语言输入的关键部分,它们能够将原始文本转换为模型能理解的格式。同时为了轻量化,两种模型都使用文本的方式存储,移除了Sentencepiece中迪对protobuf的依赖。此外,考虑到内存占用在移动设备上尤为宝贵,我们还在 mnn-llm 中引入了 disk embedding 功能。这意味着用户可以根据需要选择:在模型推理过程中使用 embedding 模型在内存计算,或者直接从磁盘加载 embedding 值。这种灵活性不仅降低了运行时的内存需求,也为用户提供了更多的选择来平衡推理性能和资源使用。为了确保 mnn-llm 的通用性和扩展性,我们设计了一种易于扩展的架构。开发者可以通过继承基类并实现特定的配置来支持不同的 LLM 模型。这种架构设计使得整合新的 LLM 模型变得简单快捷,大大降低了将最新的研究成果应用到实际产品中的门槛。

41ec458255bd31a08426831e0e9fd621.png

513bd45355aeb764da2cbbf71ea7e154.png

性能优化



  性能分析

在深入研究大型语言模型(LLM)的性能时,理解主干网络的构成至关重要。LLM的主干网络由一系列连续的block组成,每个block的核心计算部分是Attention。如图所示,Attention的执行涉及到两个主要的计算操作:Linear(绿色表示)和MatMul(黄色表示)。这两种操作不仅要执行复杂的数学计算,还要伴随诸如split、concat和transpose等内存操作,这些统称为Memory算子。因此,我们可以将LLM模型推理过程中的核心操作分为三类:Linear, MatMul和Memory。

值得注意的是,这三类算子的计算量和内存访问量会受到输入数据的batch大小和kv-cache长度的影响。而根据batch和kv-cahce的输入特点,LLM推理可以被分为两个阶段:prefill和decode。在prefill阶段,我们输入了一个包含m个token的提示(prompt),执行batch为m的推理,此时由于是初始输入,没有kv-cache的需求,得到了首个token的输出。接着,在decode阶段,我们以上一轮的输出token作为输入,进行batch为1的推理,这时kv-cache的长度变为m+n,其中n代表之前已生成的token数量。

通过在ARM-CPU上的测试,我们可以详细分析在这两个阶段中上述三类核心算子的耗时情况。例如,单个block的耗时分析显示:

  1. 在prefill阶段,Linear算子的耗时占比相对稳定,超过了93%,而MatMul和Memory算子的耗时占比分别约为3%和2%;

  2. 在decode阶段,随着m+n的增长,Linear算子的时间占比有所下降,而MatMul和Memory算子的占比有所上升。尽管如此,在多数情况下,耗时主要集中在Linear算子上。

综合以上分析,我们决定将优化工作的重点放在Linear算子上。通过对Linear计算的深入优化,我们有望实现整个LLM推理过程的性能提升。这将是提高LLM整体推理效率的关键所在,尤其是在资源受限的设备上,每一次性能的增益都至关重要。

e9df2fd83d4149dc224e26f74c41d4f1.jpeg

  优化策略

在llm模型推理过程中,线性层(Linear layers)的计算效率对于整体性能至关重要。这个计算主要分为两个阶段:prefill阶段处理大量输入数据时,线性层是矩阵乘法(GEMM),这是一个计算密集的过程;在模型解码(decode)阶段时,线性层的计算是矩阵向量乘法(GEMV),这时候访存的效率变得更加关键。

为了优化这两个阶段的性能,我们采取了不同的技术策略:

  1. 对于计算密集型的优化:我们关注于使用更强大的计算指令,选择计算峰值更高的SIMD指令集来完成核心的计算,同时使用汇编实现多种规模的kernel,以此来加速矩阵乘法操作。

  2. 对于访存密集型的优化:我们的策略是通过降低数据的位宽来减少内存访问量(量化技术)和数据重排来实现。我们选择了 W4A8 的量化方案,即将模型中的权重(W)量化到 4 位,而将激活值(A,即模型的输入和输出)量化到 8 位。这样做可以大幅减少模型的内存占用,并提升性能,因为较低位宽的数据需要更少的内存带宽来读写;同时针对W4A8的量化方案按照设备支持的最优SIMD计算指令对数据进行特定的重排以提升内存局部性,提升访存效率。

在当今流行的大型语言模型(LLM)中,线性层的权重数量达到了惊人的规模,常常包含数十亿个参数。举个例子,一个70亿参数(7b)的模型,即使采用16位浮点(fp16)来存储,也需要约14GB的内存空间。这种规模的模型在内存受限的移动设备上部署是一大挑战。为了解决这个问题,我们必须采取措施来压缩这些权重,使它们占用更少的内存。量化技术为我们提供了一条可行之路。幸运的是,LLM中的线性层权重之间的差异相对较小,这使得它们非常适合进行低比特量化——即使用较少的比特表示每个权重值。即使经过量化,计算结果仍能保持与原始浮点计算高度一致,这表明量化对模型性能的影响很小。考虑到移动端设备的内存大小,我们选择了4位量化作为解决方案。通过这种方法,那个需要7b模型现在只需大约3.5GB内存即可运行。这意味着拥有8GB内存的设备也能够运行这样一个大模型。我们采用了非对称量化方案,具体的4位量化公式是:

940db4ff4cfe1c531d2356fea1b2bd6e.png

采用这种量化方法的一个巨大优势在于,计算过程中模型的权重访存量可以减少四倍,从而有效提高访存性能。

在量化权重的同时,我们也审视了模型输入的处理方式。过去,我们利用了混合精度计算,即结合了4位量化的权重与16位或32位浮点的输入。这要求我们在计算前将量化后的权重解量化为浮点数,同时从内存中加载浮点型的输入数据,接着进行浮点乘加运算。这种方法在处理输入时需要较多的内存访问,并且由于权重是以行优先的方式存储的,这进一步增加了内存访问量。另外,由于涉及浮点计算,它使用浮点型的SIMD指令,其峰值性能低于整数型指令。

为了应对这些问题,我们采取了针对输入的动态量化方案,即W4A8的量化方案。首先我们需要在运行时统计输入的分布情况,使用absmax-quant的方案将输入两位8bit整形作为线性性层的如数。然后我们将4bit量化的权重加载并转换为8位整数值,使用8位整数来完成矩阵乘的乘累加操作,使用32位整数来保存累加结果。最终,在整个计算过程结束后,我们会将这些累加结果反量化回浮点数。采用W4A8技术不仅显著降低了内存访问量,还使我们能够利用更高算力的整数计算指令,大幅提升了模型的计算性能。

460ebac2be38e8df63af57e39cf3c2d6.jpeg

采用 W4A8 量化策略,我们能够在保持计算精度的同时显著提高模型的计算和内存访问效率。以往的实践中,W4A16或W4A32方案采用浮点运算,其中权重以int4存储,而输入数据保持16位或32位的浮点精度。在x86架构的系统中,此类浮点运算通常依赖于vfmadd132ps这类SIMD指令。相对地,当转向W4A8方案,即使用8位整数(int8)来执行计算,我们可以利用vpmaddubsw这类更高效的整数指令。在ARM架构的系统中,浮点计算使用fmla指令,而在采用8位整数计算时,可以使用如sdotsmmla的指令。性能测试显示,在x86平台上,vpmaddubsw的峰值性能几乎是vfmadd132ps的三倍。而在ARM平台上,smmla指令的峰值性能则是fmla的四倍。这一显著提升反映了通过优化指令选择可实现的算力增益。除了提升计算性能外,内存访问效率也是模型优化中不可或缺的一环。以一个具有4096x4096大小权重矩阵的广义矩阵向量乘法(GEMV)为例,我们将以传统的32位浮点(fp32)权重和输入数据的内存访问量作为基准。与此基准相比,W4A8方案明显减少了内存访问量,降幅超过五倍。即使与W4A16和W4A32方案相比,W4A8方案仍实现了两到三倍的访存量减少。

760c0626411c480bddab5c35ce0b2aa0.jpeg

同时为了提升内存局部性,减少访存开销,我们结合W4A8的计算模式与设备支持的计算指令对输入和权重做了特定的数据重排。

具体来说,考虑到输入数据的形状通常为 [batch, ic],权重的形状为 [oc, ic],我们将这些数据重新排列为 [ic/pack, batch, pack] 和 [oc/pack, ic/pack, pack, pack]。这里的 "pack" 是一种按照硬件支持的计算指令精心选取的分块大小。例如,当系统支持 smmla 指令时,我们选择 pack = 8;而当系统支持 sdot 指令时,我们选择 pack = 4;当系统支持AVX2 时选择pack = 8;而当系统仅支持SSE 时,选择使pack = 4。这种重排策略使得计算核心(kernel)能够执行更为紧凑的矩阵乘法操作:[batch, pack] 与 [pack, pack] 的矩阵相乘,生成 [batch, pack] 的结果矩阵。我们进一步针对可用的寄存器数量,实现了针对 batch 维度的不同的计算Kernel,可以充分利用计算器来提升访存效率。在大型语言模型(LLM)的线性层中,输出通道的数量(oc)往往较大。这为我们提供了在 [oc/pack] 维度上执行多线程并行计算的机会,能够充分利用现代多核能力,提升多核性能。

以下是ARM上针对smmla 指令的矩阵乘kernel核心代码:

LoopSz_TILE_2:// src    : 1 x [2 x 8] : v4// weight : 4 x [2 x 8] : v0-3// dst    : 1 x 4 x [4] : v16-19ld1 {v0.16b, v1.16b}, [x25], #32    // weight// int4 to int8: v0, v1, v2, v3ushr v8.16b, v0.16b, #4and v9.16b, v0.16b, v14.16bsub v8.16b, v8.16b, v15.16bsub v9.16b, v9.16b, v15.16bushr v10.16b, v1.16b, #4and v11.16b, v1.16b, v14.16bsub v10.16b, v10.16b, v15.16bsub v11.16b, v11.16b, v15.16bzip1 v0.16b, v8.16b, v9.16bzip2 v1.16b, v8.16b, v9.16bzip1 v2.16b, v10.16b, v11.16bzip2 v3.16b, v10.16b, v11.16bld1 {v4.16b}, [x24], x15   // src.inst 0x4e80a490 // smmla v16.4s, v4.16b, v0.16b.inst 0x4e81a491 // smmla v17.4s, v4.16b, v1.16b.inst 0x4e82a492 // smmla v18.4s, v4.16b, v2.16b.inst 0x4e83a493 // smmla v19.4s, v4.16b, v3.16bsubs x26, x26, #1bne LoopSz_TILE_2

65e54c4501a60c2e4e2317d4df99ca59.png

性能测试

测试模型主要选取1.8b, 6b与7b的模型,其中6b, 7b模型均使用4bit量化;1.8b模型分别测试了4bit和8bit量化。均使用CPU-4线程测试,android使用fp16, 其他平台使用fp32,具体测试环境如下:

b00c06855af0776a6d00fc591b2a0198.png

分别测试llm的prefill速度与decode速度,

  1. prefill速度计算:输入token数目为m的prompt, 计算得到第一个输出token的时间为t1, 则prefill_speed = m / t1

  2. decode速度计算:在输出第二个token开始直到结束输出token数为n, 耗时为t2, 则decode_speed = n / t2

各模型的速度如下图所示:

53b35e95f90611a415c9e968941b75cb.jpeg

6eafdfd62a3811fe912a6712c9aab8de.jpeg

在CPU上选择了与llama.cpp和fastllm进行性能对比,模型选取3个框架都支持的llama2-7b,均采用4bit量化;输入采用fp32。测试结果表明在ARM CPU上mnn-llm的性能大幅领先;在x86上decode速度略慢,prefill速度有较大领先。同时我们选择了与编译方法实现的llm框架mlc-llm作对比,但是mlc-llm官方不支持CPU部署,因此我们对比了mlc-llm在相同的Android设备上的GPU性能。

bc9caac7b814e2f5fe187b99be9caf17.jpeg

35f57ecdf1c2d4869d3369c597cfb67d.png

总结与展望

在大语言模型(LLM)端侧部署上,基于 MNN 实现的 mnn-llm 项目已经展现出业界领先的性能,特别是在 ARM 架构的 CPU 上。目前利用 mnn-llm 的推理能力,qwen-1.8b在mnn-llm的驱动下能够在移动端达到端侧实时会话的能力,能够在较低内存(<2G)的情况下,做到快速响应,Android可以下载 qwen-1.8b-apk 来体验;iOS也可以编译mnn-llm-ios体验。然而,端侧部署 LLM 仍然面临着一系列挑战。尽管 qwen-1.8b 模型能在端侧设备上达到实用性能,但更大规模的模型如 6b 或 7b 仍然存在较高的部署门槛。这些模型往往要求更多的内存(~3GB)并且在处理较长文本(~ 100 token)时,很难在 1 秒内给出响应,这限制了其在实时应用场景下的可用性。此外,MNN在移动端 GPU 上的 LLM 推理性能尚未达到预期水平,目前正持续地在 GPU 性能上进行优化。

qwen-1.8b-apk地址:https://github.com/wangzhaode/mnn-llm/releases/tag/qwen-1.8b-apk

1fcb48d26101b13df807a223e84726ef.png

项目代码

  1. https://github.com/alibaba/MNN/tree/master/llm

  2. https://github.com/wangzhaode/llm-export

  3. https://github.com/wangzhaode/mnn-llm

465a3c8bedf1666dd54b99ea83d8df1b.png

团队介绍

大淘宝技术Meta Team,负责面向消费场景的3D/XR基础技术建设和创新应用探索,通过技术和应用创新找到以手机及XR 新设备为载体的消费购物3D/XR新体验。团队在端智能、商品三维重建、3D引擎、XR引擎等方面有深厚的技术积累。先后发布端侧推理引擎MNN,端侧实时视觉算法库PixelAI,商品三维重建工具Object Drawer等技术。团队在OSDI、MLSys、CVPR、ICCV、NeurIPS、TPAMI等顶级学术会议和期刊上发表多篇论文。

本篇内容作者:雁行

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法

相关文章:

mnn-llm: 大语言模型端侧CPU推理优化

在大语言模型(LLM)端侧部署上&#xff0c;基于 MNN 实现的 mnn-llm 项目已经展现出业界领先的性能&#xff0c;特别是在 ARM 架构的 CPU 上。目前利用 mnn-llm 的推理能力&#xff0c;qwen-1.8b在mnn-llm的驱动下能够在移动端达到端侧实时会话的能力&#xff0c;能够在较低内存…...

Freemarker实现Html全站静态化

全站静态化 在大型网站中&#xff0c;比如主流电商商品页&#xff0c;访问者看到的页面基本上是静态页面。为什么都要把页面静态化呢&#xff1f;其实把页面静态化&#xff0c;好处有很多。例如&#xff1a;访问速度快&#xff0c;更有利于搜索引擎收录等。 目前主流的静态化…...

16.顺子日期(14)

题目 public class Main {public static boolean isLegal(String date) {int l 0;int n date.length();while(l<(n-3)) {int t1 (int)Integer.valueOf(date.substring(l,l1));int t2 (int)Integer.valueOf(date.substring(l1,l2));int t3 (int)Integer.valueOf(date.s…...

《动手学深度学习》学习笔记 第5章 深度学习计算

本系列为《动手学深度学习》学习笔记 书籍链接&#xff1a;动手学深度学习 笔记是从第四章开始&#xff0c;前面三章为基础知道&#xff0c;有需要的可以自己去看看 关于本系列笔记&#xff1a; 书里为了让读者更好的理解&#xff0c;有大篇幅的描述性的文字&#xff0c;内容很…...

【Redis】非关系型数据库之Redis的介绍及安装配置

目录 前言 一、关系型数据库与非关系型数据库 1.1关系型数据库 1.2非关系型数据库 1.3两者的区别 1.4非关系型数据库产生的背景 1.5总结 二、Redis介绍 2.1Redis是什么 2.2Redis的优点 2.3Redis的使用场景 2.4那些数据适合放在缓存中 2.5Redis为什么那么快&#xf…...

3D模型轻量化

在线工具推荐&#xff1a;3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 近来&#xff0c;基于3D模型在影视作品、数字旅游项目诸多3D视觉领域都取得…...

数据分析——快递电商

一、任务目标 1、任务 总体目的——对账 本项目解决同时使用多个快递发货&#xff0c;部分隔离区域出现不同程度涨价等情形下&#xff0c;如何快速准确核对账单的问题。 1、在订单表中新增一列【运费差异核对】来表示订单运费实际有多少差异&#xff0c;结果为数值。 2、将…...

《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置(8)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置&#xff08;7&#xff09; 2.2 HOST主桥 MPC8548处理器的拓扑结构如图2-2所示&#xff1a; 2.2.2 存储器域地址空间到PCI总线域地址空间的转换 MPC8548处理器使用ATMU&#xff…...

Hadoop分布式文件系统(二)

目录 一、Hadoop 1、文件系统 1.1、文件系统定义 1.2、传统常见的文件系统 1.3、文件系统中的重要概念 1.4、海量数据存储遇到的问题 1.5、分布式存储系统的核心属性及功能含义 2、HDFS 2.1、HDFS简介 2.2、HDFS设计目标 2.3、HDFS应用场景 2.4、HDFS重要特性 2.4…...

macOS跨进程通信: FIFO(有名管道) 创建实例

一&#xff1a; 简介 在类linux系统中管道分为有名管道和匿名管道。两者都能单方向的跨进程通信。 匿名管道&#xff08;pipe&#xff09;: 必须是父子进程之间&#xff0c;而且子进程只能由父进程fork() 出来的&#xff0c;才能继承父进程的管道句柄&#xff0c;一般mac 开发…...

推荐几个免费的HTTP接口Mock网站和工具

在前后端分离开发架构下&#xff0c;经常遇到调用后端数据API接口进行测试、集成、联调等需求&#xff0c;比如&#xff1a; &#xff08;1&#xff09;前端开发人员很快开发完成了UI界面&#xff0c;但后端开发人员的API接口还没有完成&#xff0c;不能进行前后端数据接口对接…...

企业数据库安全管理规范

1.目的 为规范数据库系统安全使用活动&#xff0c;降低因使用不当而带来的安全风险&#xff0c;保障数据库系统及相关应用系统的安全&#xff0c;特制定本数据库安全管理规范。 2.适用范围 本规范中所定义的数据管理内容&#xff0c;特指存放在信息系统数据库中的数据。 本…...

react:ffcreator中FFCreatorCenter视频队例

最近项目要求&#xff0c;一键生成房子的推荐视频&#xff0c;选几张图&#xff0c;加上联系人的方式就是一个简单的视频&#xff0c;因为有web端、小程序端&#xff0c;为了多端口用&#xff0c;决定放在服务器端生成。 目前用的是react中的nextjs来开发项目。 nextjs中怎样…...

力扣(leetcode)第434题字符串中的单词数(Python)

434.字符串中的单词数 题目链接&#xff1a;434.字符串中的单词数 统计字符串中的单词个数&#xff0c;这里的单词指的是连续的不是空格的字符。 请注意&#xff0c;你可以假定字符串里不包括任何不可打印的字符。 示例: 输入: “Hello, my name is John” 输出: 5 解释: 这…...

django学习:页面渲染与请求和响应

1.请求过程 2.页面渲染 在app中新建一个目录&#xff08;Directory&#xff09;&#xff0c;文件名命名为templates。该文件名命名是固定的&#xff0c;不可命名出错&#xff0c;如若后续步骤出错&#xff0c;该目录文件名是一个检查的重点项目。在该目录下新建一个html文件&a…...

Redis 数据一致性

概述 当我们在使用缓存时&#xff0c;如果发生数据变更&#xff0c;那么你需要同时操作缓存和数据库&#xff0c;而它们两个又分属不同的系统&#xff0c;因此无法做到同时操作成功或失败&#xff0c;因此在并发读写下很可能出现缓存与数据库数据不一致的情况 理论上可以通过…...

Mac环境下反编译apk

Mac环境下反编译apk 安装反编译工具dex2jar&#xff1a;[官网下载](https://sourceforge.net/projects/dex2jar/)JD-GUI&#xff1a;[官网下载](https://jd-gui.apponic.com/) 实操1. 将需要反编译的 .apk 文件放在下载的 dex2jar 文件夹目录下2. 使用 cd /xxx/dex2jar-2.0 命令…...

计算机网络——网络模型的组织、看法以及标准化流程

1. 通信技术和标准化领域中扮演重要角色的组织 1.1 国际和国家官方标准化机构 OSI&#xff1a;国际标准化组织&#xff08;ISO&#xff09;&#xff0c;负责国际标准的制定&#xff0c;旨在确保全球产品和服务的安全性、可靠性和效率。它有许多国家分支机构&#xff0c;包括法…...

【JAVA】volatile 关键字的作用

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 volatile 的作用&#xff1a; 结语 我的其他博客 前言 在多线程编程中&#xff0c;保障数据的一致性和线程之间的可见性是…...

Next.js 第一次接触

因为需要整个漂亮的在线文档&#xff0c;所以接触了next.js&#xff0c;因为对前端js本身不够熟悉&#xff0c;别说对react.js 又不会&#xff0c;时间又不允许深入研究&#xff0c;所以&#xff0c;为了加一个导航菜单&#xff0c;极其痛苦。 有点小bug&#xff0c;不过不影响…...

CISSP 第7章:PKI和密码学应用

第七章 PKI和密码学应用 7.1 非对称密码学 对称密码系统具有共享的秘钥系统&#xff0c;从而产生了安全秘钥分发的问题 非对称密码学使用公钥和私钥对&#xff0c;无需支出复杂密码分发系统 7.1.1 公钥与私钥 7.1.2 RSA&#xff08;兼具加密和数字签名&#xff09; RSA算法依赖…...

dji uav建图导航系列()ROS中创建dji_sdk节点包(二)实现代码

在前文 【dji uav建图导航系列()ROS中创建dji_sdk节点包(一)项目结构】中简单介绍了项目的结构,和一些配置文件的代码。本文详细说明目录src下的节点源代码实现。 文章目录 1、代码结构2、PSDK部分3、ROS部分3.1、头文件3.1.1、外部调用 node_service.h3.1.2、节点类定义…...

数字化工厂产品推荐 带OPC UA的分布式IO模块

背景 近年来&#xff0c;为了提升在全球范围内的竞争力&#xff0c;制造企业希望自己工厂的机器之间协同性更强&#xff0c;自动化设备采集到的数据能够发挥更大的价值&#xff0c;越来越多的传统型工业制造企业开始加入数字化工厂建设的行列&#xff0c;实现智能制造。 数字化…...

使用OHOS SDK构建opus

参照OHOS IDE和SDK的安装方法配置好开发环境。 从github下载源码。 执行如下命令&#xff1a; git clone --depth1 https://github.com/xiph/opus进入源码所在的目录&#xff0c;创建批处理文件ohos_build.cmd&#xff0c;内容如下&#xff1a; echo off setlocalset OHOS_…...

K-means 聚类算法分析

算法简述 K-means 算法原理 我们假定给定数据样本 X &#xff0c;包含了 n 个对象 &#xff0c;其中每一个对象都具有 m 个维度的属性。而 K-means 算法的目标就是将 n 个对象依据对象间的相似性聚集到指定的 k 个类簇中&#xff0c;每个对象属于且仅属于一个其到类簇中心距离…...

uniapp获取定位

Uniapp 是一种跨平台应用开发框架&#xff0c;它能够快速地构建出针对不同平台的应用程序。在Uniapp中&#xff0c;实现定位功能也变得十分简单&#xff0c;只需要简单的配置就能轻松实现。 一、高德地图根据指定位置获取经纬度 参考地址&#xff1a;地理/逆地理编码-基础 API…...

Python 面向对象之反射

Python 面向对象之反射 【一】概念 反射是指通过对象的属性名或者方法名来获取对象的属性或调用方法的能力反射还指的是在程序额运行过程中可以动态获取对象的信息(属性和方法) 【二】四个内置函数 又叫做反射函数 万物皆对象&#xff08;整数、字符串、函数、模块、类等等…...

HPM6750开发笔记《DMA接收和发送数据UART例程深度解析》

目录 概述&#xff1a; 端口设置&#xff1a; 代码分析&#xff1a; 运行现象&#xff1a; 概述&#xff1a; DMA&#xff08;Direct Memory Access&#xff09;是一种计算机系统中的数据传输技术&#xff0c;它允许数据在不经过中央处理器&#xff08;CPU&#xff09;的直…...

SQL IN 操作符

IN 操作符 IN 操作符允许您在 WHERE 子句中规定多个值。 SQL IN 语法 SELECT column1, column2, ... FROM table_name WHERE column IN (value1, value2, ...); 参数说明&#xff1a; column1, column2, ...&#xff1a;要选择的字段名称&#xff0c;可以为多个字段。如果…...

如何使用Plex在Windows系统搭建个人媒体站点公网可访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…...

穿衣搭配的网站如何做/百度指数大数据

LoadRunner参数化后的值在脚本中多处位置引用&#xff08;LoadRunner 一参多用&#xff09; LoadRunner的参数化给了我们很多便利&#xff0c;但是当一个脚本中同一个值出现多处&#xff0c;并且值都是一致的。这个时候&#xff0c;我们参数化的话&#xff0c;是否需要把这些数…...

一个可以做网站/原创代写文章平台

深入解析Internet***http://netsecurity.51cto.com 2010-10-09 11:20 佚名 中国IT实验室 我要评论()摘要&#xff1a;本文主要向你介绍的是Internet的***的深入剖析&#xff0c;以及对Internet***者需要了解的资料&#xff0c;系统内常见的服务及其采用的端口等内容的讲述。…...

如何修改网站联系人/宁波seo高级方法

1.在云函数的文件夹下面建立一个文件/node.js云函数 2.然后需要cnpm i 下载依赖 3.存储 &#xff08;通过点击进行存储到云函数&#xff09; 4.读取云函数里面的数据 云函数文件入口&#xff1a; const cloud require(wx-server-sdk)...

动态网站很难做吗/一键制作单页网站

本文章将会介绍个人用户如何使用远程桌面工具TeamViewer&#xff0c;将会从该产品的定义以及版本区分等方面介绍。 什么是TeamViewer&#xff1f; TeamViewer全球最流行的远程桌面工具&#xff0c;兼容于Microsoft Windows&#xff0c;Mac OS X&#xff0c;Linux&#xff0c;i…...

官方网站页面尺寸/软文兼职10元一篇

C# 查找数组中指定数字&#xff0c;最小值&#xff0c;最大值。代码1 classProgram2 {3 staticvoidMain(string[] args)4 {5 intsearchNumber;6 boolfound;7 //TestArray nums new TestArray(10);8 int[] nums newint[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};9 #region初始化数…...

wordpress 注册角色/潍坊seo教程

可变参数 JDK1.5开始&#xff0c;Java支持传递同类型的可变参数给一个方法 在方法声明中&#xff0c;在指定参数类型后加一个省略号&#xff08;…&#xff09; 一个方法中只能指定一个可变参数&#xff0c;他必须是方法的最后一个参数&#xff0c;任何普通的参数必须在他之前…...