跳转至

NPU 模型格式说明*

  • NPU编译器使用 这章节中,我们知道跑在 GX8002 上的模型文件是用 gxnpuc config.yaml 生成。
  • 本文对模型文件的结构做一个简单的说明
    model.h
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    // This file is automatically generated by NPU compiler.
    // 模式的输入输出大小+模型运行所占用的空间:sizeof(in_out) + sizeof(cmd_content) + sizeof(weight_content) + sizeof(data_content) + sizeof(tmp_content)
    const unsigned int total_size = 151550;
    
    // 模型运行所占用的空间:sizeof(cmd_content) + sizeof(weight_content) + sizeof(data_content) + sizeof(tmp_content)
    const unsigned int npu_size = 147018;
    
    // gxnpuc 编译器版本
    const char *version = "1.5.3rc7";
    
    // 模型对应的 pb 文件的 md5 值
    const char *pb_md5 = "bfe0140daa3d0440c768eda50ed40265"; 
    
    const char *npu_unit = "NPU32";
    
    // 模型编译的时间
    const char *model_info = "(20220212154001)";
    
    typedef unsigned short npu_data_t;
    
    // 模型的输入结构
    struct input {
        npu_data_t Feats[1][15][40];
        npu_data_t State_c0[1][3][64];
        npu_data_t State_c1[1][4][64];
        npu_data_t State_c2[1][5][64];
    } __attribute__ ((packed));
    
    // 模型的输出结构
    struct output {
        npu_data_t State_c0_out[1][3][64];
        npu_data_t State_c1_out[1][4][64];
        npu_data_t State_c2_out[1][5][64];
        float phone_prob[1][1][65];
    } __attribute__ ((packed));
    
    // 模型的输入+输出结构,对于循环网络来说,方案上依据该结构图设立两个以上的buffer,其中一个buffer作为模型的输入地址, 下一个buffer的 State_c0 作为模型的输出地址,这样可以节省一次模型输出拷贝到下一时刻输入的这个拷贝动作。
    struct in_out {
        npu_data_t Feats[1][15][40];
        npu_data_t State_c0[1][3][64];
        npu_data_t State_c1[1][4][64];
        npu_data_t State_c2[1][5][64];
        float phone_prob[1][1][65];
    } __attribute__ ((packed));
    
    // 模型的指令数组,只读
    const unsigned char cmd_content[5172] __attribute__ ((aligned(4))) = {
        0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 
        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 
        0x04, 0x02, 0x00, 0x00, 0x28, 0x0f, 0x10, 0x00, 0x28, 0x00, 
        ......
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x40, 
        0x02, 0x00, 0x00, 0x00, 0x40, 0x05, 0x10, 0x00, 0x40, 0x00, 
        0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 
    };
    
    // 模型的权重数组,只读
    const unsigned char weight_content[128166] __attribute__ ((aligned(4))) = {
        0x66, 0x3a, 0x6b, 0x40, 0x00, 0x44, 0x7f, 0x45, 0x41, 0x46, 
        0x49, 0x46, 0x6b, 0x46, 0xc9, 0x46, 0x3d, 0x47, 0xfc, 0x46, 
        0xa6, 0x46, 0xc1, 0x46, 0x9d, 0x46, 0x85, 0x46, 0xbe, 0x46, 
        ......
        0x10, 0x54, 0x00, 0x3c, 0x00, 0x3c, 0x10, 0x54, 0x00, 0x3c, 
        0x00, 0x40, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x45, 0x80, 0x4a, 
        0x00, 0xbc, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 
        0x00, 0x3c, 
    };
    
    // 一般为空,只读
    unsigned char *tmp_content = (void*)0;
    
    // 一般为空
    const unsigned char ops_content[0] __attribute__ ((aligned(4))) = {
    };
    
    // 模型运行时所需要临时空间
    unsigned char data_content[13680] __attribute__ ((aligned(4)));