跳转至

NPU编译器使用*

在使用 NPU 编译器gxnpuc前,请仔细阅读下面两篇技术文档:

gxnpuc用于将开源框架的网络模型文件转换为适配国芯 NPU 处理器的离线模型文件;

1. gxnpuc 工具链功能及对应参数简述*

1.1 常规功能参数*

--help

  • 参数说明:

    打印 gxnpuc 工具链的相关参数说明

  • 使用示例

    $ gxnpuc --help
    
    usage: gxnpuc [-h] [--cmpt] [--list] [-c {LEO,APUS,GRUS,V100,V120,V150}]
                  [-f {TF,PT}] [-V] [-v] [-m] [-w] [-s] [-q]
                  [config_filename]
    
    NPU Compiler
    
    positional arguments:
      config_filename       config file
    
    optional arguments:
      -h, --help            show this help message and exit
      --cmpt                get version compatibility information between npu-
                            core, python, and frameworks
      --list                list supported ops
      -c {LEO,APUS,GRUS,V100,V120,V150}, --core_name {LEO,APUS,GRUS,V100,V120,V150}
                            subparameter of --list, specify NPU Core for listing
                            supported ops
      -f {TF,PT}, --framework {TF,PT}
                            subparameter of --list, specify Deep Learning
                            Framework for listing supported ops
      -V, --version         show program's version number and exit
      -v, --verbose         verbosely list the processed ops
      -m, --meminfo         verbosely list memory info of ops
      -w, --weights         print compressed weights (GRUS only)
      -s, --save_hist       save histograms of weights value to 'npu_jpgs'
                            directory (GRUS only)
      -q, --quant           inference and generate quant file
    

--version

  • 参数说明:

    显示当前编译器版本信息

  • 使用示例

    gxnpuc --version
    

--list

  • 参数说明:

    列出当前NPU编译器支持的算子信息

  • 关联子参数

    子参数仅在 --list 参数使用时有效,且无强制要求使用

    -c

    指定芯片版本,参数值可选范围: {LEO,APUS,GRUS,V100,V120,V150}
    

    -f

    指定前端深度学习框架,参数值可选范围: {TF、PT}
    
  • 使用示例:

    列出当前 NPU 编译器支持的全部算子信息

    gxnpuc --list
    

    列出当前 NPU APUS 编译器支持的全部算子信息

    gxnpuc --list -c APUS
    

    列出当前 NPU APUS 编译器支持的全部 PyTorch 算子信息

    gxnpuc --list -c APUS -f PT
    

--cmpt

  • 参数说明:

    打印编译器所支持的Python、芯片型号、前端DL框架版本信息,以及三者之间的兼容关系

  • 使用示例:

    gxnpuc --cmpt
    

1.2 模型编译转换参数*

config_filename

  • 参数说明:

    指定编译配置文件的路径以及文件名,模型转换及模型调优时会读取该配置文件

  • 关联子参数(仅在 config_filename 正确配置时有效)

    -v

    功能描述: 编译模型时,打印 NPU 模型结构信息
    

    -m

    功能描述: 编译模型时,打印 NPU 模型中各算子节点使用的内存状态
    
  • 使用示例:

    NPU APUS 编译器以 config.yaml 为原始模型的转换配置文件,同时开启所有子参数功能

    gxnpuc config.yaml -v -m -w -s
    

gxnpuc功能参数使用注意事项

上述 --version/-V, --list, --cmpt, config_filename 四组参数互斥,不能同时使用

2. 模型编译转换配置文件说明*

2.1 TensorFlow 配置项*

配置项 参数取值 参数说明
CORENAME APUS 芯片型号
FRAMEWORK TF 指定待转换模型的前端DL框架类型
MODEL_FILE 模型文件名及路径 例: ./model.pb 指定待转换模型的文件名及路径
IN_FEATS_FILE 模型输入特征及路径 例: ./feats.txt 用于量化推理过程中计算所有节点的量化参数值
QUANT_FILE 量化文件名 例: quant.yaml 指定编译器量化推理过程生成的量化文件名称
OUTPUT_TYPE c_code 指定编译器输出 NPU 文件的格式
OUTPUT_FILE NPU文件名 例: npu.h 指定编译器输出 NPU 文件的名称
INPUT_OPS op_name: shape 指定 NPU 模型所有输入节点的相关信息
OUTPUT_OPS [output_name, ...] 指定 NPU 模型所有输出节点的相关信息
COMPRESS true / false (默认值 false) 是否使能全连接权重量化压缩功能
MAX_CACHE_SIZE 具体分配的内存值 例: 10240 SRAM 中开辟 CACHE 内存,用于存储权重和 data
USE_DATA_CACHE true / false (默认值 false) 是否需要将 data 存放于 cache 中, 当data存放在PSRAM时,可设置为true
FUSE_BN true / false (默认值 false) 是否使能 BN 参数融合功能
SPLIT_CMD true / false (默认值 true) 是否需要根据卷积的执行时间拆分指令(一条指令拆分到1ms之内)

注意事项

  • 待转换的原始模型必须为 FrozenPB 格式
  • APUS编译器不支持BN的操作,待转换的原始模型带有BN操作的,在编译时必须选择将BN融合在权重信息中

IN_FEATS_FILE

  • 文件格式

    每一行代表一组输入特征,每行数据的排布方式以及数据长度与输入特征的维度保持一致,并且特征值之间以逗号分割;此外,各行数据之间也是以逗号分割。 提供的特征数据尽可能涵盖应用的各种场景。

  • 使用示例

    模型应用在安静、家庭聊天、白噪的环境中,用户需要在每个环境中随机挑选一段wav,然后将这些wav合成为一条,提取出其特征文件。 例如config.yaml文件中配置Feats: [1, 1, 10],故特征文件格式如下:

    feats.txt
    0.3826,0.3445,0.2839,0.4637,0.3573,0.7226,0.8244,0.135,0.202,0.9004,
    0.402,0.50962,0.6991,0.4234,0.28219,0.1980,0.31208,0.687,0.0483,0.5683,
    ...
    0.3176,0.35404,0.9429,0.919,0.14952,0.9451,0.6569,0.227,0.19459,0.023,
    0.43631,0.2177,0.663,0.3806,0.393,0.38857,0.7234,0.60385,0.0879,0.0696,
    

INPUT_OPS

  • 参数格式

    op_name: shape

    op_name —— 模型输入节点的名称
    
    shape   —— 对应节点名为 op_name 的输入在推理时的 shape
    
  • 使用示例

    TensorFlow 框架中搭建模型时,通常定义占位符作为计算图的输入,用户需要为占位符指定具体的标识符作为输入名称

    本例代码中,模型定义了四组占位符(模型输入),并分别配置 Feats、State_c0、State_c1、State_c2 标识符作为输入名称

    其中 state0_in、state1_in、state2_in 为上一帧输出状态值(初始帧时为全零张量)

    inputs    = tf.placeholder(tf.float32, [1, 1, 64], name="Feats")
    state0_in = tf.placeholder(tf.float32, [1, 3, 64], name="State_c0")
    state1_in = tf.placeholder(tf.float32, [1, 4, 64], name="State_c1")
    state2_in = tf.placeholder(tf.float32, [1, 5, 64], name="State_c2")
    

    故该模型配置文件中的 INPUT_OPS 参数可按如下方式配置:

    config.yaml
    INPUT_OPS:
        Feats:    [1, 1, 64]
        State_c0: [1, 3, 64]
        State_c1: [1, 4, 64]
        State_c2: [1, 5, 64]
    

    注意事项

    • 输入状态节点必须放在输入特征后面

OUTPUT_OPS

  • 参数格式

    [output_name, ...]

    output_name 为模型输出节点的名称
    
  • 使用示例

    TensorFlow 框架中搭建模型时,为方便 NPU 的编译配置,用户可以通过 tf.identity 接口对输出张量实现拷贝并重命名的操作

    本例代码中,为四组输出张量分别配置 Result、State_c0_out、State_c1_out、State_c2_out 标识符作为输出名称

    其中 state0_out、state1_out、state2_out 为当前一帧的输出状态值

    outputs, states = fsmn_layer(...)
    
    result_out = tf.identity(outputs,   name="Result")
    state1_out = tf.identity(states[0], name="State_c0_out")
    state2_out = tf.identity(states[1], name="State_c1_out")
    state3_out = tf.identity(states[2], name="State_c2_out")
    

    故该模型配置文件中的 INPUT_OPS 参数可按如下方式配置:

    config.yaml
    OUTPUT_OPS: [State_c0_out, State_c1_out, State_c2_out, Result]
    

    注意事项

    • 输出状态节点必须放在预测输出节点之前

USE_DATA_CACHE

  • 参数格式

    USE_DATA_CACHE: false/true

  • 使用环境

    如果data在PSRAM中,为了降低重复读取数据时的开销,编译模型时可以配置USE_DATA_CACHE为true,数据会从PSRAM拷贝到SRAM中,从而提高数据重复读取的效率

    注意事项

    • 该配置项设置为true时,需要配置MAX_CACHE_SIZE大于0

2.2 PyTorch 配置项*

注意事项

若用户需要编译转换 PyTorch 模型,则 NPU 编译器版本至少 1.6.0b0 以上,且必须使用 Python3.7

配置项 参数取值 参数说明
CORENAME APUS 芯片型号
FRAMEWORK PT 指定待转换模型的前端DL框架类型
MODEL_FILE 模型文件名及路径 例: ./model.pth 指定待转换模型的文件名及路径
IN_FEATS_FILE 模型输入特征及路径 例: ./feats.txt 用于量化推理过程中计算所有节点的量化参数值
QUANT_FILE 量化文件名 例: quant.yaml 指定编译器量化推理过程生成的量化文件名称
OUTPUT_TYPE c_code 指定编译器输出 NPU 文件的格式
OUTPUT_FILE NPU文件名 例: npu.h 指定编译器输出 NPU 文件的名称
INPUT_OPS input_index: shape 指定 NPU 模型所有输入节点的相关信息
INPUT_NCX_TO_NXC [input_index, ...] 是否转换 NPU 模型输入张量的数据排布格式
COMPRESS true / false (默认值 false) 是否使能全连接权重量化压缩功能
MAX_CACHE_SIZE 具体分配的内存值 例: 10240 SRAM 中开辟 CACHE 内存,用于存储权重和 data
USE_DATA_CACHE true / false (默认值 false) 是否需要将 data 存放于 cache 中, 当data存放在PSRAM时,可设置为true
FUSE_BN true / false (默认值 false) 是否使能 BN 参数融合功能
SPLIT_CMD true / false (默认值 true) 是否需要根据卷积的执行时间拆分指令(一条指令拆分到1ms之内)

注意事项

  • 待转换的原始模型必须为 jit.ScriptModule 格式

  • 编译器1.6.0.b0版本以上,Python3.7,PyTorch 1.10 - 1.13

INPUT_OPS

  • 参数格式

    input_index: shape

    input_index —— 输入节点的索引
    
    shape       —— 对应输入在 NPU 模型中的推理 shape
    
  • 使用示例

    由于 PyTorch 框架中采用动态计算图,各算子节点 name 是自动生成的,导致无法为输入配置标识符;

    因此 NPU 编译器转换 PyTorch 模型时,配置文件中 INPUT_OPS 参数采用索引值进行输入张量的映射;

    本例中,以继承 nn.Module 基类的方式来构建自定义 PyTorch 模型,并简述 INPUT_OPS 参数的配置方式:

    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3)
            self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
            self.conv2 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3)
            self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
            self.adaptive_pool = nn.AdaptiveMaxPool2d((1,1))
            self.flatten = nn.Flatten()
            self.linear1 = nn.Linear(64,32)
            self.relu    = nn.ReLU()
            self.linear2 = nn.Linear(32,1)
    
        def forward(self, x, y):
            x = self.conv1(x)
            x = self.pool1(x)
            y = self.conv2(y)
            y = self.pool2(y)
            z = torch.concat([x,y], dim=1)
            z = self.adaptive_pool(z)
            z = self.flatten(z)
            z = self.linear1(z)
            z = self.relu(z)
            y = self.linear2(z)
            return y
    
    net           = Net()
    input0_tensor = torch.randn([1, 3, 32, 32])
    input1_tensor = torch.randn([1, 1, 32, 32])
    
    output_tensor = net(input0_tensor, input1_tensor)
    
    由 forward 方法可知上述模型定义了两组输入 x、y,输入 x 的索引为0,输入 y 的索引为1;

    故该模型配置文件中的 INPUT_OPS 参数可按如下方式配置:

    config.yaml
    INPUT_OPS:
        0: [1, 3, 32, 32]
        1: [1, 1, 32, 32]
    
  • 约束条件

    PyTorch 模型转换时,需要保证输入是张量,不可以是张量列表或张量元组

    NPU 编译器不支持上述类型的输入格式,用户需要将张量列表和张量元组拆分为张量进行输入

    本例模型中,输入采用了张量列表/张量元组(与使用示例中的模型仅在输入有差异)

    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3)
            self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
            self.conv2 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3)
            self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
            self.adaptive_pool = nn.AdaptiveMaxPool2d((1,1))
            self.flatten = nn.Flatten()
            self.linear1 = nn.Linear(64,32)
            self.relu    = nn.ReLU()
            self.linear2 = nn.Linear(32,1)
    
        def forward(self, xy):
            x = self.conv1(xy[0])
            x = self.pool1(x)
            y = self.conv2(xy[1])
            y = self.pool2(y)
            z = torch.concat([x,y], dim=1)
            z = self.adaptive_pool(z)
            z = self.flatten(z)
            z = self.linear1(z)
            z = self.relu(z)
            y = self.linear2(z)
            return y
    
    net           = Net()
    input0_tensor = torch.randn([1, 3, 32, 32])
    input1_tensor = torch.randn([1, 1, 32, 32])
    list_tensor   = [input0_tensor, input1_tensor]
    tuple_tensor  = (input0_tensor, input1_tensor)
    
    # 输入是张量列表
    output_tensor = net(list_tensor)
    
    # 输入是张量元组
    output_tensor = net(tuple_tensor)
    

INPUT_NCX_TO_NXC

  • 参数相关概述

    在深度学习领域中,模型算子节点之间通常采用多维度张量进行数据传输,比如卷积神经网络的特征图通常采用四维度张量存储

    四维度张量的各维度可分别表示为 N: batch; H: height; W: width; C: channels

    由于数据在内存中是以线性排布方式存储,当数据维度的访问顺序变化时,数据在内存中的分布也存在差异; PyTorch 框架中采用 NCHW 顺序,TensorFlow 框架中采用 NHWC 顺序,上述两种访问顺序可称为数据的排布格式(data format)

    NPU 计算密集型算子采用 NHWC、NLC 数据排布格式进行存储,若 NPU 计算密集型算子的输入张量是 NCHW 或 NCL 数据排布格式,则编译器会在该算子前插入转置节点进行数据格式的转换

  • 参数说明

    当原始模型输入张量的数据格式为 NCHW 或 NCL 时,可通过配置该参数,决定 NPU 模型推理时,该输入张量是保持原始 PyTorch 模型中的数据排布格式,还是需要已经 NCHW -> NHWC 或 NCL -> NLC 转换处理后的数据排布格式

  • 参数格式

    [input_index, ...]

    input_index —— 需要进行数据排布格式转换的输入节点的索引
    

    注意事项

    当使能某个输入张量进行数据排布格式转换时,需要同步调整参数 INPUT_OPS 中对应输入的 shape,具体使用可见使用示例

  • 使用示例

    import torch.nn as nn
    
    class Model(torch.nn.Module):
        def __init__(self):
            super(Model, self).__init__()
            self.gru  = torch.nn.GRU(128, 128, batch_first=True, bias=True)
            self.conv = torch.nn.Conv1d(128, 128, 1, 1)
    
        def forward(self, x, h):
            x = self.conv(x)
            x = x.permute(0, 2, 1)
            z = self.gru(x, h)
    
            return z
    
    model        = Model()
    batch        = 1
    seq_length   = 32
    channel      = 128
    input_tensor = torch.randn([batch, channel, seq_length])
    input_state  = torch.randn([1, batch, channel])
    
    output_tensor, output_state = model(input_tensor, input_state)
    

    上述模型在 PyTorch 框架下推理时,input_state 数据排布格式不是 NCL,故无法进行数据排布格式转换;

    input_tensor 数据排布格式为 NCL,故可以选择是否进行数据排布格式转换后,再提供至 NPU 模型输入;

    下面将分别描述格式转换参数使能与不使能的两种情况:

    • 使能参数,输入张量 input_tensor 进行格式转换

      input_tensor 原始模型输入 shape 为 [1, 128, 32],使能格式转换功能后,NPU 模型需要的实际 shape 为 [1, 32, 128]

      模型配置文件的 INPUT_NCX_TO_NXC 和 INPUT_OPS 参数可按如下方式配置:

      config.yaml
      INPUT_NCX_TO_NXC: [0]
      
      INPUT_OPS:
          0: [1, 32, 128]
          1: [1, 1, 128]
      

      下图为模型结构图:

    • 不使能参数,输入张量 input_tensor 保持原始数据排布格式

      模型配置文件的 INPUT_NCX_TO_NXC 和 INPUT_OPS 参数可按如下方式配置:

      config.yaml
      INPUT_NCX_TO_NXC: []
      
      INPUT_OPS:
          0: [1, 128, 32]
          1: [1, 1, 128]
      

      下图为模型结构图:

      不使能 INPUT_NCX_TO_NXC

    对比上述两 NPU 模型结构图可知,格式转换功能开启后,可将输入侧插入的转置节点优化

    该参数能够根据用户需求,更加灵活的设置输入张量的数据格式

3. 编译模型*

3.1 模型文件准备*

NPU编译器严格限制模型文件格式,不同框架需按照指定方式导出。

TensorFlow

  • 准备 TensorFlow 生成的 CKPT 和 PB 文件,或 saved_model 方式生成的模型文件。
  • 通过 TensorFlow 提供的freeze_graph.py脚本生成 FROZEN_PB 文件。

PyTorch

  • 模型训练完成后,导出模型权重文件
  • 构建 PyTorch 推理模型脚本,并生成 PyTorch Module 实例
  • 转换自定义 PyTorch Module 为 Torch ScriptModule,并将 ScriptModule 实例序列化输出为编译器所需的模型文件

    上述步骤具体可参考 PyTorch 模型转换示例

3.2 编写配置文件*

  • 编写 yaml 配置文件,包括 模型文件名,输入特征文件名,输出文件名,输出文件类型,量化文件名,是否压缩,输入节点名和维度信息,输出节点名等

3.3 编译生成模型文件*

编译生成模型文件需要以下两个步骤:

  • 经过模型量化推理生成模型量化文件。
  • 使用编译器生成模型文件。

生成模型量化文件命令如下

$ gxnpuc config.yaml -q
生成模型文件命令如下
$ gxnpuc config.yaml

注意

NPU 工具链编译处理不同深度框架的模型文件时,必须安装对应框架在 NPU 工具链的运行环境 生成的模型文件格式说明请阅读:NPU模型格式说明