标杆数据生成工具
概述
在对 MindSpore Lite 模型进行基准测试前,开发者可以按照约定格式生成标杆数据(Benchmark Data)。基于生成的标杆数据运用benchmark工具进行基准测试,能够对原始模型和转换后的模型精度进行定量分析。
mslite_gold标杆数据生成工具,可基于原始模型输入数据input.npz和推理得到的输出数据output.npz生成标杆数据,本文介绍该工具的用法。
mslite_gold工具使用说明
开发者首先需要将原始模型输入数据和推理得到的输出数据,通过numpy中的savez()命令保存为.npz格式的文件,再通过运行mslite_gold.py 分别将输入数据input.npz和输出数据output.npz转化为.bin和.out的二进制格式文件。
环境要求
python依赖库:
- numpy>= 2.0.2
- onnx>= 1.17.0
- onnxruntime>= 1.19.2
- ast>= 1.6.3
- collection>= 0.1.6
使用示例
python mslite_gold.py --inputFile "/path/to/input.npz" --outputFile "/path/to/output.npz" --savePath "/path/to/save_data"
执行命令后,会在/path/to/save_data/目录中生成如下文件:
- input.bin:输入数据,对每个输入Tensor的数据进行- flatten一维化,单独保存到一个二进制文件- input.bin,不含名称、dtype、shape等元信息。
- output.out:输出数据,所有输出内容保存到一个文本文件,格式如下:
每个输出Tensor占用2行:
name dim shape1 [shape2 ...]
data0 data1 ...
- 第一行:记录输出Tensor的元信息,依次为:名称、维度、形状 
- 第二行:记录输出Tensor的数据。 
示例:
out_0 2 2 3
1.0 2.0 3.0 4.0 5.0 6.0
表示一个名称为out_0,维度是2维,形状是[2, 3],内容是[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]的Tensor。
下面以ONNX模型生成标杆数据为例,详细介绍工具的用法。
- 随机生成输入,进行模型推理,再将输入输出保存为 - .npz格式。- onnx_demo.py示例代码 支持基于ONNX模型随机生成数据,或手动输入数据,并执行推理获得输出数据。手动输入数据时,可以通过参数 - --inDataFile来确定输入数据路径。如果模型是动态shape类型,需通过参数- --inputShape来确定输入尺寸。参数- --inDataFile和- --inputShape非必须,用户可以根据自身的使用场景来自由选用。下面是示例代码的基础使用示例:- python onnx_demo.py --modelFile "/path/to/model_example.onnx" --savePath "/path/to/data_example" - /path/to/data_example/目录中会生成- input.npz和- output.npz文件。
- 将输入输出的 - npz文件转化成标杆数据文件。- python mslite_gold.py --inputFile "/path/to/data_example/input.npz" --outputFile "/path/to/data_example/output.npz" --savePath "/path/to/save_data" - 最后,在 - /path/to/save_data目录中会生成上述的标杆数据文件。
mslite_gold工具代码细节
以下展示标杆数据生成的代码细节,先转换input,再转换output。
import os
import argparse
from collections import OrderedDict
import numpy as np
def save_bin(args):
    if not os.path.exists(args.savePath):
        print(f"mkdir:{args.savePath}")
        os.makedirs(args.savePath)
    try:
        input_dict = np.load(args.inputFile)
        print(f"Loaded inputs from {args.inputFile}: {list(input_dict.keys())}")
    except (FileNotFoundError, PermissionError) as e:
        print(f"Error loading inputs: {e}")
        return
    i = 0
    input_dict = OrderedDict(input_dict)
    for key, input_data in input_dict.items():
        print(f"input {key}: shape={input_data.shape}, dtype={input_data.dtype}")
        if np.issubdtype(input_data.dtype, np.integer):
            input_data.astype(np.int32).flatten().tofile(os.path.join(args.savePath, f"input.bin{i}"))
        else:
            input_data.flatten().tofile(os.path.join(args.savePath, f"input.bin{i}"))
        i = i + 1
    try:
        output_dict = np.load(args.outputFile)
        print(f"Loaded outputs from {args.outputFile}: {list(output_dict.keys())}")
    except (FileNotFoundError, PermissionError) as e:
        print(f"Error loading outputs: {e}")
        return
    opened = 0
    output_dict = OrderedDict(output_dict)
    output_file = os.path.join(args.savePath, 'model.out')
    for i, output_data in output_dict.items():
        print(f"output {i}: shape={output_data.shape}, dtype={output_data.dtype}")
        mode = 'w' if opened == 0 else 'a'
        if str(output_data.shape) == "[]":
            output_shape = [1]
        else:
            output_shape = output_data.shape
        with open(output_file, mode) as text_file:
            opened = 1
            if not output_shape:
                output_shape.append(len(output_data))
            text_file.write(f"{i} {len(output_data.shape)} ")
            text_file.write(" ".join([str(s) for s in output_data.shape]))
            text_file.write('\n')
            print(f"result shape: {len(output_data.flatten())}")
            for k in output_data.flatten():
                text_file.write(f"{k} ")
            text_file.write('\n')
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Save inputs and outputs in specified format")
    parser.add_argument('--inputFile', type=str, required=True, help='Input your specified data.')
    parser.add_argument('--outputFile', type=str, required=True, help='Input your specified data.')
    parser.add_argument('--savePath', type=str, required=True, help="Path to the data directory.")
    para = parser.parse_args()
    save_bin(para)