android_os

第16章:Neural Networks API (NNAPI)

Android Neural Networks API (NNAPI) 是 Android 8.1 引入的专门用于在移动设备上运行机器学习推理的 C API。本章将深入剖析 NNAPI 的架构设计、HAL 接口实现、模型编译优化机制,并与 iOS Core ML 进行技术对比,帮助读者理解移动端 AI 推理框架的设计哲学和实现细节。

16.1 NNAPI 架构设计

16.1.1 系统架构概览

NNAPI 采用分层架构设计,从上到下包括:

应用层接口

运行时层(libneuralnetworks.so)

HAL 层(Hardware Abstraction Layer)

驱动层实现

16.1.2 执行流程分析

NNAPI 的典型执行流程涉及多个阶段,每个阶段都有特定的内部机制:

  1. 模型构建阶段
    • 通过 ANeuralNetworksModel_create 创建模型
      • 分配 Model 对象和内部数据结构
      • 初始化操作数和操作列表
      • 设置模型元数据
    • 添加操作数(张量)定义
      • ANeuralNetworksModel_addOperand 注册张量
      • 指定数据类型(FLOAT32/INT32/UINT8 等)
      • 设置张量维度(支持动态维度)
      • 标记量化参数(scale/zero_point)
    • 添加操作(算子)及其输入输出
      • ANeuralNetworksModel_addOperation 添加计算节点
      • 指定操作类型(ANEURALNETWORKS_* 枚举)
      • 连接输入输出操作数索引
      • 设置操作特定参数
    • 设置模型输入输出
      • ANeuralNetworksModel_identifyInputsAndOutputs
      • 标记模型的入口和出口张量
      • 支持多输入多输出
    • 调用 ANeuralNetworksModel_finish 完成构建
      • 验证模型完整性
      • 构建内部计算图
      • 准备编译元数据
  2. 编译阶段
    • ANeuralNetworksCompilation_create 创建编译对象
      • 关联模型对象
      • 初始化编译上下文
      • 准备设备枚举
    • 设置编译选项
      • ANeuralNetworksCompilation_setPreference 设置优先级
        • ANEURALNETWORKS_PREFER_LOW_POWER:功耗优先
        • ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER:延迟优先
        • ANEURALNETWORKS_PREFER_SUSTAINED_SPEED:吞吐量优先
      • ANeuralNetworksCompilation_setTimeout 设置超时
      • ANeuralNetworksCompilation_setPriority 设置任务优先级
    • 选择目标设备(可指定或自动选择)
      • 自动模式:运行时评估所有可用设备
      • 手动模式:ANeuralNetworksCompilation_setDevices
      • 设备过滤:基于能力和性能特征
    • 缓存处理
      • ANeuralNetworksCompilation_setCaching 设置缓存目录
      • 生成缓存 token(基于模型哈希)
      • 检查缓存命中避免重复编译
    • 执行编译
      • ANeuralNetworksCompilation_finish 触发编译
      • 模型分区:将操作分配到不同设备
      • 设备编译:调用 HAL prepareModel
      • 生成执行计划和调度信息
  3. 执行阶段
    • ANeuralNetworksExecution_create 创建执行对象
      • 关联编译对象
      • 分配执行资源
      • 初始化输入输出槽
    • 设置输入数据
      • ANeuralNetworksExecution_setInput 绑定输入缓冲区
      • ANeuralNetworksExecution_setInputFromMemory 使用共享内存
      • 支持动态形状更新
    • 设置输出缓冲区
      • ANeuralNetworksExecution_setOutput 指定输出位置
      • ANeuralNetworksExecution_setOutputFromMemory 零拷贝输出
      • 输出形状查询支持
    • 配置执行参数
      • ANeuralNetworksExecution_setTimeout 执行超时
      • ANeuralNetworksExecution_setLoopTimeout 循环超时
      • ANeuralNetworksExecution_setMeasureTiming 性能测量
    • 执行推理
      • 同步执行:ANeuralNetworksExecution_compute
        • 阻塞等待完成
        • 直接返回结果
      • 异步执行:ANeuralNetworksExecution_startCompute
        • 返回 ANeuralNetworksEvent
        • 通过 ANeuralNetworksEvent_wait 等待
      • Fenced 执行:ANeuralNetworksExecution_startComputeWithDependencies
        • 基于 sync_fence 的依赖管理
        • 支持 GPU/Camera 管线集成
    • 获取执行结果
      • 输出数据自动填充到指定缓冲区
      • ANeuralNetworksExecution_getOutputOperandDimensions 查询输出形状
      • ANeuralNetworksExecution_getDuration 获取执行时间
        • ANEURALNETWORKS_DURATION_ON_HARDWARE:硬件执行时间
        • ANEURALNETWORKS_DURATION_IN_DRIVER:驱动总时间
  4. 资源清理
    • 显式释放:ANeuralNetworks*_free 系列函数
    • 引用计数:内部对象生命周期管理
    • 自动清理:与进程生命周期绑定

16.1.3 设备选择策略

NNAPI 的设备选择是性能优化的关键,涉及复杂的评估和调度算法:

设备发现与枚举

设备管理器初始化流程:
1. 扫描 HAL 服务(通过 hwservicemanager)
2. 加载 HIDL/AIDL 驱动
3. 查询设备能力
4. 构建设备注册表

关键 API:

自动选择算法

设备评分机制:

  1. 操作支持度计算
    • 遍历模型中的所有操作
    • 调用 IDevice::getSupportedOperations
    • 计算设备可执行的操作比例
    • 考虑操作的计算复杂度权重
  2. 性能评估
    • 基于历史执行数据
    • 参考设备性能特征表
    • 考虑以下指标:
      • 峰值算力(TOPS/GFLOPS)
      • 内存带宽
      • 功耗特征
      • 启动延迟
  3. 编译偏好影响
    • PREFER_LOW_POWER:优先选择低功耗设备(如 DSP)
    • PREFER_FAST_SINGLE_ANSWER:优先选择低延迟设备(如 GPU)
    • PREFER_SUSTAINED_SPEED:优先选择稳定性能设备
  4. 综合评分公式
    Score = α * SupportRatio + β * PerformanceScore + γ * PowerEfficiency
    其中 α、β、γ 根据编译偏好动态调整
    

手动设备指定

使用场景:

实现方式:

// 获取特定设备
ANeuralNetworksDevice* device;
ANeuralNetworks_getDevice(deviceIndex, &device);

// 查询设备特性
int64_t featureLevel;
ANeuralNetworksDevice_getFeatureLevel(device, &featureLevel);

// 指定编译设备
ANeuralNetworksCompilation_setDevices(compilation, &device, 1);

智能分区执行

模型分区算法:

  1. 构建设备-操作兼容性矩阵
    • 每个设备查询支持的操作
    • 构建二维矩阵 M[device][operation]
    • 标记不支持的操作
  2. 识别执行岛(Execution Island)
    • 连续的可在同一设备执行的操作序列
    • 使用图遍历算法识别连通分量
    • 评估岛间的数据依赖
  3. 优化分区策略
    • 最小化跨设备数据传输
      • 计算边切割成本
      • 考虑张量大小和传输开销
    • 平衡设备负载
      • 估算每个分区的计算量
      • 避免设备空闲等待
    • 考虑内存限制
      • 每个设备的可用内存
      • 中间结果的存储需求
  4. 生成执行计划
    • 确定每个分区的执行设备
    • 插入必要的数据传输操作
    • 生成同步点和依赖关系

多设备协同优化

  1. Pipeline 并行
    • 将模型划分为多个阶段
    • 不同批次在不同设备上并行
    • 适用于推理吞吐量优化
  2. 数据并行
    • 同一模型在多个设备上复制
    • 分割输入批次并行处理
    • 结果聚合和同步
  3. 混合精度执行
    • 不同设备使用不同精度
    • INT8 on DSP, FP16 on GPU
    • 自动插入类型转换

设备选择的高级特性

  1. 动态设备切换
    • 基于运行时负载
    • 热插拔设备支持
    • 故障转移机制
  2. 能效感知调度
    • 监控设备功耗状态
    • 温度限制考虑
    • 电池状态影响
  3. QoS 保证
    • 延迟敏感任务优先
    • 带宽预留机制
    • 公平调度算法

16.2 HAL 接口与驱动集成

16.2.1 HAL 接口定义

NNAPI HAL 使用 HIDL/AIDL 定义,经历了多个版本演进,主要接口包括:

IDevice 接口详解

// 位于 hardware/interfaces/neuralnetworks/版本/IDevice.hal
interface IDevice {
    // 设备能力查询
    getCapabilities() → (status, capabilities)
        - capabilities.relaxedFloat32toFloat16PerformanceScalar
        - capabilities.relaxedFloat32toFloat16PerformanceTensor
        - capabilities.operandPerformance[] // 每种数据类型的性能
        - capabilities.ifPerformance // IF/WHILE 条件性能
        - capabilities.whilePerformance // 循环性能
    
    // 支持度查询
    getSupportedOperations(model) → (status, supportedOps[])
        - 返回每个操作的支持状态
        - 考虑操作参数和数据类型
        - 检查设备特定限制
    
    // 模型准备(编译)
    prepareModel(model, preference, deadlineNs, callbacks) → status
        - model: 序列化的模型结构
        - preference: 执行偏好(延迟/功耗/吞吐量)
        - deadlineNs: 编译截止时间
        - callbacks: 异步回调接口
    
    // 内存分配(v1.3+)
    allocate(desc, roles, type, deadlineNs) → (status, buffer, token)
        - desc: 内存描述符
        - roles: 内存用途(输入/输出/中间结果)
        - type: 分配类型(设备/主机共享)
        - 返回 IBuffer 对象和 token
    
    // 缓存支持(v1.2+)
    prepareModelFromCache(deadlineNs, cacheHandles, token, callbacks)
        - 从缓存恢复编译模型
        - 避免重复编译开销
}

IPreparedModel 接口详解

interface IPreparedModel {
    // 基本同步执行
    execute(request, measure) → (status, outputShapes, timing)
        - request: 包含输入输出内存位置
        - measure: 是否测量执行时间
        - outputShapes: 动态输出形状
        - timing: 执行时间统计
    
    // 带超时同步执行(v1.3+)
    executeSynchronously(request, measure, deadlineNs, loopTimeoutNs)
        - deadlineNs: 最晚完成时间
        - loopTimeoutNs: 循环超时设置
    
    // Fence 异步执行(v1.3+)
    executeFenced(request, waitFor, measure, deadlineNs, loopTimeoutNs, 
                  executionTimeoutNs) → (status, syncFence, callback)
        - waitFor: 输入依赖的 fence
        - syncFence: 输出完成 fence
        - 与 GPU/Camera 管线集成
    
    // Burst 模式配置(v1.2+)
    configureExecutionBurst(requestChannel, resultChannel, context) → status
        - 使用 FMQ (Fast Message Queue) 通信
        - 减少 IPC 开销
        - 预分配执行资源
}

操作类型定义与分类

NNAPI 定义了 180+ 种标准操作,按照功能分类:

  1. 基础数学运算
    • ANEURALNETWORKS_ADD:元素级加法
    • ANEURALNETWORKS_MUL:元素级乘法
    • ANEURALNETWORKS_DIV:元素级除法
    • ANEURALNETWORKS_SUB:元素级减法
    • ANEURALNETWORKS_POW:幂运算
    • ANEURALNETWORKS_SQRT:平方根
  2. 神经网络层
    • ANEURALNETWORKS_CONV_2D:2D 卷积
    • ANEURALNETWORKS_DEPTHWISE_CONV_2D:深度可分离卷积
    • ANEURALNETWORKS_GROUPED_CONV_2D:分组卷积
    • ANEURALNETWORKS_FULLY_CONNECTED:全连接层
    • ANEURALNETWORKS_LSTM:长短期记忆网络
    • ANEURALNETWORKS_RNN:普通 RNN
    • ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM:双向 LSTM
  3. 激活函数
    • ANEURALNETWORKS_RELU:ReLU 激活
    • ANEURALNETWORKS_RELU1/RELU6:有界 ReLU
    • ANEURALNETWORKS_SIGMOID:Sigmoid 激活
    • ANEURALNETWORKS_TANH:双曲正切
    • ANEURALNETWORKS_ELU:指数线性单元
    • ANEURALNETWORKS_HARD_SWISH:硬 Swish 激活
  4. 池化与采样
    • ANEURALNETWORKS_MAX_POOL_2D:最大池化
    • ANEURALNETWORKS_AVERAGE_POOL_2D:平均池化
    • ANEURALNETWORKS_L2_POOL_2D:L2 池化
    • ANEURALNETWORKS_RESIZE_BILINEAR:双线性插值
    • ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR:最近邻插值
  5. 张量操作
    • ANEURALNETWORKS_RESHAPE:重塑形状
    • ANEURALNETWORKS_TRANSPOSE:转置
    • ANEURALNETWORKS_CONCATENATION:拼接
    • ANEURALNETWORKS_SPLIT:分割
    • ANEURALNETWORKS_SLICE:切片
    • ANEURALNETWORKS_SQUEEZE:压缩维度
  6. 控制流操作(v1.3+)
    • ANEURALNETWORKS_IF:条件分支
    • ANEURALNETWORKS_WHILE:循环结构

HAL 版本演进

  1. HAL 1.0 (Android 8.1)
    • 基本操作集(29 种)
    • 同步执行接口
    • 简单内存管理
  2. HAL 1.1 (Android 9.0)
    • 扩展操作集(45 种)
    • 量化支持增强
    • 更多激活函数
  3. HAL 1.2 (Android 10)
    • 大幅扩展操作(92 种)
    • Burst 执行模式
    • 缓存编译结果
    • 动态输出形状
  4. HAL 1.3 (Android 11)
    • 控制流支持
    • Fenced 执行
    • 内存域概念
    • QoS 和优先级
  5. AIDL HAL (Android 12+)
    • 从 HIDL 迁移到 AIDL
    • 更好的版本化支持
    • 简化的 IPC 机制

16.2.2 驱动实现要点

内存管理机制

  1. 零拷贝实现 ``` 内存共享流程:
    1. 应用分配 hidl_memory/AHardwareBuffer
    2. 通过 IPC 传递内存句柄
    3. 驱动映射到设备地址空间
    4. 直接在设备上访问数据 ```

    关键技术:

    • ION 分配器:统一的内存分配接口
    • dmabuf:Linux 内核 DMA 缓冲区共享
    • Gralloc:图形缓冲区分配器
  2. 内存池管理
    class MemoryPool {
        // 按大小分类的内存块
        std::map<size_t, std::vector<Memory>> pools;
           
        // 分配策略
        Memory allocate(size_t size) {
            // 1. 查找匹配的空闲块
            // 2. 如果没有,分配新块
            // 3. 记录使用状态
        }
           
        // 回收机制
        void recycle(Memory mem) {
            // 1. 标记为空闲
            // 2. 合并相邻块
            // 3. 定期清理未用块
        }
    };
    
  3. 内存对齐优化
    • 按照设备要求对齐(64/128/256 字节)
    • SIMD 指令对齐要求
    • 缓存行对齐优化

并发控制架构

  1. 执行队列设计
    class ExecutionQueue {
        // 优先级队列
        std::priority_queue<Task> highPriorityQueue;
        std::priority_queue<Task> normalQueue;
        std::priority_queue<Task> lowPriorityQueue;
           
        // 工作线程池
        std::vector<std::thread> workers;
           
        // 任务调度
        void schedule(Task task) {
            // 1. 根据优先级入队
            // 2. 唤醒空闲工作线程
            // 3. 负载均衡
        }
    };
    
  2. 资源锁管理
    • 细粒度锁:每个资源独立锁
    • 读写锁:区分读操作和写操作
    • 无锁数据结构:使用原子操作
  3. 死锁预防
    • 资源获取顺序规则
    • 超时机制
    • 死锁检测算法

错误处理框架

  1. 错误码体系
    enum ErrorCode {
        // 基本错误
        NONE = 0,
        DEVICE_UNAVAILABLE = 1,
        GENERAL_FAILURE = 2,
        OUTPUT_INSUFFICIENT_SIZE = 3,
        INVALID_ARGUMENT = 4,
           
        // 资源错误
        INSUFFICIENT_MEMORY = 1000,
        DEVICE_BUSY = 1001,
        RESOURCE_EXHAUSTED = 1002,
           
        // 执行错误
        MISSED_DEADLINE = 2000,
        ABORTED = 2001,
        INVALID_STATE = 2002,
    };
    
  2. 异常传播机制
    • 同步路径:直接返回错误码
    • 异步路径:通过回调传递
    • 跨进程:HIDL/AIDL 异常封装
  3. 恢复策略
    class ErrorRecovery {
        // 重试机制
        template<typename Func>
        auto retryWithBackoff(Func func, int maxRetries) {
            for (int i = 0; i < maxRetries; i++) {
                try {
                    return func();
                } catch (RecoverableError& e) {
                    std::this_thread::sleep_for(
                        std::chrono::milliseconds(100 * (1 << i)));
                }
            }
        }
           
        // 降级策略
        void fallbackToCPU(Model model) {
            // 切换到 CPU 参考实现
        }
    };
    

性能监控与调优

  1. 性能计数器
    struct PerformanceCounters {
        // 执行统计
        uint64_t totalExecutions;
        uint64_t successfulExecutions;
        uint64_t failedExecutions;
           
        // 时间统计
        Duration totalHardwareTime;
        Duration totalDriverTime;
        Duration averageLatency;
           
        // 资源使用
        size_t peakMemoryUsage;
        float averageUtilization;
    };
    
  2. 性能分析工具
    • Systrace 集成:跟踪关键路径
    • Perfetto 事件:详细性能数据
    • 自定义探针:特定热点分析
  3. 自适应优化
    • 动态批大小调整
    • 执行路径选择
    • 内存使用优化

16.2.3 厂商驱动案例

高通 Hexagon NN 深度剖析

  1. 架构特点
    • Hexagon DSP 架构
      • 4 个标量执行单元
      • 2 个 HVX (Hexagon Vector eXtensions) 单元
      • 1024 位向量宽度
    • 专用 HTA (Hexagon Tensor Accelerator)
      • 256 MAC 单元阵列
      • INT8/INT16 加速
      • 自定义张量指令
  2. 关键优化技术
    // HVX 向量化示例
    void conv2d_hvx(const uint8_t* input, const uint8_t* weights, 
                    uint8_t* output) {
        // 使用 HVX 内在函数
        HVX_Vector vin = vmem(input);
        HVX_Vector vweight = vmem(weights);
        HVX_Vector vout = vdmpy(vin, vweight); // 向量点积
        vmem(output) = vout;
    }
    
    • 数据量化优化
      • 动态量化范围调整
      • 非对称量化支持
      • 量化误差最小化
    • 内存访问优化
      • L2 缓存预取
      • DMA 传输优化
      • 零拷贝路径
  3. 驱动实现特点
    • 异构计算管理
      • CPU 预处理
      • DSP 核心计算
      • GPU 后处理
    • 电源管理
      • 动态频率调整
      • 电源门控
      • 低功耗模式

联发科 APU (AI Processing Unit) 详解

  1. 硬件架构 ``` APU 3.0 架构:
    • 6 个 AI 核心 (AI Core)
    • 每核 2048 MACs
    • 支持 INT8/INT16/FP16
    • 4MB 局部内存
    • 独立 DMA 引擎 ```
  2. 源力编译器 (Neuron Compiler)
    • 图优化
      • 算子融合
      • 布局优化
      • 内存复用
    • 编译策略
      • 多核分配
      • 流水线并行
      • 数据切分
  3. 特色功能
    • 多模型并发
      class APUScheduler {
          // 多模型调度
          void scheduleModels(vector<Model> models) {
              // 1. 资源评估
              // 2. 核心分配
              // 3. 并发执行
          }
      };
      
    • 动态形状支持
    • 在线学习能力

Google Tensor 芯片分析

  1. TPU 核心设计
    • 矩阵乘法单元 (MXU) ``` 128x128 系统阵列:
      • INT8 运算: 16K ops/cycle
      • bfloat16: 8K ops/cycle
      • 脉动阵列架构 ```
    • 统一缓冲区 (Unified Buffer)
      • 4MB SRAM
      • 高带宽访问
      • 双缓冲设计
  2. 软硬件协同设计
    • 编译器优化
      // TPU 特定优化
      void optimizeForTPU(Graph& graph) {
          // 1. 矩阵分块
          tileMatrixOps(graph, 128, 128);
          // 2. 内存布局
          optimizeMemoryLayout(graph);
          // 3. 指令调度
          scheduleInstructions(graph);
      }
      
    • 运行时调度
      • CPU 预处理管线
      • TPU 计算管线
      • GPU 渲染管线
  3. 系统集成优势
    • 与 Pixel Visual Core 协同
    • ISP 管线集成
    • 低延迟音频处理

华为达芬奇 NPU

  1. 双大核 + 微核架构
    • 达芬奇 Architecture 2.0 ``` 大核:处理复杂模型
      • 3D Cube 计算单元
      • 高精度计算

      微核:处理轻量任务

      • 低功耗设计
      • 快速响应 ```
  2. 自研指令集
    • 张量计算指令
    • 数据重排指令
    • 特殊函数指令
  3. 驱动特色
    • HiAI 框架集成
    • 跨设备计算
    • 安全执行环境

三星 Exynos NPU

  1. 三级架构设计
    • Neural Core:核心计算
    • Neural CPU:控制逻辑
    • Neural DSP:特殊运算
  2. 性能特点
    • 15 TOPS @ INT8
    • 混合精度支持
    • 压缩模型加速

驱动开发最佳实践

  1. 性能优化指南
    • 内存访问模式优化
    • 计算密集度提升
    • 并行度最大化
  2. 调试工具链
    • 性能分析器
    • 内存泄漏检测
    • 正确性验证
  3. 兼容性保证
    • 版本管理
    • 回退机制
    • 测试覆盖

16.3 模型编译与优化

16.3.1 编译流程详解

前端解析阶段

  1. 模型验证
    class ModelValidator {
        // 拓扑验证
        bool validateTopology(const Model& model) {
            // 1. 检查环路
            if (hasCycle(model.graph)) return false;
               
            // 2. 验证连接性
            for (auto& op : model.operations) {
                if (!validateConnections(op)) return false;
            }
               
            // 3. 检查输入输出
            return validateIOTensors(model);
        }
           
        // 参数验证
        bool validateParameters(const Operation& op) {
            // 检查参数范围
            // 验证维度兼容性
            // 确认数据类型
        }
    };
    
  2. 计算图构建
    • 节点创建:每个操作对应一个节点
    • 边连接:数据依赖关系
    • 属性标注:张量形状、数据类型
      struct ComputeGraph {
        std::vector<Node> nodes;
        std::vector<Edge> edges;
        std::map<int, TensorInfo> tensorInfo;
             
        // 构建图
        void buildFromModel(const Model& model) {
            // 1. 创建节点
            for (auto& op : model.operations) {
                nodes.push_back(createNode(op));
            }
                 
            // 2. 连接边
            for (auto& connection : model.connections) {
                edges.push_back(createEdge(connection));
            }
                 
            // 3. 推断张量信息
            inferTensorShapes();
        }
      };
      
  3. 张量形状推断
    • 静态形状推断
    • 动态形状处理
    • 广播规则应用

图优化阶段

  1. 算子融合优化
    class OperatorFusion {
        // Conv + BatchNorm + ReLU 融合
        void fuseConvBNReLU(Graph& graph) {
            for (auto& pattern : findPatterns(graph, "Conv->BN->ReLU")) {
                // 1. 提取参数
                auto conv = pattern.nodes[0];
                auto bn = pattern.nodes[1];
                auto relu = pattern.nodes[2];
                   
                // 2. 计算融合参数
                auto fusedWeights = fuseWeights(conv.weights, 
                                               bn.scale, bn.bias, 
                                               bn.mean, bn.variance);
                   
                // 3. 创建融合节点
                auto fusedOp = createFusedConvBNReLU(fusedWeights);
                   
                // 4. 替换原节点
                graph.replace(pattern, fusedOp);
            }
        }
           
        // 其他融合模式
        void fusePatterns(Graph& graph) {
            fuseConvBNReLU(graph);
            fuseMatMulAdd(graph);      // MatMul + Add
            fuseActivations(graph);     // 多种激活函数
            fuseElementwise(graph);     // 元素级操作
        }
    };
    
  2. 常量折叠优化
    class ConstantFolding {
        void foldConstants(Graph& graph) {
            bool changed = true;
            while (changed) {
                changed = false;
                for (auto& node : graph.nodes) {
                    if (allInputsConstant(node)) {
                        // 1. 计算常量结果
                        auto result = evaluateNode(node);
                           
                        // 2. 替换为常量节点
                        auto constNode = createConstant(result);
                        graph.replace(node, constNode);
                           
                        changed = true;
                    }
                }
            }
        }
    };
    
  3. 死代码消除
    • 未使用节点删除
    • 不可达路径消除
    • 冗余计算合并
  4. 布局优化
    class LayoutOptimizer {
        // NCHW <-> NHWC 转换优化
        void optimizeLayout(Graph& graph) {
            // 1. 分析最佳布局
            auto layout = analyzeOptimalLayout(graph);
               
            // 2. 插入转换节点
            insertLayoutTransforms(graph, layout);
               
            // 3. 合并相邻转换
            mergeAdjacentTransforms(graph);
        }
    };
    

后端代码生成

  1. 设备特定代码生成
    class CodeGenerator {
        // 为不同设备生成代码
        std::unique_ptr<ExecutableCode> generate(const Graph& graph, 
                                                 Device device) {
            switch (device.type) {
                case DeviceType::CPU:
                    return generateCPUCode(graph);
                case DeviceType::GPU:
                    return generateGPUCode(graph);
                case DeviceType::DSP:
                    return generateDSPCode(graph);
                case DeviceType::NPU:
                    return generateNPUCode(graph);
            }
        }
           
        // CPU 代码生成
        std::unique_ptr<CPUCode> generateCPUCode(const Graph& graph) {
            CPUCodeBuilder builder;
               
            // 1. 内存分配
            auto memoryPlan = planMemory(graph);
               
            // 2. 指令选择
            for (auto& node : graph.nodes) {
                auto kernels = selectKernels(node, cpuInfo);
                builder.addKernels(kernels);
            }
               
            // 3. 向量化优化
            builder.vectorize();
               
            return builder.build();
        }
    };
    
  2. 内存布局优化
    class MemoryPlanner {
        MemoryPlan planMemory(const Graph& graph) {
            // 1. 生命周期分析
            auto lifetimes = analyzeLifetimes(graph);
               
            // 2. 内存复用
            auto allocation = allocateWithReuse(lifetimes);
               
            // 3. 对齐优化
            optimizeAlignment(allocation);
               
            // 4. 缓存优化
            optimizeCacheUsage(allocation);
               
            return allocation;
        }
           
        // 内存复用算法
        Allocation allocateWithReuse(const Lifetimes& lifetimes) {
            // 使用图着色算法
            auto graph = buildInterferenceGraph(lifetimes);
            auto coloring = colorGraph(graph);
            return assignMemory(coloring);
        }
    };
    
  3. 并行化策略
    class ParallelizationStrategy {
        // 数据并行
        void applyDataParallelism(ComputeKernel& kernel) {
            auto batchSize = kernel.inputShape[0];
            auto numThreads = getOptimalThreadCount();
               
            kernel.parallel_for(0, batchSize, numThreads);
        }
           
        // 模型并行
        void applyModelParallelism(Graph& graph) {
            // 1. 分区
            auto partitions = partitionGraph(graph);
               
            // 2. 调度
            schedulePartitions(partitions);
        }
           
        // 流水线并行
        void applyPipelineParallelism(ExecutionPlan& plan) {
            // 创建流水线阶段
            auto stages = createPipelineStages(plan);
               
            // 设置缓冲区
            setupInterstageBuffers(stages);
        }
    };
    

16.3.2 性能优化技术

量化技术详解

  1. INT8 量化实现
    class INT8Quantizer {
        // 量化参数计算
        struct QuantParams {
            float scale;
            int32_t zero_point;
               
            // 计算量化参数
            static QuantParams compute(float min_val, float max_val) {
                QuantParams params;
                   
                // 对称量化
                float max_abs = std::max(std::abs(min_val), 
                                        std::abs(max_val));
                params.scale = max_abs / 127.0f;
                params.zero_point = 0;
                   
                // 非对称量化
                // params.scale = (max_val - min_val) / 255.0f;
                // params.zero_point = -min_val / params.scale;
                   
                return params;
            }
        };
           
        // 量化核心函数
        void quantizeTensor(const float* input, int8_t* output, 
                           size_t size, const QuantParams& params) {
            for (size_t i = 0; i < size; i++) {
                int32_t q = std::round(input[i] / params.scale + 
                                      params.zero_point);
                output[i] = std::max(-128, std::min(127, q));
            }
        }
           
        // 反量化
        void dequantizeTensor(const int8_t* input, float* output,
                             size_t size, const QuantParams& params) {
            for (size_t i = 0; i < size; i++) {
                output[i] = (input[i] - params.zero_point) * params.scale;
            }
        }
    };
    
  2. 动态量化策略
    class DynamicQuantization {
        // 运行时校准
        void calibrate(const Model& model, const Dataset& calibData) {
            std::map<int, QuantStats> stats;
               
            // 1. 收集统计信息
            for (auto& sample : calibData) {
                auto activations = runModel(model, sample);
                updateStats(stats, activations);
            }
               
            // 2. 计算量化参数
            for (auto& [tensorId, stat] : stats) {
                quantParams[tensorId] = computeOptimalParams(stat);
            }
        }
           
        // 最优参数计算
        QuantParams computeOptimalParams(const QuantStats& stats) {
            // KL 散度最小化
            return minimizeKLDivergence(stats.histogram);
        }
    };
    
  3. 混合精度优化
    class MixedPrecisionOptimizer {
        // 精度分配策略
        void assignPrecisions(Graph& graph) {
            // 1. 敏感度分析
            auto sensitivities = analyzeSensitivity(graph);
               
            // 2. 分配精度
            for (auto& node : graph.nodes) {
                if (sensitivities[node.id] > threshold) {
                    node.precision = Precision::FP32;
                } else if (node.type == OpType::MatMul) {
                    node.precision = Precision::FP16;
                } else {
                    node.precision = Precision::INT8;
                }
            }
               
            // 3. 插入类型转换
            insertCastOperations(graph);
        }
    };
    

高级内存优化

  1. 张量生命周期分析
    class TensorLifetimeAnalyzer {
        struct Lifetime {
            int firstUse;
            int lastUse;
            size_t size;
            int alignment;
        };
           
        std::map<int, Lifetime> analyze(const Graph& graph) {
            std::map<int, Lifetime> lifetimes;
               
            // 1. 遍历执行顺序
            auto order = topologicalSort(graph);
               
            // 2. 记录使用点
            for (int step = 0; step < order.size(); step++) {
                auto& node = graph.nodes[order[step]];
                   
                // 输入张量
                for (int input : node.inputs) {
                    lifetimes[input].lastUse = step;
                    if (lifetimes[input].firstUse == -1) {
                        lifetimes[input].firstUse = step;
                    }
                }
                   
                // 输出张量
                for (int output : node.outputs) {
                    lifetimes[output].firstUse = step;
                    lifetimes[output].size = getTensorSize(output);
                }
            }
               
            return lifetimes;
        }
    };
    
  2. 内存池设计
    class MemoryPool {
        struct Block {
            size_t offset;
            size_t size;
            bool free;
        };
           
        std::vector<Block> blocks;
        size_t totalSize;
           
        // 分配算法
        size_t allocate(size_t size, int alignment) {
            // 1. 首次适配
            for (auto& block : blocks) {
                if (block.free && block.size >= size) {
                    size_t alignedOffset = align(block.offset, alignment);
                    if (alignedOffset + size <= block.offset + block.size) {
                        // 分割块
                        splitBlock(block, alignedOffset, size);
                        return alignedOffset;
                    }
                }
            }
               
            // 2. 扩展池
            expandPool(size, alignment);
            return allocate(size, alignment);
        }
           
        // 碎片整理
        void defragment() {
            // 合并相邻空闲块
            mergeAdjacentFreeBlocks();
               
            // 移动占用块
            compactAllocatedBlocks();
        }
    };
    
  3. 工作空间优化
    class WorkspaceOptimizer {
        // 计算最小工作空间
        size_t computeMinWorkspace(const Graph& graph) {
            // 1. 分析每个操作的工作空间需求
            std::map<int, size_t> workspaceNeeds;
            for (auto& node : graph.nodes) {
                workspaceNeeds[node.id] = 
                    estimateWorkspace(node.type, node.params);
            }
               
            // 2. 并发分析
            auto concurrentOps = analyzeConcurrency(graph);
               
            // 3. 计算峰值需求
            size_t maxWorkspace = 0;
            for (auto& group : concurrentOps) {
                size_t groupWorkspace = 0;
                for (int opId : group) {
                    groupWorkspace += workspaceNeeds[opId];
                }
                maxWorkspace = std::max(maxWorkspace, groupWorkspace);
            }
               
            return maxWorkspace;
        }
    };
    

执行优化技术

  1. 批处理优化
    class BatchOptimizer {
        // 动态批处理
        void optimizeBatching(ExecutionPlan& plan) {
            // 1. 分析批处理机会
            auto batchableOps = findBatchableOperations(plan);
               
            // 2. 合并批次
            for (auto& group : batchableOps) {
                auto optimalBatchSize = computeOptimalBatchSize(group);
                mergeBatches(group, optimalBatchSize);
            }
               
            // 3. 重新调度
            rescheduleExecution(plan);
        }
           
        // 最佳批大小计算
        int computeOptimalBatchSize(const OpGroup& group) {
            // 考虑内存带宽和计算能力
            int memoryLimit = getAvailableMemory() / group.memoryPerItem;
            int computeLimit = getComputeCapacity() / group.computePerItem;
               
            return std::min(memoryLimit, computeLimit);
        }
    };
    
  2. 流水线化执行
    class PipelineExecutor {
        struct Stage {
            std::vector<Operation> ops;
            std::queue<Task> taskQueue;
            std::thread worker;
        };
           
        std::vector<Stage> stages;
           
        // 创建流水线
        void createPipeline(const Graph& graph) {
            // 1. 划分阶段
            auto stageOps = partitionIntoStages(graph);
               
            // 2. 创建工作线程
            for (auto& ops : stageOps) {
                Stage stage;
                stage.ops = ops;
                stage.worker = std::thread([this, &stage]() {
                    processStage(stage);
                });
                stages.push_back(std::move(stage));
            }
               
            // 3. 设置缓冲区
            setupInterstageBuffers();
        }
    };
    
  3. 异步内存传输
    class AsyncMemoryTransfer {
        // DMA 传输管理
        class DMAManager {
            std::queue<TransferRequest> pendingTransfers;
            std::vector<DMAChannel> channels;
               
            // 发起异步传输
            Future<void> asyncTransfer(void* src, void* dst, 
                                      size_t size) {
                auto channel = getAvailableChannel();
                   
                TransferRequest req{src, dst, size};
                auto future = channel.startTransfer(req);
                   
                // 后台线程管理传输
                transferThread.addTask([channel, future]() {
                    future.wait();
                    channel.release();
                });
                   
                return future;
            }
        };
           
        // 预取策略
        void prefetchData(const ExecutionPlan& plan) {
            for (int i = 0; i < plan.operations.size() - 1; i++) {
                auto& currentOp = plan.operations[i];
                auto& nextOp = plan.operations[i + 1];
                   
                // 当前操作执行时,预取下一个操作的数据
                parallel_invoke(
                    [&]() { executeOperation(currentOp); },
                    [&]() { prefetchOperationData(nextOp); }
                );
            }
        }
    };
    

16.3.3 缓存机制详解

编译缓存实现

  1. 缓存架构设计
    class CompilationCache {
        // 缓存项定义
        struct CacheEntry {
            std::string modelHash;      // 模型哈希
            std::string deviceId;       // 设备标识
            CompilationParams params;   // 编译参数
               
            std::vector<uint8_t> compiledBinary;  // 编译结果
            std::chrono::time_point<> timestamp;  // 时间戳
            size_t hitCount;                      // 命中次数
        };
           
        // 缓存存储
        class CacheStorage {
            // 内存缓存
            std::unordered_map<std::string, CacheEntry> memCache;
               
            // 磁盘缓存
            std::string cacheDir;
               
            // 保存到磁盘
            void persistToDisk(const std::string& key, 
                              const CacheEntry& entry) {
                std::string filePath = cacheDir + "/" + key + ".nnc";
                   
                // 序列化元数据
                std::ofstream meta(filePath + ".meta");
                serializeMetadata(meta, entry);
                   
                // 保存二进制
                std::ofstream binary(filePath, std::ios::binary);
                binary.write(reinterpret_cast<const char*>(
                    entry.compiledBinary.data()), 
                    entry.compiledBinary.size());
            }
               
            // 从磁盘加载
            std::optional<CacheEntry> loadFromDisk(const std::string& key) {
                std::string filePath = cacheDir + "/" + key + ".nnc";
                   
                if (!fileExists(filePath)) return std::nullopt;
                   
                // 加载并验证
                auto entry = deserializeEntry(filePath);
                if (validateEntry(entry)) {
                    return entry;
                }
                   
                return std::nullopt;
            }
        };
    };
    
  2. 缓存键生成
    class CacheKeyGenerator {
        std::string generateKey(const Model& model, 
                               const Device& device,
                               const CompilationParams& params) {
            // 1. 计算模型哈希
            std::string modelHash = computeModelHash(model);
               
            // 2. 设备特征
            std::string deviceFeatures = getDeviceFeatures(device);
               
            // 3. 编译参数
            std::string paramsHash = hashParams(params);
               
            // 4. 组合键
            return modelHash + "_" + deviceFeatures + "_" + paramsHash;
        }
           
        // 模型哈希计算
        std::string computeModelHash(const Model& model) {
            SHA256 hasher;
               
            // 哈希拓扑结构
            for (auto& op : model.operations) {
                hasher.update(op.type);
                hasher.update(op.inputs);
                hasher.update(op.outputs);
                hasher.update(op.params);
            }
               
            // 哈希权重数据
            for (auto& tensor : model.tensors) {
                if (tensor.isConstant) {
                    hasher.update(tensor.data);
                }
            }
               
            return hasher.finalize();
        }
    };
    
  3. 缓存淘汰策略
    class CacheEvictionPolicy {
        // LRU 淘汰
        void evictLRU(CacheStorage& cache, size_t targetSize) {
            std::vector<std::pair<std::string, time_t>> entries;
               
            // 收集所有项的访问时间
            for (auto& [key, entry] : cache.memCache) {
                entries.push_back({key, entry.timestamp});
            }
               
            // 按时间排序
            std::sort(entries.begin(), entries.end(), 
                     [](auto& a, auto& b) { return a.second < b.second; });
               
            // 淘汰旧项
            size_t currentSize = cache.getCurrentSize();
            for (auto& [key, _] : entries) {
                if (currentSize <= targetSize) break;
                   
                currentSize -= cache.remove(key);
            }
        }
           
        // 使用频率淘汰
        void evictLFU(CacheStorage& cache, size_t targetSize) {
            // 按 hitCount 排序并淘汰
        }
    };
    

执行缓存优化

  1. 执行资源预分配
    class ExecutionResourceCache {
        struct ResourcePool {
            std::vector<ExecutionContext> contexts;
            std::queue<int> availableIndices;
            std::mutex mutex;
               
            // 获取可用上下文
            ExecutionContext* acquire() {
                std::lock_guard<std::mutex> lock(mutex);
                   
                if (availableIndices.empty()) {
                    // 创建新上下文
                    contexts.emplace_back();
                    return &contexts.back();
                }
                   
                int idx = availableIndices.front();
                availableIndices.pop();
                return &contexts[idx];
            }
               
            // 释放上下文
            void release(ExecutionContext* ctx) {
                std::lock_guard<std::mutex> lock(mutex);
                   
                // 清理和重置
                ctx->reset();
                   
                // 放回池中
                int idx = ctx - contexts.data();
                availableIndices.push(idx);
            }
        };
           
        // 每个模型的资源池
        std::unordered_map<std::string, ResourcePool> modelPools;
    };
    
  2. Burst 模式实现
    class BurstExecutor {
        // Burst 会话
        class BurstSession {
            IPreparedModel* model;
            FMQRequestChannel requestChannel;
            FMQResultChannel resultChannel;
            std::thread executorThread;
               
            // 初始化 Burst 会话
            void initialize() {
                // 1. 创建 FMQ 通道
                requestChannel.create(1024 * 1024);  // 1MB
                resultChannel.create(1024 * 1024);
                   
                // 2. 配置模型
                model->configureExecutionBurst(
                    requestChannel.getDescriptor(),
                    resultChannel.getDescriptor());
                   
                // 3. 启动执行线程
                executorThread = std::thread([this]() {
                    processBurstRequests();
                });
            }
               
            // 处理 Burst 请求
            void processBurstRequests() {
                while (running) {
                    Request req;
                    if (requestChannel.read(&req)) {
                        // 直接执行,无 IPC 开销
                        auto result = executeDirectly(req);
                           
                        // 写回结果
                        resultChannel.write(result);
                    }
                }
            }
        };
           
        // Burst 会话管理
        std::unordered_map<std::string, BurstSession> sessions;
    };
    
  3. 热点路径优化
    class HotPathOptimizer {
        // 执行统计
        struct PathStats {
            std::vector<int> executionPath;
            int executionCount;
            double averageTime;
        };
           
        std::map<std::string, PathStats> pathStatistics;
           
        // 分析热点路径
        void analyzeHotPaths(const Model& model) {
            // 1. 收集执行路径
            auto paths = collectExecutionPaths(model);
               
            // 2. 统计频率
            for (auto& path : paths) {
                pathStatistics[hashPath(path)].executionCount++;
            }
               
            // 3. 识别热点
            std::vector<std::string> hotPaths;
            for (auto& [pathHash, stats] : pathStatistics) {
                if (stats.executionCount > threshold) {
                    hotPaths.push_back(pathHash);
                }
            }
               
            // 4. 优化热点路径
            for (auto& pathHash : hotPaths) {
                optimizePath(pathHash);
            }
        }
           
        // 路径优化
        void optimizePath(const std::string& pathHash) {
            // 1. 专门编译
            compilePathSpecialized(pathHash);
               
            // 2. 预分配资源
            preallocatePathResources(pathHash);
               
            // 3. 缓存中间结果
            cacheIntermediateResults(pathHash);
        }
    };
    

缓存一致性保证

  1. 版本管理
    class CacheVersionManager {
        struct VersionInfo {
            int nnApiVersion;
            int halVersion;
            std::string driverVersion;
            std::string buildHash;
        };
           
        // 验证缓存有效性
        bool validateCache(const CacheEntry& entry) {
            VersionInfo current = getCurrentVersion();
            VersionInfo cached = entry.versionInfo;
               
            // 版本匹配
            if (current.nnApiVersion != cached.nnApiVersion ||
                current.halVersion != cached.halVersion) {
                return false;
            }
               
            // 驱动版本检查
            if (current.driverVersion != cached.driverVersion) {
                return requiresRecompilation(current, cached);
            }
               
            return true;
        }
    };
    
  2. 并发访问控制
    class ConcurrentCacheAccess {
        // 读写锁
        std::shared_mutex cacheMutex;
           
        // 细粒度锁
        std::unordered_map<std::string, std::unique_ptr<std::mutex>> 
            entryLocks;
           
        // 安全读取
        std::optional<CacheEntry> read(const std::string& key) {
            std::shared_lock<std::shared_mutex> lock(cacheMutex);
               
            auto it = cache.find(key);
            if (it != cache.end()) {
                return it->second;
            }
               
            return std::nullopt;
        }
           
        // 安全写入
        void write(const std::string& key, const CacheEntry& entry) {
            std::unique_lock<std::shared_mutex> lock(cacheMutex);
               
            cache[key] = entry;
               
            // 异步持久化
            persistAsync(key, entry);
        }
    };
    

16.4 与 iOS Core ML 对比

16.4.1 架构差异

API 设计理念

模型格式

设备抽象

16.4.2 性能特征

执行效率

内存使用

功耗优化

16.4.3 生态系统

框架支持

模型转换

开发工具

16.4.4 未来发展

NNAPI 方向

Core ML 方向

本章小结

本章深入剖析了 Android Neural Networks API 的设计与实现:

  1. 架构设计:分层架构提供了灵活性和可扩展性,支持多种硬件加速器
  2. HAL 接口:标准化的硬件抽象层使得厂商能够充分发挥硬件潜力
  3. 编译优化:多层次的优化技术确保模型在设备上高效执行
  4. 生态对比:与 iOS Core ML 相比,NNAPI 更底层但也更灵活

关键要点:

练习题

基础题

  1. NNAPI 执行流程 描述一个典型的 NNAPI 模型从创建到执行的完整流程,包括各个阶段的主要 API 调用。

    Hint: 考虑模型构建、编译和执行三个主要阶段

    参考答案 完整流程包括: 1. 模型构建:创建模型 → 添加操作数 → 添加操作 → 完成模型 2. 编译阶段:创建编译对象 → 设置选项 → 执行编译 3. 执行阶段:创建执行对象 → 设置输入输出 → 执行推理 → 获取结果 关键 API:ANeuralNetworksModel_create、ANeuralNetworksModel_addOperand、 ANeuralNetworksModel_addOperation、ANeuralNetworksCompilation_create、 ANeuralNetworksExecution_create 等。
  2. HAL 接口功能 解释 IDevice 和 IPreparedModel 接口的主要区别和各自的职责。

    Hint: 考虑编译前后的不同阶段

    参考答案 IDevice 接口负责: - 设备能力查询 - 操作支持度检查 - 模型编译(prepareModel) - 设备级资源管理 IPreparedModel 接口负责: - 执行已编译的模型 - 管理执行资源 - 处理输入输出数据 - 提供执行性能指标
  3. 量化技术 说明 NNAPI 中 INT8 量化的基本原理和优势。

    Hint: 考虑精度、性能和功耗的权衡

    参考答案 INT8 量化原理: - 将浮点数映射到 8 位整数范围 - 使用 scale 和 zero_point 参数 - 量化公式:real_value = (int8_value - zero_point) * scale 优势: - 内存使用减少 4 倍 - 计算速度提升(SIMD 指令) - 功耗降低 - 缓存效率提高

挑战题

  1. 多设备执行策略 设计一个算法,将神经网络模型自动分割到 CPU、GPU 和 NPU 三个设备上执行,目标是最小化总执行时间。需要考虑哪些因素?

    Hint: 考虑设备间数据传输开销和各设备的计算特征

    参考答案 需要考虑的因素: 1. 操作支持度:每个设备支持的操作类型 2. 计算性能:不同操作在各设备上的执行时间 3. 内存带宽:设备的内存访问速度 4. 传输开销:设备间数据传输成本 5. 并行机会:可以并行执行的子图 算法思路: - 构建操作性能模型 - 使用动态规划或启发式搜索 - 考虑数据局部性 - 最小化关键路径长度
  2. 编译优化分析 分析 Conv2D + BatchNorm + ReLU 这个常见模式如何进行算子融合优化,包括数学推导和实现要点。

    Hint: BatchNorm 在推理时可以折叠到 Conv2D 的权重中

    参考答案 融合优化过程: 1. BatchNorm 公式:y = γ * (x - μ) / √(σ² + ε) + β 2. Conv2D 输出:x = Σ(W * input) + b 3. 融合后:W' = γ * W / √(σ² + ε), b' = γ * (b - μ) / √(σ² + ε) + β 4. ReLU 可以直接应用在输出上 实现要点: - 预计算融合后的权重 - 减少内存访问次数 - 避免中间结果存储 - 利用 SIMD 指令加速
  3. 性能分析工具 设计一个 NNAPI 性能分析工具的架构,需要收集哪些指标,如何实现?

    Hint: 考虑不同层次的性能数据

    参考答案 需要收集的指标: 1. 模型级:总执行时间、吞吐量 2. 层级:每层执行时间、内存使用 3. 设备级:利用率、功耗 4. 系统级:CPU/内存/缓存状态 实现方案: - 插桩 NNAPI Runtime - HAL 层添加性能回调 - 使用 systrace 集成 - 提供可视化界面
  4. 跨平台模型部署 设计一个方案,使得同一个模型可以在 Android (NNAPI) 和 iOS (Core ML) 上部署,如何处理两个平台的差异?

    Hint: 考虑中间表示和平台特定优化

    参考答案 方案设计: 1. 统一中间表示(如 ONNX) 2. 平台转换器: - ONNX → NNAPI (通过 TFLite) - ONNX → Core ML 3. 操作兼容性处理: - 不支持操作的替代实现 - 自定义操作的处理 4. 性能优化: - 平台特定的图优化 - 量化策略适配 5. 测试验证: - 数值精度对比 - 性能基准测试
  5. 隐私保护推理 如何在 NNAPI 框架下实现隐私保护的模型推理,防止模型参数泄露?

    Hint: 考虑加密执行和安全硬件

    参考答案 隐私保护方案: 1. 模型加密存储: - 使用 Android Keystore - 运行时解密到安全内存 2. 安全执行环境: - 利用 TEE (Trusty) - 隔离的执行进程 3. 参数混淆: - 同态加密(性能损失大) - 差分隐私添加噪声 4. 访问控制: - SELinux 策略限制 - 应用权限验证 5. 审计日志: - 记录模型访问 - 异常检测机制

常见陷阱与错误

  1. 内存泄漏
    • 错误:忘记释放 ANeuralNetworksMemory 对象
    • 正确:使用 RAII 或确保配对的 create/free 调用
  2. 设备选择
    • 错误:假设所有设备都支持所有操作
    • 正确:查询设备能力,准备 CPU 后备方案
  3. 同步问题
    • 错误:在异步执行完成前访问输出缓冲区
    • 正确:等待执行完成回调或使用同步 API
  4. 版本兼容
    • 错误:使用新 API 不检查 API 级别
    • 正确:运行时检查 API 可用性
  5. 性能陷阱
    • 错误:频繁创建和销毁模型/编译对象
    • 正确:复用编译后的模型,使用执行缓存

最佳实践检查清单