掌桥专利:专业的专利平台
掌桥专利
首页

一种神经网络计算的内存管理方法

文献发布时间:2023-06-19 11:54:11



技术领域

本发明属于计算机软件、人工智能领域,具体涉及一种对任意深度神经网络优化其运行功能时内存管理的方法。

背景技术

深度卷积神经网络算法由多层具体的神经元算法层、隐藏层组成,主要包含有卷积层,主要算子为矩阵或向量的卷积计算。该计算任务的主要特点为输入的数据量大、输入数据具有空间特征信息的耦合。计算所需算力大,所需要的数据量更大,存储瓶颈成为了主要的制约因素。

近年来人工智能算法已经得到广泛应用,但在相关场景下,数据存储的容量、性能和成本因素成为制约需求的主要因素。

在终端部署人工智能算法,其需求特征为,由于存储的硬件容量有限,必需要将数据进行复用,减少数据的膨胀;而对于不同领域和产业场景所常用的人工神经网络算法不同,需要存储容量不同,动态分配带来的风险需要一种静态分配方法,防止存储空间分配失败的风险。这样,我们就需要一种方法,能够静态分配神经网络数据存储,复用神经网络存储区存储神经网络数据,灵活快速定位神经网络数据地址。

发明内容

本发明提供一种神经网络计算的内存管理方法。针对终端部署场景,解决对数据存储静态分配问题,突破过去动态管理内存的技术限制;解决存储数据的复用问题,大大降低过去所需要的存储规模所带来的成本限制;还对静态分配办法进行了优化,使数据定位以及操作仍具有灵活性。

本发明所述方法,包括一套数据结构设计方法、一套编译张量算法所需计算参数的初始化的方法、内存管理策略、以及一套可供运行支持本发明方法的软件的硬件平台实施例。

本发明的效果在于:

1、提供了一种内存管理方法

2、降低了软硬件系统的整体成本

3、提高了嵌入式系统的性能

4、适合于低成本嵌入式ASIC上应用。

附图说明

图1为深度神经网络优化其运行功能时所需存储的方法框图;

图2为本发明所述神经网络存储区描述和层数据描述区根据网络配置静态分配的主流程图;

图3为本发明所述人工智能神经网络算法数据处理过程图;

图4为本发明所述数据宏块的可能的内存地址分布示意图;

图5为本发明所述可部署所述人工智能算法推理软件的硬件平台;

图6为本发明所述神经网络存储区描述和层数据描述区根据网络配置静态分配的初始化层只读数据描述项流程图;

图7为本发明所述神经网络存储区描述和层数据描述区根据网络配置静态分配的初始化不复用层读写数据存储区描述流程图;

图8为本发明所述神经网络存储区描述和层数据描述区根据网络配置静态分配的初始化层读写数据描述项流程图;

附图标记说明

layer 神经网络层

ro Read only,神经网络只读存储区

rw Read Write,神经网络可读可写存储区

buffer 神经网络存储区

stack 神经网络存储区描述的栈描述

data 神经网络数据描述区

content 神经网络数据项描述

CPU 一般处理器,用于进行软件指令的执行,以调度与配置各种硬件装置

AIoC 智能处理硬件子系统,包括CPU以及专用于智能硬件处理的功能硬件装置、存储装置、调试装置以及其他系统辅助装置

MOA 张量、矩阵类数据操作加速器,专用于该数据类型的特定运算的硬件算子装置

VOA 矢量数据操作加速器,专用于该数据类型的特定运算的硬件算子装置

SOA 标量数据操作加速器,专用于该数据类型的特定运算的硬件算子装置

DMA 动态随机存储访问装置,专用于各种数据类型的搬运

DDR 双速率动态随机存储器,一种优选的系统内存。

具体实施方式

下面通过附图和实施例,对本发明做进一步的详细描述。

结合类似图像处理的算法特点与软件开发工程方法,对数据管理与内存划分做以下基本定义,其特征为,数据帧分为channel(r/g/b, y/u/v…数目或标签为n)每个channel对应的是一张图(map),图分割宏块(Macro Block,MB),宏块分割为片(Tile),片分为块(Block)。输出map也有多组,对应多个输出channel(数目或标签为m),输入MB会累加到输出MB上去。宏块MB表示从主要的大块存储区域填充一次计算缓存的数据区域。输入数据的MB尺寸根据硬件计算缓存的规模和简化控制计算需要、并通过软件定义,其尺寸设定支持如图4所示3种:图4左侧所示为line型数据,其物理地址按照整行排列;图4中间所示为raw型数据,其物理地址的排列,在主存储区的物理拓补实现空间中存在换行顺序排列的情况;图4右侧所示为super raw型数据。以上三种尺寸设定都可以用{起始地址,数据高度,数据长度}的描述来定义,只有在考虑主存储区的物理拓补实现空间及其访问效率时,还需要增加特定的有关参数,例如在某个实施例中的{line尺寸,page尺寸或bank参数}来描述。

图3为本发明所述人工智能神经网络算法数据处理过程图。对于一个任意的神经网络算法,都可以拆分为神经节点层,每层都有相应的输入数据和输出数据,同时上一层的输出数据往往是下一层的输入数据,从而构成整体神经网络。图3所示就是其中一层从输入数据到输出数据的处理过程。在图3一侧是输入层数据(一组二维map构成的张量数据),其下方是参数输入层数据(高维的张量数据,按照特定的维度进行排布)。在map中划分数据宏块区域(MB),宏块中划分数据片区域(tile),数据片中划分数据块区域(block)。数据宏块会从存储中装填到靠近硬件算子的数据缓存中,针对宏块内的算子计算均由硬件算子加速完成;硬件处理输出的数据构成输出数据宏块,也会先存储在数据缓存中,然后再搬运回到存储中,排布成输出map。以上过程中,初始化map的存储区域由本发明所述的自动分析神经网络算法来配置初始化数据分配的软件过程来完成,是在神经网络算法编译的过程中就完成的;输入、输出数据宏块的搬运则是部署软件根据编译的结果所生成的代码指令来调度硬件DMA单元来自动完成的。

根据本发明所述以上定义,对于任意卷积神经网络,其参数规模为m*n个块(每个块为一个卷积核,其中实际包括K*K个数据),其数据初始化排布为m/tm个参数输入map图,其中划分为tm个参数输入数据宏块。卷积计算的部分结果(partial)与输出数据分割概念完全相同。所有宏块级的搬运也是部署软件根据编译的结果所生成的代码指令来调度硬件DMA单元来自动完成的。

图1为深度神经网络优化其运行功能时所需存储的方法框图。图1分为上下两个框,分别标为:上边的1框,面向存储区域进行描述;下边的2框,面向神经网络算法每一层需要管理的数据进行描述。在图1的方框描述区左侧,是一列内存调度与控制的描述维度,根据这些维度,一方面在图3描述框中列出相应的描述关系,另一方面构成了基本数据类和数据结构设计的框架。

如图1所示,在编译初始化时起初,存储空间总体上分为只读(layer_ro_buffer)和读写(layer_rwN_buffer)两种属性。其中所述只读属性由神经网络算法本身决定,读写属性需要通过编译后分析其静态分配。在较细的维度,框图1给出了存储区域的具体描述,这些描述作为相关区域的一个管理索引表,在存储区域中占据很少的空间。区域被划分直到MB层级,本发明所述优化存储的方法需要用到map层级,即图3所示的层或栈,在这个层级上完成对存储区域的分配和复用。更具体的颗粒度分割如图3最下边的图例所示。

在对神经网络算法进行编译时,编译软件根据特定的方法,静态的将层数据描述的相关地址指向存储区地址,存在两种情形:层数据的基地址指向上一层的读写数据区域的基地址;层数据的基地址指向上一层的读写数据区域的基地址加上一个特定的偏移地址。本发明所述的自动分析神经网络算法来配置初始化数据分配的方法,其特征为,自动处理上述两种情形,其软件过程如图2所述。

图2为本发明所述神经网络存储区描述和层数据描述区根据网络配置静态分配的主流程图,在这个过程中完成根据网络配置,并获取网络层数。首先初始化所有神经网络数据的数据存储区,数据存储区描述,层数据描述区数据为0,并且设置设置数据存储区描述的数据存储区的基地址和长度信息,之后对每一层完成初始化层只读数据描述项、初始化不复用层读写数据存储区描述和初始化层读写数据描述项。初始化层只读数据描述项功能如图6所示,根据网络配置,获取层只读数据项数和每个只读数据项长度信息, 由于只读数据项不复用,设置栈的层偏移为栈的上一层偏移加上只读数据存储区描述的偏移,重新设置只读存储区描述的偏移为0,对每一个数据项设置只读数据描述的长度,偏移,基地址和层号,增加只读数据存储区描述的偏移加上只读数据项的长度,并且设置只读数据存储区描述的层栈的层长度为已处理的只读数据项的总长度。初始化不复用层读写数据存储区描述如图7表示,根据网络配置获取保留层数和每个保留层号信息,对每一个保留层,如果保留层为偶数层,该层数据在数据存储区0,否则该层数据在数据存储区1,设置数据在保留层的后一层和当前处理层之间的所有层保留,计算新的数据存储区描述的栈描述的层偏移,对从保留层下一层到当前层的每一个层设置新的数据存储区的栈描述的层偏移。初始化层读写数据描述项如图8所示,根据网络配置信息获取层读写数据项数和每个读写数据项长度,如果层为偶数层,该层数据在数据存储区0,否则该层数据在数据存储区1,重新设置读写存储区描述的偏移为0,对每一个数据项设置读写数据描述的长度,偏移,基地址和层号,增加读写数据存储区描述的偏移加上读写数据项的长度,并且设置读写数据存储区描述的层栈的层长度为已处理的读写数据项的总长度。

在一个实施例中,神经网络存储区描述的栈描述数据结构如下:

typedef struct ai_net_layer_buffer_stack_struct {

UINT32_T layer_length;

UINT32_T layer_offset;

} AI_NET_LAYER_BUFFER_STACK, *AI_NET_LAYER_BUFFER_STACK_PTR;

在一个实施例中,神经网络存储区描述的数据结构如下:

typedef struct ai_net_layer_buffer_struct {

UINT8_T *buffer;

UINT32_T offset;

UINT32_T length;

AI_NET_LAYER_BUFFER_STACK stack[AI_NET_LAYER_MAX];

} AI_NET_LAYER_BUFFER, *AI_NET_LAYER_BUFFER_PTR;

在一个实施例中,神经网络层数据描述区的数据描述项的数据结构如下:

typedef struct ai_net_layer_content_struct {

AI_NET_LAYER_BUFFER *layer_buffer;

UINT32_T offset;

UINT32_T length;

INT32_T layer_index;

} AI_NET_LAYER_CONTENT, *AI_NET_LEYER_CONTENT_PTR;

在一个实施例中,神经网络层数据描述区的一层数据描述区的数据结构如下:

typedef struct ai_net_layer_data_struct {

AI_NET_LAYER_CONTENT ro_content[AI_NET_LAYER_RO_CONTENT_MAX];

AI_NET_LAYER_CONTENT rw0_content[AI_NET_LAYER_RW0_CONTENT_MAX];

AI_NET_LAYER_CONTENT rw1_content[AI_NET_LAYER_RW1_CONTENT_MAX];

} AI_NET_LAYER_DATA, *AI_NET_LAYER_DATA_PTR;

在一个实施例中,深度神经网络优化其运行功能时所需存储的数据结构描述如下:

typedef struct ai_net_layer_struct {

UINT8_T layer_ro_buffer[AI_NET_LAYER_RO_MEM_LENGTH_MAX];

AI_NET_LAYER_BUFFER layer_ro;

UINT8_T layer_rw0_buffer[AI_NET_LAYER_RW0_MEM_LENGTH_MAX];

AI_NET_LAYER_BUFFER layer_rw0;

UINT8_T layer_rw1_buffer[AI_NET_LAYER_RW1_MEM_LENGTH_MAX];

AI_NET_LAYER_BUFFER layer_rw1;

AI_NET_LAYER_DATA layer_data[AI_NET_LAYER_MAX];

} AI_NET_LAYER, *AI_NET_LAYER_PTR;

在一个实施例中,根据以上定义,神经网络所需存储的数据实例化如下:

AI_NET_LAYER_DATA g_ai_layer_data;

根据神经网络配置初始化神经网络所需存储的数据的方法,如图2过程所述,部分关键伪代码表示如下:

ERROR_T AiNetLayerInit(void)

{

net_layer = &( g_ai_layer_data);

layer_ro = &(net_layer->layer_ro);

layer_rw0 = &(net_layer->layer_rw0);

layer_rw1 = &(net_layer->layer_rw1);

/* 神经网络数据存储区及存储区描述初始化 */

AiNetLayerBufferInit(layer_ro, net_layer->layer_ro_buffer, AI_NET_LAYER_RO_MEM_LENGTH_MAX);

AiNetLayerBufferInit(layer_rw0, net_layer->layer_rw0_buffer, AI_NET_LAYER_RW_MEM_LENGTH_MAX);

AiNetLayerBufferInit(layer_rw1, net_layer->layer_rw1_buffer, AI_NET_LAYER_RW_MEM_LENGTH_MAX);

/* 初始化每层神经网络数据存储 */

for (layer_index = 0; layer_index < AI_NET_LAYER_MAX; layer_index++) {

/* 只读数据在神经网络各层之间不能复用,所以只读数据存储区的只读数据存储区描述的栈描述的偏移增加 */

AiNetLayerBufferSetLayerOffset(layer_ro, layer_index);

/* 由于数据复用,初始化一层神经网络数据存储后,清除数据存储区的数据存储区描述的偏移 */

AiNetLayerBufferInitOffset(layer_ro);

AiNetLayerBufferInitOffset(layer_rw0);

AiNetLayerBufferInitOffset(layer_rw1);

/* 初始化神经网络一层数据描述区的数据项 */

AiNetLayerSetLayer(layer_index);

}

return AI_ERROR_SUCCESS;

}

在一个实施例中,神经网络数据存储区及存储区描述初始化方法,伪代码表示如下:

ERROR_T AiNetLayerBufferInit(AI_NET_LAYER_BUFFER *layer_buffer,UINT8_T *buffer, UINT32_T length)

{

UINT32_T layer_index;

for (layer_index = 0; layer_index < AI_NET_LAYER_MAX; layer_index++) {

layer_buffer->stack[layer_index].layer_length = 0;

layer_buffer->stack[layer_index].layer_offset = 0;

}

layer_buffer->offset = 0;

layer_buffer->length = length;

layer_buffer->buffer = buffer;

return AI_ERROR_SUCCESS;

}

本发明定义只读数据在神经网络各层之间不能复用,所以只读数据存储区的只读数据存储区描述的栈描述的偏移增加,在一个实施例中,该步骤伪代码表示如下:

ERROR_T AiNetLayerBufferSetLayerOffset(AI_NET_LAYER_BUFFER *layer_buffer, UINT32_T layer_index)

{

if (layer_index == 0) {

layer_buffer->stack[layer_index].layer_offset = layer_buffer->offset;

} else {

layer_buffer->stack[layer_index].layer_offset = layer_buffer->offset+ layer_buffer->stack[layer_index-1].layer_offset;

}

return AI_ERROR_SUCCESS;

}

作为本发明所述方法的必要步骤,由于数据复用,初始化一层神经网络数据存储后,清除数据存储区的数据存储区描述的偏移,在一个实施例中,该步骤的伪代码表示如下:

ERROR_T AiNetLayerBufferInitOffset(AI_NET_LAYER_BUFFER *layer_buffer)

{

layer_buffer->offset = 0;

return AI_ERROR_SUCCESS;

}

初始化神经网络一层数据描述区的数据项的方法,在一个实施例中,伪代码表示如下:

ERROR_T AiNetLayerSetLayer(UINT32_T layer_index)

{

net_layer = &( g_ai_layer_data);

/* 只读数据不复用,直接取只读数据存储区描述 */

layer_ro = &(net_layer->layer_ro);

/* 初始化只读数据描述区的只读数据描述项 */

For (ro_index = 0; ro_index < AI_NET_LAYER_RO_CONTENT_MAX; ro_index++) {

AiNetLayerContentInit(&layer_data->ro_content[ro_index], ro_content_length, layer_ro, layer_index);

}

/* 获取非前一层的数据不复用层数和层数组,通过设置数据存储区描述的栈描述的偏移实现不复用数据 */

AiGetLayerIndexReservedArray(&layer_index_reserved_array, &AI_NET_LAYER_RW_RESERVED_MAX);

For (rw_reserved_index = 0; rw_reserved_index < AI_NET_LAYER_RW_RESERVED_MAX; rw_reserved_index++) {

if ((layer_index_reserved_array[rw_reserved_index] % 2) == 0) {

layer_reserved_rw = &(net_layer->layer_rw0);

} else {

layer_reserved_rw = &(net_layer->layer_rw1);

}

layer_index_start = layer_index_reserved_array[rw_reserved_index] + 1;

layer_index_end = layer_index;

AiNetLayerBufferLayerOffsetStack(layer_reserved_rw, layer_index_start, layer_index_end);

}

/* 由于读写数据复用原因,读写数据存储区复用 */

if ((layer_index % 2) == 0) {

layer_rw = &(net_layer->layer_rw0);

rw_content = net_layer->rw0_conent;

} else {

layer_rw = &(net_layer->layer_rw1);

rw_content = net_layer->rw1_content;

}

/* 初始化读写数据描述区的读写数据描述项 */

For (rw_index = 0; rw_index < AI_NET_LAYER_RW_CONTENT_MAX; rw_index++) {

AiNetLayerContentInit(&rw_content[rw_index], rw_content_length,layer_rw, layer_index);

}

return AI_ERROR_SUCCESS;

}

获取非前一层的数据不复用起始层和结束层, 通过设置数据存储区描述的栈描述的偏移实现不复用数据,在一个实施例中,所述方法伪代码形式表示如下:

ERROR_T AiNetLayerBufferLayerOffsetStack(AI_NET_LAYER_BUFFER *layer_buffer, UINT32_T layer_index_start, UINT32_T layer_index_end)

{

stack = &(layer_buffer->stack[layer_index_start - 1]);

/* 计算新的栈偏移 */

layer_offset_base = stack->layer_offset + stack->layer_length;

/* 修改后续的层的栈偏移 */

for (layer_index = layer_index_start; layer_index <= layer_index_end;layer_index++) {

stack = &(layer_buffer->stack[layer_index]);

stack->layer_offset = layer_offset_base + stack->layer_offset;

}

return AI_ERROR_SUCCESS;

}

初始化数据描述区的数据描述项的方法,在一个实施例中,伪代码表示如下:

ERROR_T AiNetLayerContentInit(AI_NET_LAYER_CONTENT *layer_content,UINT32_T length, AI_NET_LAYER_BUFFER *layer_buffer, UINT32_T layer_index)

{

/* 修改数据存储区的数据描述信息,偏移增加,数据空间静态分配 */

offset = layer_buffer->offset;

layer_buffer->offset = offset + length;

layer_buffer->stack[layer_index].layer_length = layer_buffer->offset;

/* 设置数据描述区的数据项描述 */

layer_content->length = length;

layer_content->offset = offset;

layer_content->layer_buffer = layer_buffer;

layer_content->layer_index = layer_index;

return AI_ERROR_SUCCESS;

}

获取神经网络数据项在神经网络数据存储区中的数据起始地址的方法,伪代码表示如下:

UINT8_T *AiNetLayerContentGetAddress(AI_NET_LAYER_CONTENT *layer_content)

{

/* 获取数据存储区基地址 */

base_address = layer_content->layer_buffer->buffer;

/* 获取数据描述项的偏移 */

offset = layer_content->offset;

/* 获取层号 */

layer_index = layer_content->layer_index;

/* 计算在数据存储区中的偏移: 数据描述项的偏移+数据存储区描述的层的栈描述的偏移 */

offset += layer_content->layer_buffer->stack[layer_index].layer_offset;

/* 计算数据项的数据起始地址:数据存储区基地址 + 数据项在数据存储区中的偏移 */

base_address = base_address + offset;

return base_address;

}

在一个实施例中,如图5所示的硬件平台,可部署应用了本发明所述优化内存方法的人工智能算法推理软件。该硬件系统由支持特定指令的CPU、子系统互联总线、DDR存储、一系列经过针对应用领域定制的算子加速器硬件设备以及子系统辅助外部设备组成。在该实施例中,所述一系列经过针对应用领域定制的算子加速器硬件设备包括MOA、VOA、SOA和DMA等硬件设备。在该实施例中,其中CPU负责执行应用了本发明所述优化内存方法的人工智能算法推理软件中的指令;本发明所述的数据存储及优化方法针对的就是其中的DDR存储。

以上所述的具体实施方式,对本发明的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本发明的具体实施方式而已,并不用于限定本发明的保护范围,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。

相关技术
  • 一种神经网络计算的内存管理方法
  • 一种神经网络前向计算过程中的内存管理方法及设备
技术分类

06120113098051