1.内存占用
神经网络模型常见的内存占用可以分为以下几个部分:
1.1 模型参数内存
- 定义:神经网络的权重和偏置等参数会占用内存。
- 计算方法:
- 参数总量 = 各层参数数量的总和。
- 每个参数的大小取决于数据类型(如 float32 为 4 字节,float16 为 2 字节,int8 为 1 字节)。
- 公式: 参数内存=参数总数×每个参数的字节数
- 示例: 一个全连接层 输入维度=1024,输出维度=512,数据类型为 float32,则: 参数量=1024×512+512 (偏置项)=524,800 参数内存: 524,800×4 Bytes≈2.1 MB
1.2 激活内存
- 定义:网络各层的中间结果(激活)占用内存。
- 计算方法:
- 激活值总量 = 每层输出的维度之和。
- 数据类型通常与模型参数一致(如 float32)。
- 公式: 激活内存=每层激活值数量×每个激活值的字节数
- 示例: 卷积层:输入特征图大小为 64×64(宽 × 高),通道数为 128,输出通道数为 256,假设数据类型为 float32,则: 激活内存大小=64×64×256×4 (Bytes)=4MB
1.3 数据存储内存
- 输入数据:
- 输入数据占用内存,根据输入维度计算。
- 示例:输入大小为 32×3×224×224,数据类型为 float32:32×(3×224×224)×4≈19MB
- 输出数据:
- 模型输出也需要占用内存,占用情况同输入。
2.征程 6 模型推理内存分析
模型推理过程中的内存占用来自三个方面, input tensor memory + output tensor memory + model memoy,其中 model memory 主要是模型文件 size + 运行时指令运行时所需的内存(如从 SRAM 换出所需),可以等效理解为第一节介绍的模型参数内存+激活内存。
此外,模型加载过程中 runtime 将申请额外的内存用于模型的解析,该申请的内存在初始化完成后释放。
3.征程 6 模型推理内存监控
OpenExplorer 中提供的 hrt_ucp_monitor 支持监控内存信息,下面我们来看一下 hrt_ucp_monitor 监控内存的用法示例。
工具准备:将工具链 OpenExplorer 开发包中 hrt_ucp_monitor 传到开发板上即可。
工具使用:运行 hrt_ucp_monitor 时,如果不指定参数,则使用默认参数运行。默认开启所有硬件 IP 监控,以交互模式运行, BPU 和 DSP 每秒采样 500 次,硬件 IP 占用率每 1000ms 刷新一次。如果想要修改,可以参考工具链的用户手册,或运行 hrt_ucp_monitor -h 获取工具的使用详情。
3.1 无模型推理
在终端运行命令:hrt_ucp_monitor,可以看到板端预留 4.5G 内存。
有两个地方需要专门解释一下:
1.ION(Ion Memory Allocator)共享内存管理
ION 是 google 在 Android4.x 为了解决内存碎片化管理而引入的通用内存管理器,用来支持不同的内存分配机制,如 CARVOUT(PMEM),物理连续内存(kmalloc),虚拟地址连续但物理地址不连续内存(vmalloc),IOMMU 等。
ION Info 还包括一些系统以及核间通信的占用,并不是模型本身的占用
2.HBMEM(Hobot Memory Management)地平线内存管理模块
HBMEM,是一个地平线自研的内存管理软件,用于解决 Linux 内核无法很好的支持预留内存的管理,以及应用与驱动之间的内存共享的问题。
3.2 有模型推理
在 A 终端运行程序,在 B 终端运行命令:hrt_ucp_monitor,即可看到对应的监控信息:
可以看到,模型推理时,主要是 carveout 的内存,也可以使用如下命令查看内存使用情况:
cat /sys/kernel/debug/ion/heaps/carveout
查看对应进程的占用即可