【“星瑞” O6 评测】 — CPU llama.cpp不同优化速度对比

在这里插入图片描述

前言

随着大模型应用场景的不断拓展,arm cpu 凭借其独特优势在大模型推理领域的重要性日益凸显。它在性能、功耗、架构适配等多方面发挥关键作用,推动大模型在不同场景落地

1. Kleidi AI 简介

Arm Kleidi 成为解决这些挑战的理想方案,它能够为运行在 Arm CPU 上的所有 AI 推理工作负载提供无缝的性能优化。KleidiAI 是一套轻量级且高性能开源的 Arm 例程,专为 AI 加速而设计。Arm 的 KleidiAI 库,提供了针对 sme、i8mm 和点积加速等硬件功能优化的矩阵乘法内核,目前已被集成到最新版本的主流端侧 AI 框架中,包括 ExecuTorch、Llama.cpp、LiteRT (通过XNNPACK)和 MediaPipe,能让数百万名开发者无需进行额外操作,即可自动获取 AI 性能的显著提升。

这里我们对比同一个模型,CPU编译时不同优化选项带来的提升

2. 依赖安装

sudo apt install cmake libcurl4-openssl-dev

下载代码

git clone https://github.com/ggml-org/llama.cpp.git## 切换到我测试的分支(可选)
git checkout b5195

3. 编译时不同优化选项实测

3.1 不开启任何优化

cmake -B build
cmake --build build --config Release -j

3.2 下载/转换/量化模型

https://www.modelscope.cn/models/Qwen/Qwen2.5-3B-Instruct/files下载模型

转换

pip install -r requirements/requirements-convert_hf_to_gguf.txt
python convert_hf_to_gguf.py /home/radxa/.cache/modelscope/hub/models/Qwen/Qwen2.5-3B-Instruct

量化

可以将模型的权重系数量化成Q4_0

./build/bin/llama-quantize /home/radxa/.cache/modelscope/hub/models/Qwen/Qwen2.5-3B-Instruct/Qwen2.5-3B-Instruct-F16.gguf asserts/Qwen2.5-3B-Instruct-Q4_0.gguf Q4_0

验证模型正确性

taskset -c 0,5,6,7,8,9,10,11 ./build/bin/llama-cli -m asserts/Qwen2.5-3B-Instruct-Q4_0.gguf -c 4096 -t 8 --conversation

打印信息

> hello
Hello! How can I assist you today? Do you have any questions or topics you'd like to discuss?> 
llama_perf_sampler_print:    sampling time =       2.79 ms /    32 runs   (    0.09 ms per token, 11477.76 tokens per second)
llama_perf_context_print:        load time =     498.94 ms
llama_perf_context_print: prompt eval time =     592.82 ms /     9 tokens (   65.87 ms per token,    15.18 tokens per second)
llama_perf_context_print:        eval time =    1711.00 ms /    22 runs   (   77.77 ms per token,    12.86 tokens per second)
llama_perf_context_print:       total time =    6498.13 ms /    31 tokens
Interrupted by user

3.3 不开启任何优化的benchmark

taskset -c 0,5,6,7,8,9,10,11 ./build/bin/llama-bench -m asserts/Qwen2.5-3B-Instruct-Q4_0.gguf -p 128 -n 128 -t 8

结果

modelsizeparamsbackendthreadstestt/s
qwen2 3B Q4_01.69 GiB3.09 BCPU8pp12817.16 ± 0.08
qwen2 3B Q4_01.69 GiB3.09 BCPU8tg12812.85 ± 0.09

3.4 开启avmv9优化

编译

cmake -B build_armv9 -DCMAKE_CXX_FLAGS="-march=armv9-a" -DCMAKE_C_FLAGS="-march=armv9-a"
cmake --build build_armv9 --config Release -j

benchmark命令: taskset -c 0,5,6,7,8,9,10,11 ./build_armv9/bin/llama-bench -m asserts/Qwen2.5-3B-Instruct-Q4_0.gguf -p 128 -n 128 -t 8

结果

modelsizeparamsbackendthreadstestt/s
qwen2 3B Q4_01.69 GiB3.09 BCPU8pp12884.39 ± 0.80
qwen2 3B Q4_01.69 GiB3.09 BCPU8tg12818.76 ± 0.22

3.5 开启kleidiai优化

kleidiai已经集成到llama.cpp的后端,只需要编译时给定正确的选项就行。

官方给的编译,我有报错

cmake -B build_kle -DGGML_CPU_KLEIDIAI=ON
cmake --build build_kle --config Release -j

报错:

/home/radxa/1_AI_models/llama.cpp/ggml/src/ggml-cpu/kleidiai/kernels.cpp:22:30: error: zero-size array ‘gemm_gemv_kernels’22 | static ggml_kleidiai_kernels gemm_gemv_kernels[] = {|                              ^~~~~~~~~~~~~~~~~
gmake[2]: *** [ggml/src/CMakeFiles/ggml-cpu.dir/build.make:272: ggml/src/CMakeFiles/ggml-cpu.dir/ggml-cpu/kleidiai/kernels.cpp.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....

于是改用clang++编译器,

## 安装依赖
sudo apt install clang libomp-dev## 编译
cmake -B build_kle -DGGML_CPU_KLEIDIAI=ON -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
cmake --build build_kle --config Release -j

benchmark命令: taskset -c 0,5,6,7,8,9,10,11 ./build_kle/bin/llama-bench -m asserts/Qwen2.5-3B-Instruct-Q4_0.gguf -p 128 -n 128 -t 8

结果

modelsizeparamsbackendthreadstestt/s
qwen2 3B Q4_01.69 GiB3.09 BCPU8pp128129.53 ± 6.59
qwen2 3B Q4_01.69 GiB3.09 BCPU8tg12816.25 ± 0.18

打印中有load_tensors: CPU_KLEIDIAI model buffer size = 1488.38 MiBKLEIDIAI = 1表明编译选项正确打开。
全部的打印信息。

build: 5195 (2d451c80) with cc (Debian 12.2.0-14) 12.2.0 for aarch64-linux-gnu
main: llama backend init
main: load the model and apply lora adapter, if any
llama_model_loader: loaded meta data with 35 key-value pairs and 434 tensors from asserts/Qwen2.5-3B-Instruct-Q4_0.gguf (version GGUF V3 (latest))
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv   0:                       general.architecture str              = qwen2
llama_model_loader: - kv   1:                               general.type str              = model
llama_model_loader: - kv   2:                               general.name str              = Qwen2.5 3B Instruct
llama_model_loader: - kv   3:                           general.finetune str              = Instruct
llama_model_loader: - kv   4:                           general.basename str              = Qwen2.5
llama_model_loader: - kv   5:                         general.size_label str              = 3B
llama_model_loader: - kv   6:                            general.license str              = other
llama_model_loader: - kv   7:                       general.license.name str              = qwen-research
llama_model_loader: - kv   8:                       general.license.link str              = https://huggingface.co/Qwen/Qwen2.5-3...
llama_model_loader: - kv   9:                   general.base_model.count u32              = 1
llama_model_loader: - kv  10:                  general.base_model.0.name str              = Qwen2.5 3B
llama_model_loader: - kv  11:          general.base_model.0.organization str              = Qwen
llama_model_loader: - kv  12:              general.base_model.0.repo_url str              = https://huggingface.co/Qwen/Qwen2.5-3B
llama_model_loader: - kv  13:                               general.tags arr[str,2]       = ["chat", "text-generation"]
llama_model_loader: - kv  14:                          general.languages arr[str,1]       = ["en"]
llama_model_loader: - kv  15:                          qwen2.block_count u32              = 36
llama_model_loader: - kv  16:                       qwen2.context_length u32              = 32768
llama_model_loader: - kv  17:                     qwen2.embedding_length u32              = 2048
llama_model_loader: - kv  18:                  qwen2.feed_forward_length u32              = 11008
llama_model_loader: - kv  19:                 qwen2.attention.head_count u32              = 16
llama_model_loader: - kv  20:              qwen2.attention.head_count_kv u32              = 2
llama_model_loader: - kv  21:                       qwen2.rope.freq_base f32              = 1000000.000000
llama_model_loader: - kv  22:     qwen2.attention.layer_norm_rms_epsilon f32              = 0.000001
llama_model_loader: - kv  23:                       tokenizer.ggml.model str              = gpt2
llama_model_loader: - kv  24:                         tokenizer.ggml.pre str              = qwen2
llama_model_loader: - kv  25:                      tokenizer.ggml.tokens arr[str,151936]  = ["!", "\"", "#", "$", "%", "&", "'", ...
llama_model_loader: - kv  26:                  tokenizer.ggml.token_type arr[i32,151936]  = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
llama_model_loader: - kv  27:                      tokenizer.ggml.merges arr[str,151387]  = ["Ġ Ġ", "ĠĠ ĠĠ", "i n", "Ġ t",...
llama_model_loader: - kv  28:                tokenizer.ggml.eos_token_id u32              = 151645
llama_model_loader: - kv  29:            tokenizer.ggml.padding_token_id u32              = 151643
llama_model_loader: - kv  30:                tokenizer.ggml.bos_token_id u32              = 151643
llama_model_loader: - kv  31:               tokenizer.ggml.add_bos_token bool             = false
llama_model_loader: - kv  32:                    tokenizer.chat_template str              = {%- if tools %}\n    {{- '<|im_start|>...
llama_model_loader: - kv  33:               general.quantization_version u32              = 2
llama_model_loader: - kv  34:                          general.file_type u32              = 2
llama_model_loader: - type  f32:  181 tensors
llama_model_loader: - type q4_0:  252 tensors
llama_model_loader: - type q6_K:    1 tensors
print_info: file format = GGUF V3 (latest)
print_info: file type   = Q4_0
print_info: file size   = 1.69 GiB (4.71 BPW) 
load: special tokens cache size = 22
load: token to piece cache size = 0.9310 MB
print_info: arch             = qwen2
print_info: vocab_only       = 0
print_info: n_ctx_train      = 32768
print_info: n_embd           = 2048
print_info: n_layer          = 36
print_info: n_head           = 16
print_info: n_head_kv        = 2
print_info: n_rot            = 128
print_info: n_swa            = 0
print_info: n_swa_pattern    = 1
print_info: n_embd_head_k    = 128
print_info: n_embd_head_v    = 128
print_info: n_gqa            = 8
print_info: n_embd_k_gqa     = 256
print_info: n_embd_v_gqa     = 256
print_info: f_norm_eps       = 0.0e+00
print_info: f_norm_rms_eps   = 1.0e-06
print_info: f_clamp_kqv      = 0.0e+00
print_info: f_max_alibi_bias = 0.0e+00
print_info: f_logit_scale    = 0.0e+00
print_info: f_attn_scale     = 0.0e+00
print_info: n_ff             = 11008
print_info: n_expert         = 0
print_info: n_expert_used    = 0
print_info: causal attn      = 1
print_info: pooling type     = 0
print_info: rope type        = 2
print_info: rope scaling     = linear
print_info: freq_base_train  = 1000000.0
print_info: freq_scale_train = 1
print_info: n_ctx_orig_yarn  = 32768
print_info: rope_finetuned   = unknown
print_info: ssm_d_conv       = 0
print_info: ssm_d_inner      = 0
print_info: ssm_d_state      = 0
print_info: ssm_dt_rank      = 0
print_info: ssm_dt_b_c_rms   = 0
print_info: model type       = 3B
print_info: model params     = 3.09 B
print_info: general.name     = Qwen2.5 3B Instruct
print_info: vocab type       = BPE
print_info: n_vocab          = 151936
print_info: n_merges         = 151387
print_info: BOS token        = 151643 '<|endoftext|>'
print_info: EOS token        = 151645 '<|im_end|>'
print_info: EOT token        = 151645 '<|im_end|>'
print_info: PAD token        = 151643 '<|endoftext|>'
print_info: LF token         = 198 'Ċ'
print_info: FIM PRE token    = 151659 '<|fim_prefix|>'
print_info: FIM SUF token    = 151661 '<|fim_suffix|>'
print_info: FIM MID token    = 151660 '<|fim_middle|>'
print_info: FIM PAD token    = 151662 '<|fim_pad|>'
print_info: FIM REP token    = 151663 '<|repo_name|>'
print_info: FIM SEP token    = 151664 '<|file_sep|>'
print_info: EOG token        = 151643 '<|endoftext|>'
print_info: EOG token        = 151645 '<|im_end|>'
print_info: EOG token        = 151662 '<|fim_pad|>'
print_info: EOG token        = 151663 '<|repo_name|>'
print_info: EOG token        = 151664 '<|file_sep|>'
print_info: max token length = 256
load_tensors: loading model tensors, this can take a while... (mmap = true)
load_tensors:   CPU_Mapped model buffer size =  1720.63 MiB
load_tensors: CPU_KLEIDIAI model buffer size =  1488.38 MiB
.......................................................................................
llama_context: constructing llama_context
llama_context: n_seq_max     = 1
llama_context: n_ctx         = 4096
llama_context: n_ctx_per_seq = 4096
llama_context: n_batch       = 2048
llama_context: n_ubatch      = 512
llama_context: causal_attn   = 1
llama_context: flash_attn    = 0
llama_context: freq_base     = 1000000.0
llama_context: freq_scale    = 1
llama_context: n_ctx_per_seq (4096) < n_ctx_train (32768) -- the full capacity of the model will not be utilized
llama_context:        CPU  output buffer size =     0.58 MiB
init: kv_size = 4096, offload = 1, type_k = 'f16', type_v = 'f16', n_layer = 36, can_shift = 1
init:        CPU KV buffer size =   144.00 MiB
llama_context: KV self size  =  144.00 MiB, K (f16):   72.00 MiB, V (f16):   72.00 MiB
llama_context:        CPU compute buffer size =   300.75 MiB
llama_context: graph nodes  = 1338
llama_context: graph splits = 1
common_init_from_params: setting dry_penalty_last_n to ctx_size = 4096
common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)
main: llama threadpool init, n_threads = 8
main: chat template example:
<|im_start|>system
You are a helpful assistant<|im_end|>
<|im_start|>user
Hello<|im_end|>
<|im_start|>assistant
Hi there<|im_end|>
<|im_start|>user
How are you?<|im_end|>
<|im_start|>assistantsystem_info: n_threads = 8 (n_threads_batch = 8) / 12 | CPU : NEON = 1 | ARM_FMA = 1 | FP16_VA = 1 | MATMUL_INT8 = 1 | SVE = 1 | DOTPROD = 1 | SVE_CNT = 16 | OPENMP = 1 | KLEIDIAI = 1 | AARCH64_REPACK = 1 | main: interactive mode on.
sampler seed: 3948005486
sampler params: repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = 4096top_k = 40, top_p = 0.950, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.800mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000
sampler chain: logits -> logit-bias -> penalties -> dry -> top-k -> typical -> top-p -> min-p -> xtc -> temp-ext -> dist 
generate: n_ctx = 4096, n_batch = 2048, n_predict = -1, n_keep = 0== Running in interactive mode. ==- Press Ctrl+C to interject at any time.- Press Return to return control to the AI.- To return control without starting a new line, end your input with '/'.- If you want to submit another line, end your input with '\'.- Not using system message. To change it, set a different value via -sys PROMPT

问题
但是这样编译出来的可执行程序,执行测试的时候,模型效果是有问题,还需要排查。

./build_kle/bin/llama-cli -m asserts/Qwen2.5-3B-Instruct-Q4_0.gguf -c 4096 -t 8 --conversation## 打印
> hello
共和国owan続きMAR composition composition分 mutationorphAug AovOransition""""""""""" "" "" "amyamy.tom Entriesreta_suffix"卫生ventions警MessageBox

4.总结

同样的硬件,同样的模型,从上面的评测可以看到开启了kleidiai相较于armv9在prefill阶段提升了54.49%, decode阶段略有下降13.37。

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

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

相关文章

wireshark抓包也能被篡改?

wireshark本身并不能修改数据包&#xff0c;但是tcprewrite 可以修改数据包&#xff0c;然后通过tcpreplay 进行重放&#xff0c;这个时候wireshark抓的包&#xff0c;就是被篡改后的pcap包了。 ailx10 网络安全优秀回答者 互联网行业 安全攻防员 去咨询 步骤一&#xff1a…

使用PyTorch进行热狗图像分类模型微调

本教程将演示如何使用PyTorch框架对预训练模型进行微调&#xff0c;实现热狗与非热狗图像的分类任务。我们将从数据准备开始&#xff0c;逐步完成数据加载、可视化等关键步骤。 1. 环境配置与库导入 %matplotlib inline import os import torch from torch import nn from d2l…

内容中台与企业内容管理核心差异剖析

功能定位与架构设计差异 在企业数字化进程中&#xff0c;内容中台与企业内容管理&#xff08;ECM&#xff09;的核心差异首先体现在功能定位层面。传统ECM系统以文档存储、版本控制及权限管理为核心&#xff0c;主要服务于企业内部知识库的静态管理需求&#xff0c;例如通过Ba…

使用PyMongo连接MongoDB的基本操作

MongoDB是由C语言编写的非关系型数据库&#xff0c;是一个基于分布式文件存储的开源数据库系统&#xff0c;其内容存储形式类似JSON对象&#xff0c;它的字段值可以包含其他文档、数组及文档数组。在这一节中&#xff0c;我们就来回顾Python 3下MongoDB的存储操作。 常用命令:…

第 12 届蓝桥杯 C++ 青少组中 / 高级组省赛 2021 年真题

一、选择题 第 1 题 题目&#xff1a;下列符号中哪个在 C 中表示行注释 ( )。 A. ! B. # C. ] D. // 正确答案&#xff1a;D 答案解析&#xff1a; 在 C 中&#xff0c;//用于单行注释&#xff08;行注释&#xff09;&#xff0c;从//开始到行末的内容会被编译器忽略。选项 A…

【python】【UV】一篇文章学完新一代 Python 环境与包管理器使用指南

&#x1f40d; UV&#xff1a;新一代 Python 环境与包管理器使用指南 一、UV 是什么&#xff1f; UV 是由 Astral 团队开发的高性能 Python 环境管理器&#xff0c;旨在统一替代 pyenv、pip、venv、pip-tools、pipenv 等工具。 1.1 UV 的主要功能 &#x1f680; 极速包安装&…

前端性能优化2:结合HTTPS与最佳实践,全面优化你的网站性能

点亮极速体验&#xff1a;结合HTTPS与最佳实践&#xff0c;为你详解网站性能优化的道与术 在如今这个信息爆炸、用户耐心极其有限的数字时代&#xff0c;网站的性能早已不是一个可选项&#xff0c;而是关乎生存和发展的核心竞争力。一个迟缓的网站&#xff0c;无异于在数字世界…

JavaWeb:vueaxios

一、简介 什么是vue? 快速入门 <!-- 3.准备视图元素 --><div id"app"><!-- 6.数据渲染 --><h1>{{ msg }}</h1></div><script type"module">// 1.引入vueimport { createApp, ref } from https://unpkg.com/vu…

Tauri联合Vue开发中Vuex与Pinia关系及前景分析

在 TauriVue 的开发场景中&#xff0c;Vuex 和 Pinia 是两种不同的状态管理工具&#xff0c;它们的关系和前景可以从以下角度分析&#xff1a; 一、Vuex 与 Pinia 的关系 继承与发展 Pinia 最初是作为 Vuex 5 的提案设计的&#xff0c;其目标是简化 Vuex 的复杂性并更好地适配 …

Linux中的时间同步

一、时间同步服务扩展总结 1. 时间同步的重要性 多主机协作需求&#xff1a;在分布式系统、集群、微服务架构中&#xff0c;时间一致性是日志排序、事务顺序、数据一致性的基础。 安全协议依赖&#xff1a;TLS/SSL证书、Kerberos认证等依赖时间有效性&#xff0c;时间偏差可能…

【算法基础】三指针排序算法 - JAVA

一、基础概念 1.1 什么是三指针排序 三指针排序是一种特殊的分区排序算法&#xff0c;通过使用三个指针同时操作数组&#xff0c;将元素按照特定规则进行分类和排序。这种算法在处理包含有限种类值的数组时表现出色&#xff0c;最经典的应用是荷兰国旗问题&#xff08;Dutch …

《操作系统真象还原》第十二章(2)——进一步完善内核

文章目录 前言可变参数的原理实现系统调用write更新syscall.h更新syscall.c更新syscall-init.c 实现printf编写stdio.h编写stdio.c 第一次测试main.cmakefile结果截图 完善printf修改main.c 结语 前言 上部分链接&#xff1a;《操作系统真象还原》第十二章&#xff08;1&#…

ICML2021 | DeiT | 训练数据高效的图像 Transformer 与基于注意力的蒸馏

Training data-efficient image transformers & distillation through attention 摘要-Abstract引言-Introduction相关工作-Related Work视觉Transformer&#xff1a;概述-Vision transformer: overview通过注意力机制蒸馏-Distillation through attention实验-Experiments…

深度学习:AI 机器人时代

在科技飞速发展的当下&#xff0c;AI 机器人时代正以汹涌之势席卷而来&#xff0c;而深度学习作为其核心驱动力&#xff0c;正重塑着我们生活与工作的方方面面。 从智能工厂的自动化生产&#xff0c;到家庭中贴心服务的智能助手&#xff0c;再到复杂环境下执行特殊任务的专业机…

《告别试错式开发:TDD的精准质量锻造术》

深度解锁TDD&#xff1a;应用开发的创新密钥 在应用开发的复杂版图中&#xff0c;如何雕琢出高质量、高可靠性的应用&#xff0c;始终是开发者们不懈探索的核心命题。测试驱动开发&#xff08;TDD&#xff09;&#xff0c;作为一种颠覆性的开发理念与方法&#xff0c;正逐渐成…

应用层自定义协议序列与反序列化

目录 一、网络版计算器 二、网络版本计算器实现 2.1源代码 2.2测试结果 一、网络版计算器 应用层定义的协议&#xff1a; 应用层进行网络通信能否使用如下的协议进行通信呢&#xff1f; 在操作系统内核中是以这种协议进行通信的&#xff0c;但是在应用层禁止以这种协议进行…

Excel-CLI:终端中的轻量级Excel查看器

在数据驱动的今天&#xff0c;Excel 文件处理成为了我们日常工作中不可或缺的一部分。然而&#xff0c;频繁地在图形界面与命令行界面之间切换&#xff0c;不仅效率低下&#xff0c;而且容易出错。现在&#xff0c;有了 Excel-CLI&#xff0c;一款运行在终端中的轻量级Excel查看…

百度后端开发一面

mutex, rwmutex 在Go语言中&#xff0c;Mutex&#xff08;互斥锁&#xff09;和RWMutex&#xff08;读写锁&#xff09;是用于管理并发访问共享资源的核心工具。以下是它们的常见问题、使用场景及最佳实践总结&#xff1a; 1. Mutex 与 RWMutex 的区别 Mutex: 互斥锁&#xf…

STM32 IIC总线

目录 IIC协议简介 IIC总线系统结构 IIC总线物理层特点 IIC总线协议层 空闲状态 应答信号 数据的有效性 数据传输 STM32的IIC特性及架构 STM32的IIC结构体 0.96寸OLED显示屏 SSD1306框图及引脚定义 4针脚I2C接口模块原理图 字节传输-I2C 执行逻辑框图 命令表…

【unity游戏开发入门到精通——UGUI】整体控制一个UGUI面板的淡入淡出——CanvasGroup画布组组件的使用

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发——UGUI】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言CanvasGroup画布组组件参数 实战专栏推荐完结 前言 如果我们想要整体控制…