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技术 | 终端技术 | 音视频技术

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

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

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

相关文章

吉时利2601A数字源表Keithley 2601A

吉时利2601A源测量单元&#xff08;SMU&#xff09;&#xff0c;也被称为源表&#xff0c;是一种高性能的仪器&#xff0c;能够提供100毫伏至40伏的电压范围&#xff0c;以及100纳至10安的电流范围。这种仪器能够提供的功率高达40.4瓦&#xff0c;使其在台式I-V表征工具或多通道…

单电阻落地扇电机驱动 DEMO 方案

SYNWIT DEMO方案 低压 PMSM 电机&#xff0c;软件上采用SVPWM空间电压矢量调制技术&#xff0c;直接闭环启动&#xff0c;相比传统方波效率提高15%&#xff0c;具有更小的谐波分量及转矩脉动&#xff0c;同时采用32位MCU芯片SWM201G6S7 SSOP28 封装为主控&#xff0c;为驱动算…

钡铼分布式IO在玻璃制造中的实时数据采集与监控应用介绍

导读 玻璃行业多年来一直广泛使用 PLC 来帮助管理生产过程所需的精确材料比例&#xff0c;完全依赖其PLC进行数据采集与控制&#xff0c;并且大量依靠人工来操作&#xff0c;所以这些高成本推动了对成本较低的替代方案的需求。 场景描述 某玻璃厂生产的玻璃生产包括配料段、熔…

攀登者1 - 华为OD统一考试

OD统一考试 分值: 100分 题解: Java / Python / C++ 题目描述 攀登者喜欢寻找各种地图,并且尝试攀登到最高的山峰。 地图表示为一维数组,数组的索引代表水平位置,数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如:[0,1,2,4,3,1,0,0,1,2,3,1,2,1,0],代表如下…

iPhone 恢复出厂设置后如何恢复数据

如果您在 iPhone 上执行了恢复出厂设置&#xff0c;您会发现所有旧数据都被清除了。这对于清理混乱和提高设备性能非常有用&#xff0c;但如果您忘记保存重要文件&#xff0c;那就是坏消息了。 恢复出厂设置后可以恢复数据吗&#xff1f;是的&#xff01;幸运的是&#xff0c;…

有什么安全处理方案可以有效防护恶意爬虫

常见的爬虫 有百度爬虫、谷歌爬虫、必应爬虫等搜索引擎类爬虫&#xff0c;此类爬虫经常被企业用于提高站点在搜索引擎内的自然排名&#xff0c;使得站点在各大搜索引擎中的排名能够提高&#xff0c;进一步通过搜索引擎来进行引流为企业增加业务流量。 恶意爬虫与合法、合规的搜…

C语言程序设计——程序流程控制方法(一)

C语言关系运算符 ---等于ab!不等于a!b<、>小于和大于a>b 、a<b<、>小于等于、大于等于a>b 、a<b!非!(0)、!(NULL) 在C99之后&#xff0c;C语言开始支持布尔类型&#xff0c;头文件是stdbool.h。在文中我所演示的所有代码均是C99版。 在C语言上上述关…

JavaSE 万字总结知识点(期末复习指南)

目录 一.Java的特性 二.注释 三.数据类型 基本数据类型 包装类 引用数据类型 四.运算符 五.逻辑控制 选择语句 循环语句 六.数组 七.方法 八.类与对象 构造方法 内部类 九.继承和多态 十.抽象类与接口 抽象类 接口 十一.异常 一.Java的特性 Java最初由Sun…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)添加 删除 修改 释放

在上篇文章&#xff08;处理任务队列中的任务&#xff09;中我们讲解了处理任务队列中的任务的具体流程&#xff0c;eventLoopProcessTask函数的作用&#xff1a; 处理队列中的任务&#xff0c;需要遍历链表并根据type进行对应处理,也就是处理dispatcher中的任务。 // 处理任…

AVL树介绍以及代码实现

二叉搜索树的查找和删除虽然最优情况下能够做到 O(logN) 的级别&#xff0c;但是在一些特殊情况下&#xff0c;它的查找速度只能到达 O(N)级别&#xff0c;比如数据按顺序插入&#xff0c;那么就一定是一棵单边树。 为了针对这种情况&#xff0c;俄罗斯的两位数学家&#xff1a…

字节跳动基础架构SRE-Copilot获得2023 CCF国际AIOps挑战赛冠军

近日&#xff0c;2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会在北京成功举办&#xff0c;活动吸引了来自互联网、运营商、科研院所、高校、软硬件厂商等领域多名专家学者参与&#xff0c;为智能运维的前沿学术研究、落地生产实践打开了新思路。决赛中&#xff0…

安全加密基础—基本概念、keytool、openssl

安全加密基础—基本概念、keytool、openssl 目录 前言 一、概念 明文通信 无密钥密文通信 对称加密 非对称加密 数字签名 消息摘要(MD5) CA数字证书(解决公钥分发的问题) HTTPS 相关文件扩展名 常用后缀名 普通的pem文件内容 二、keytool 2.1常用的命令如下 2…

【linux踩雷】Ubuntu中su root密码无法使用

【linux踩雷】Ubuntu中su root密码无法使用 在ubuntu的安装过程中&#xff0c;没有出现设置root密码&#xff0c;以为密码为空&#xff0c;但是却不能使用 解决方法&#xff1a; 先用sudo passwd更改密码&#xff0c;再去su root就可以了。

2024前端炫酷源码分享(附效果图及在线演示)

分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 GSAP-火箭动画特效 GSAP 火箭动画 当氮气充足的情况下 火箭会冲出 并继续飞行 图片…

AI教我学编程之C#关键字

AI教我学编程系列学习第三课 — C#关键字 前言重点先知关键字分类保留字上下文关键字 对话AI首遇波澜调整指令第一次第二次第三次直到我提出如下指令 人工智能&#xff1f;阶段总结 知识拓展1、Ecma和ISO是什么&#xff1f;2、System&#xff0c;dllhost.exe&#xff0c;taskmg…

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

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

html5实现好看的个人博客模板源码

文章目录 1.设计来源1.1 主界面1.2 认识我界面1.3 我的文章界面1.4 我的模板界面1.5 文章内容界面 2.结构和源码2.1 目录结构2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/135368653 html5实现好看…

【数据库原理】(11)SQL数据查询功能

基本格式 SELECT [ALL|DISTINCT]<目标列表达式>[,目标列表达式>]... FROM <表名或视图名>[,<表名或视图名>] ... [ WHERE <条件表达式>] [GROUP BY<列名 1>[HAVING <条件表达式>]] [ORDER BY <列名 2>[ASC DESC]];SELECT: 指定要…

网络知识-以太网技术的发展及网络设备

目 录 一、背景介绍 &#xff08;一&#xff09;网络技术的时代 &#xff08;二&#xff09;以太网技术脱颖而出 二、以太网的工作原理 &#xff08;一&#xff09;、载波侦听多路访问&#xff08;CSMA/CD&#xff09; 1、数据发送流程 2、发送过程解析 3、…