恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
ARM 与 NEON 实战指南:为移动端与服务器编写高速 SIMD 内核(Maths, CS AI Compendium 第 16 章)
首页
资讯中心
/
ARM 与 NEON 实战指南:为移动端与服务器编写高速 SIMD 内核(Maths, CS AI Compendium 第 16 章)
ARM 与 NEON 实战指南:为移动端与服务器编写高速 SIMD 内核(Maths, CS AI Compendium 第 16 章)
发布时间:2026/9/17 4:08:58
ARM 与 NEON 实战指南为移动端与服务器编写高速 SIMD 内核Maths, CS AI Compendium 第 16 章【免费下载链接】maths-cs-ai-compendiumBecome a cracked AI/ML researcher/engineer with this unconventional textbook covering maths, computing, and ML with intuition.项目地址: https://gitcode.com/GitHub_Trending/mat/maths-cs-ai-compendium本指南以 chapter 16 - SIMD and GPU programming/02. ARM and NEON.md 为主体展开覆盖 ARM 架构基础、NEON 128 位 SIMD 内建函数编程、I8MM 整数矩阵乘、SVE/SVE2 可扩展向量、SME 矩阵扩展、Apple Silicon 特性与编译器自动向量化并附带三个可直接编译运行的 NEON 实验。读完本文你将掌握在 Mac M 系列或 Linux aarch64 上用 C 内建函数写出可落地到点积、ReLU、矩阵乘法等 ML 内核的 SIMD 代码并理解 NEON → I8MM → SVE → SME 的硬件演进如何一步步逼近原生矩阵运算。ARM 处理器驱动着每一部智能手机、大部分平板、Apple 的笔记本电脑以及越来越多的数据中心服务器。如果你拥有 iPhone、MacBook或使用 AWS Graviton 实例你就在运行 ARM。ARM 的能效优势使其在移动与嵌入式领域占据统治地位并在服务器与 ML 推理场景中越来越有竞争力。理解 ARM SIMD意味着你能在大多数人实际使用的硬件上写出跑得更快的代码——而本仓库Maths, CS AI Compendium正是把这条从 Python 到 C 再到硬件的链路讲透的一本非常规教科书。为什么 ARM 值得你掌握能效驱动的格局变迁在深入代码之前先理解 ARM 为何重要。本仓库 chapter 16 - SIMD and GPU programming/01. hardware fundamentals.md 指出2005 年前后 CPU 频率触及约 4GHz 的功耗墙功耗 $P \propto C \cdot V^2 \cdot f$此后性能增长只能靠并行多核、更宽的 SIMD 单元、GPU 大规模并行。而在并行时代的竞争中能效FLOPS/watt日益成为比裸 FLOPS 更关键的指标这正是 ARM 拿下数据中心的根本原因ARM 的 FLOPS/watt 优于 x86Apple M4 更是在单核性能比肩 Intel 的同时功耗只有其零头。从 SIMD 指令宽度看ARM 处于什么位置硬件基础章节 给出的矢量寄存器全景是寄存器宽度32 位浮点数64 位双精度名称128 位42SSEx86、NEONARM256 位84AVX/AVX2x86512 位168AVX-512x86可变128–2048 位可变可变SVE/SVE2ARMNEON 的 128 位宽度窄于 x86 的 AVX256 位与 AVX-512512 位但 ARM 以出色的能效和极广的部署面作为补偿。对于 ML 而言这组指令宽度的意义在于矩阵乘法内层循环点积直接映射为 SIMD 乘加指令这正是 NumPy/PyTorch 底层调用的 BLAS 库被 SIMD 重度优化的原因参见 chapter 16 - SIMD and GPU programming/00. why C and how ML frameworks work.md 中 NumPy → BLAS → SIMD 的调用链。ARM 架构基础RISC、定长指令与寄存器文件ARM 是RISC精简指令集计算机架构RISC 与 CISC 对比详见 chapter 13 - computing and OS/02. computer architecture.md核心特征如下Load-store 架构算术指令只操作寄存器绝不直接操作内存。要把内存中的两个数相加必须 (1) 装入寄存器(2) 相加(3) 存回内存。这比 x86一条指令即可完成寄存器与内存相加更简单但流水线更干净。定宽指令ARMv8AArch64的每条指令恰好 32 位解码快速且可预测x86 变长指令可达 1–15 字节。32 个通用寄存器x0–x30各 64 位外加栈指针 sp 与零寄存器 xzr。对比 x86 的 16 个通用寄存器——寄存器越多内存访问越少代码越快。32 个 SIMD/浮点寄存器v0–v31各 128 位用于 NEON 与浮点运算。// ARM 汇编仅观感——实际编程你用的是内建函数不是汇编 // 两个寄存器相加 add x0, x1, x2 // x0 x1 x2 // 从内存加载 ldr x0, [x1] // x0 *x1从 x1 指向的地址加载 64 位 // NEON四个浮点相加 fadd v0.4s, v1.4s, v2.4s // v0 v1 v2四个 32 位浮点你不会去写汇编。你会使用内建函数intrinsicsC/C 中与具体指令一一对应的函数。编译器负责寄存器分配、指令调度等底层细节。NEON128 位 SIMD 与内建函数基础NEON是 ARM 的 SIMD 扩展每个 NEON 寄存器宽 128 位可容纳数据类型每寄存器元素数记号float324float32x4_tfloat168float16x8_tint324int32x4_tint168int16x8_tint816int8x16_tNEON 内建函数遵循v[操作][限定符]_[类型]的命名约定#include arm_neon.h // 从内存加载 4 个 float 到 NEON 寄存器 float32x4_t a vld1q_f32(ptr); // vld1q 向量加载 1q 128 位quad // 将 NEON 寄存器中的 4 个 float 存回内存 vst1q_f32(out_ptr, a); // vst1q 向量存储 1q 128 位 // 算术 float32x4_t c vaddq_f32(a, b); // c a b4 个 float float32x4_t d vmulq_f32(a, b); // d a * b4 个 float float32x4_t e vfmaq_f32(c, a, b); // e c a * b融合乘加4 个 float // 比较返回掩码真则全 1假则全 0 uint32x4_t mask vcgtq_f32(a, b); // mask[i] (a[i] b[i]) ? 0xFFFFFFFF : 0 // 按掩码选择元素类似 numpy.where float32x4_t result vbslq_f32(mask, a, b); // result[i] mask[i] ? a[i] : b[i] // 归约将 4 个元素求和为标量 float total vaddvq_f32(a); // total a[0] a[1] a[2] a[3]vfmaq_f32融合乘加是 ML 最重要的 SIMD 指令它在一条指令内计算 $c c a \times b$且只做一次舍入比先乘后加更精确。点积、矩阵乘法、卷积全部由 FMA 构建。实战一向量化点积点积是矩阵乘法的内层循环。先写标量 C 版本再用 NEON 向量化#include arm_neon.h // 标量点积 float dot_scalar(const float* a, const float* b, int n) { float sum 0.0f; for (int i 0; i n; i) { sum a[i] * b[i]; } return sum; } // NEON 向量化点积 float dot_neon(const float* a, const float* b, int n) { float32x4_t sum_vec vdupq_n_f32(0.0f); // 将 4 个累加器初始化为 0 int i 0; for (; i 4 n; i 4) { float32x4_t va vld1q_f32(a i); // 从 a 加载 4 个元素 float32x4_t vb vld1q_f32(b i); // 从 b 加载 4 个元素 sum_vec vfmaq_f32(sum_vec, va, vb); // sum_vec va * vb } // 将 4 个累加器归约为标量 float sum vaddvq_f32(sum_vec); // 处理剩余元素当 n 不是 4 的倍数时 for (; i n; i) { sum a[i] * b[i]; } return sum; }关键 C 概念const float*指向只读 float 数据的指针const承诺不会通过该指针修改数据。a i指针算术。a i指向数组第 $i$ 个元素等价于a[i]。结尾的清理循环处理 $n$ 不是 4 的倍数的情况——这是 SIMD 代码的通用模式主体用向量化块处理余数用标量代码收尾。为什么sum_vec用 4 个累加器与其用单个标量累加器不如用 4 个相互独立的累加器每个 SIMD 通道一个。这消除了数据依赖每次迭代的 FMA 都依赖sum_vec但 4 条独立通道让 CPU 可以对 FMA 流水化。最后再把 4 个部分和归约成 1 个。实战二向量化 ReLU#include arm_neon.h void relu_neon(const float* input, float* output, int n) { float32x4_t zero vdupq_n_f32(0.0f); int i 0; for (; i 4 n; i 4) { float32x4_t x vld1q_f32(input i); float32x4_t result vmaxq_f32(x, zero); // max(x, 0) ReLU vst1q_f32(output i, result); } // 标量清理 for (; i n; i) { output[i] input[i] 0 ? input[i] : 0; } }vmaxq_f32计算两个向量的逐元素最大值。由于其中一个向量全为 0这恰好就是 ReLU无分支、无比较只有一条指令。注意ReLU、加法这类逐元素操作算术强度低每加载一个字节只做 1 次运算属于memory-bound内存受限——按硬件基础章节 的 roofline 模型它们受内存带宽约束而非算力约束这也是内核融合kernel fusion如此重要的原因。I8MM整数矩阵乘指令I8MMInt8 Matrix Multiply是 ARMv8.6 扩展为 INT8 矩阵乘法INT32 累加提供了专用指令——这正是量化 ML 推理所需的。关键指令是SMMLASigned Matrix Multiply-Accumulate取两个 8×2 的 INT8 块将结果累加进一个 2×2 的 INT32 块#include arm_neon.h // I8MM两个 8 元素 INT8 向量相乘累加进 4 个 INT32 结果 // 该函数由 2x8 × 8x2 输入块计算输出矩阵的一个 2x2 瓦片 void matmul_i8mm_tile(const int8_t* A, const int8_t* B, int32_t* C) { // 从 A 加载 16 字节2 行 × 8 元素打包存放 int8x16_t va vld1q_s8(A); // 16 字节 2 行 × 8 元素 int8x16_t vb vld1q_s8(B); // 16 字节 2 行 × 8 元素 // 加载已有累加器2x2 4 个 int32 值 int32x4_t acc vld1q_s32(C); // I8MM 指令acc A_tile × B_tile^T // 由 2×8 × 8×2 输入计算 2×2 输出 acc vmmlaq_s32(acc, va, vb); // I8MM 指令 vst1q_s32(C, acc); }为什么 I8MM 重要没有 I8MM 时NEON 上的 INT8 矩阵乘法需要拓宽乘法vmull再配对相加——每个输出元素要好几条指令。有了 I8MM硬件在单条指令内完成 8 元素点积2×8 × 8×2 2×2。对 INT8 推理负载这比普通 NEON 快4–8 倍。可用性Apple M1全部 Apple Silicon、ARM Cortex-A510/A710/X2ARMv9、AWS Graviton3。运行时用#ifdef __ARM_FEATURE_MATMUL_INT8检测。对 ML 推理而言运行在 ARM 服务器Graviton或 Apple Silicon 上的 INT8 量化模型量化原理详见 chapter 17 - AI inference/01. quantisation.md其中解释了 INT8 相对 FP16 的 2 倍吞吐与近线性带宽收益会极大受益于 I8MM。ONNX Runtime、llama.cpp 等框架会在运行时检测 I8MM 并自动使用优化内核——chapter 17 - AI inference/04. edge inference.md 也明确指出 llama.cpp 在 CPU 端支持 AVX2、NEON 与 I8MM是消费级硬件跑 LLM 的首选。SVE 与 SVE2可扩展向量扩展NEON 宽度固定为 128 位。SVEScalable Vector Extension引入**与向量长度无关VLA**的编程方式代码只写一次可在任意向量宽度128 到 2048 位的硬件上运行宽度由硬件在运行时决定。#include arm_sve.h void add_sve(const float* a, const float* b, float* c, int n) { int i 0; svbool_t pred svwhilelt_b32(i, n); // 谓词哪些通道是激活的 while (svptest_any(svptrue_b32(), pred)) { svfloat32_t va svld1(pred, a i); svfloat32_t vb svld1(pred, b i); svst1(pred, c i, svadd_x(pred, va, vb)); i svcntw(); // 按硬件向量宽度推进以 32 位元素计 pred svwhilelt_b32(i, n); } }谓词寄存器svbool_t取代了标量清理循环。每个通道有一个谓词位激活通道参与运算未激活通道被屏蔽。svwhilelt_b32(i, n)创建的谓词使i, i1, ..., n-1对应的通道激活自动处理尾部数据。svcntw()在运行时返回每个向量寄存器容纳的 32 位元素数256 位 SVE 的 CPU 返回 8512 位返回 16。你的代码自动适配。SVE 目前见于 ARM Neoverse V1/V2AWS Graviton3/4 及部分服务器芯片Apple Silicon 尚不支持。SME 与 SME2可扩展矩阵扩展SMEScalable Matrix Extension是 ARM 对标 Intel AMX 与 NVIDIA Tensor Core 的方案为矩阵运算配备专用硬件。SME2ARMv9.2进一步扩展。SME 引入ZA 瓦片寄存器硬件中存储的二维矩阵尺寸最大可达 SVL×SVL 字节SVL 为流式向量长度通常每个维度 128–512 位。与 NEON一维向量乃至 SVE一维可扩展向量不同SME 原生操作二维瓦片。编程模型有两种模式普通模式标准 ARM 执行NEON、SVE 照常工作。流式 SVE 模式通过smstart进入启用 SME 指令。SVE 指令在该模式下也可用但寄存器宽度可能不同。#include arm_sme.h // SME2用于矩阵乘法的外积累加 // 将 A_col × B_row 累加进 ZA 瓦片寄存器 void sme2_matmul_outer(const float* A_col, const float* B_row, int K) { // 进入流式模式 // smstart; //通过编译器内建函数或内联汇编完成 // 将 ZA 瓦片累加器清零 svzero_za(); for (int k 0; k K; k) { // 将 A 的一列与 B 的一行加载进 SVE 寄存器 svfloat32_t a svld1_f32(svptrue_b32(), A_col[k * SVL]); svfloat32_t b svld1_f32(svptrue_b32(), B_row[k * SVL]); // 外积ZA a × b^T // 一条指令累加一个 SVL×SVL 瓦片 svmopa_za32_f32_m(0, svptrue_b32(), svptrue_b32(), a, b); } // 将 ZA 瓦片存回内存 // svst1_za(...); // 退出流式模式 // smstop; }关键概念svmopa外积累加是 SME 的核心指令计算两个向量的完整外积并累加进 ZA 瓦片。当 SVL512 位16 个 float时这是 16×16 的外积——一条指令执行 256 次 FMA。ZA 瓦片在流式模式内跨指令持续存在。你可以把多个外积每个 K 迭代一个累加进同一瓦片逐步构建完整的矩阵乘法瓦片。流式模式SME 指令只在流式模式下工作。进出流式模式的开销意味着 SME 最适合持续的矩阵计算而非短促的计算突刺。SME2 新增多向量操作同时处理 2 或 4 个 SVE 向量、更多瓦片操作以及与普通模式的更好集成。可用性ARM Neoverse V2AWS Graviton4及部分即将推出的移动芯片Apple Silicon 尚不支持截至 2026 年。SME 仍处于早期多数 ML 框架还没有 SME 优化内核。演进脉络NEON128 位向量逐元素→ I8MMINT8 矩阵瓦片→ SVE可扩展向量→ SME可扩展二维矩阵瓦片。每一代都更接近硬件上的原生矩阵运算。Apple Silicon 特性Apple M 系列芯片M1、M2、M3、M4基于 ARM 但采用定制微架构性能核与能效核P 核Firestorm/Avalanche 等负责重计算E 核Icestorm/Blizzard 等处理后台任务由调度器把线程分配到合适的内核类型。AMXApple Matrix eXtensions独立于 NEON 的专用矩阵乘单元。AMX 未公开文档Apple 不发布 ISA但 Accelerate 框架在内部使用它实现 BLAS 操作。在 Mac 上调用np.dot会经由 Accelerate 使用 AMX。你无法直接对 AMX 编程除非逆向。统一内存CPU 与 GPU 共享同一物理 RAM。其他平台上数据须经 PCIe约 32 GB/s从 CPU 内存拷贝到 GPU 内存Apple Silicon 上无需拷贝——GPU 直接读取 CPU 写好的同一块内存。这消除了 ML 负载的一大瓶颈。神经引擎Neural Engine16 核专用 ML 加速器INT8 推理约 30 TOPS每秒万亿次运算被 Core ML 用于端侧推理。Apple Silicon 上的 ML 建议使用 MLXApple 面向统一内存架构设计的 ML 框架PyTorch 也有 MPSMetal Performance Shaders后端但成熟度不如 CUDA。自动向量化让编译器替你写 SIMD手写 SIMD 内建函数很繁琐。编译器能自动向量化你的代码吗能但有前提。现代编译器GCC、Clang可以自动向量化简单循环// 编译器可以自动向量化这段代码配合 -O3 -marchnative void add_auto(const float* a, const float* b, float* c, int n) { for (int i 0; i n; i) { c[i] a[i] b[i]; } }有助于自动向量化的模式循环次数可预知的简单循环。迭代之间无数据依赖c[i]不依赖c[i-1]。连续内存访问无 scatter/gather。const与restrict指针告知编译器数组不重叠。// restrict 告诉编译器a、b、c 指向不重叠的内存 void add_restrict(const float* __restrict__ a, const float* __restrict__ b, float* __restrict__ c, int n) { for (int i 0; i n; i) { c[i] a[i] b[i]; } }没有restrict时编译器必须假设c可能与a或b重叠写c[i]可能改变a[i1]从而阻止向量化。阻碍自动向量化的模式数据依赖a[i] a[i-1] b[i]每次迭代依赖上一次。循环内复杂控制流if语句除非编译器能转成谓词化执行。循环内函数调用除非函数被内联。指针别名数组可能重叠且没有restrict。检查自动向量化——用编译器标志查看哪些循环被向量化了# GCC展示向量化决策 g -O3 -marchnative -fopt-info-vec-optimized code.cpp # Clang展示向量化报告 clang -O3 -marchnative -Rpassloop-vectorize code.cpp内建函数 vs 自动向量化的取舍先从干净的 C 与编译器优化入手。如果编译器已向量化你的循环很好若性能仍不足先查看向量化报告理解原因再只为关键内层循环手写内建函数。过早手写内建函数只会让代码难以阅读且没有保证的收益。有趣的是x86/AVX 章节 展示了同一思路的对照实现AVX2 点积每次迭代处理 8 个 float而 NEON 是 4 个——对长向量这是约 2 倍的吞吐差异忽略内存带宽限制。动手实践三个可运行的 NEON 实验以下三个任务请用 g 或 clang 在 ARM 环境Mac M 系列或 Linux aarch64编译运行。任务 1标量 vs NEON 点积基准测试// task1_neon_dot.cpp // 编译Mac/ARM Linuxclang -O3 -o task1 task1_neon_dot.cpp // 注意AArch64 上 NEON 默认开启无需特殊编译选项 #include iostream #include chrono #include vector #include arm_neon.h float dot_scalar(const float* a, const float* b, int n) { float sum 0.0f; for (int i 0; i n; i) { sum a[i] * b[i]; } return sum; } float dot_neon(const float* a, const float* b, int n) { float32x4_t sum_vec vdupq_n_f32(0.0f); int i 0; for (; i 4 n; i 4) { float32x4_t va vld1q_f32(a i); float32x4_t vb vld1q_f32(b i); sum_vec vfmaq_f32(sum_vec, va, vb); } float sum vaddvq_f32(sum_vec); for (; i n; i) sum a[i] * b[i]; return sum; } int main() { const int N 10000000; std::vectorfloat a(N, 1.0f), b(N, 2.0f); // 预热 volatile float s1 dot_scalar(a.data(), b.data(), N); volatile float s2 dot_neon(a.data(), b.data(), N); // 基准标量 auto start std::chrono::high_resolution_clock::now(); for (int t 0; t 100; t) { s1 dot_scalar(a.data(), b.data(), N); } auto end std::chrono::high_resolution_clock::now(); double scalar_ms std::chrono::durationdouble, std::milli(end - start).count() / 100; // 基准NEON start std::chrono::high_resolution_clock::now(); for (int t 0; t 100; t) { s2 dot_neon(a.data(), b.data(), N); } end std::chrono::high_resolution_clock::now(); double neon_ms std::chrono::durationdouble, std::milli(end - start).count() / 100; std::cout Scalar: scalar_ms ms (result: s1 )\n; std::cout NEON: neon_ms ms (result: s2 )\n; std::cout Speedup: scalar_ms / neon_ms x\n; return 0; }任务 2NEON ReLU 与求最大值// task2_neon_ops.cpp // 编译clang -O3 -o task2 task2_neon_ops.cpp #include iostream #include vector #include cmath #include arm_neon.h void relu_neon(const float* in, float* out, int n) { float32x4_t zero vdupq_n_f32(0.0f); int i 0; for (; i 4 n; i 4) { float32x4_t x vld1q_f32(in i); vst1q_f32(out i, vmaxq_f32(x, zero)); } for (; i n; i) out[i] in[i] 0 ? in[i] : 0; } float max_neon(const float* data, int n) { float32x4_t max_vec vdupq_n_f32(-INFINITY); int i 0; for (; i 4 n; i 4) { max_vec vmaxq_f32(max_vec, vld1q_f32(data i)); } float result vmaxvq_f32(max_vec); for (; i n; i) result result data[i] ? result : data[i]; return result; } int main() { std::vectorfloat data {-3, 1, -1, 4, 2, -5, 0, 7, -2, 3}; std::vectorfloat out(data.size()); relu_neon(data.data(), out.data(), data.size()); std::cout ReLU: ; for (float x : out) std::cout x ; std::cout \n; float mx max_neon(data.data(), data.size()); std::cout Max: mx (expected: 7)\n; return 0; }任务 3自动向量化 vs 手写 NEON// task3_auto_vs_manual.cpp // 编译clang -O3 -Rpassloop-vectorize -o task3 task3_auto_vs_manual.cpp // 或g -O3 -fopt-info-vec-optimized -o task3 task3_auto_vs_manual.cpp #include iostream #include chrono #include vector #include arm_neon.h // 让编译器自动向量化 void add_auto(const float* __restrict__ a, const float* __restrict__ b, float* __restrict__ c, int n) { for (int i 0; i n; i) { c[i] a[i] b[i]; } } // 手写 NEON void add_neon(const float* a, const float* b, float* c, int n) { int i 0; for (; i 4 n; i 4) { vst1q_f32(c i, vaddq_f32(vld1q_f32(a i), vld1q_f32(b i))); } for (; i n; i) c[i] a[i] b[i]; } int main() { const int N 10000000; std::vectorfloat a(N, 1.0f), b(N, 2.0f), c(N); auto bench { fn(a.data(), b.data(), c.data(), N); // 预热 auto start std::chrono::high_resolution_clock::now(); for (int t 0; t 100; t) fn(a.data(), b.data(), c.data(), N); auto end std::chrono::high_resolution_clock::now(); double ms std::chrono::durationdouble, std::milli(end - start).count() / 100; std::cout name : ms ms\n; }; bench(add_auto, Auto-vectorised); bench(add_neon, Hand-written NEON); // 两者应非常接近——编译器对这种简单循环的自动向量化做得很好 return 0; }生产视角ARM SIMD 内核在 ML 引擎中的落地本仓库在多个章节呼应了 ARM SIMD 的生产价值chapter 17 - AI inference/04. edge inference.md 与本文共同引用了Cactus——一个面向移动设备与可穿戴设备的低延迟 AI 引擎它以三层架构Engine → Graph → Kernels为具体案例展示了如何用自定义 ARM NEON 与 NPU 加速内核实现 attention、KV-cache 量化与 chunked prefill并通过零拷贝内存映射实现远低于其他引擎的 RAM 占用。TensorFlow Lite 针对 ARM CPU 与 Android NPU 优化二进制约 1MB支持 INT8 与 float16llama.cpp 则通过 AVX/NEON/I8MM 在消费级 CPU 上直接运行 GGUF 量化模型——这些都是本文所讲内建函数在生产中的真实形态。延伸阅读在继续深入之前建议按本仓库的脉络补齐上下文chapter 16 - SIMD and GPU programming/00. why C and how ML frameworks work.mdPython 前端 C 后端的框架结构、何时写自定义 C 内核、pybind11 绑定。chapter 16 - SIMD and GPU programming/01. hardware fundamentals.mdSIMD 概念、矢量寄存器全景、roofline 模型、功耗与能效经济学。chapter 16 - SIMD and GPU programming/03. x86 and AVX.mdx86 SSE/AVX/AVX-512/AMX 的对照实现与内存对齐陷阱。chapter 17 - AI inference/01. quantisation.mdINT8/INT4 量化原理以及 I8MM 加速的量化推理背景。chapter 17 - AI inference/04. edge inference.mdARM 端侧推理引擎TFLite、llama.cpp、Cactus的部署细节。README.md本书总览与学习路径。【免费下载链接】maths-cs-ai-compendiumBecome a cracked AI/ML researcher/engineer with this unconventional textbook covering maths, computing, and ML with intuition.项目地址: https://gitcode.com/GitHub_Trending/mat/maths-cs-ai-compendium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考