EXPERIMENT / 配套代码

audit_onnx.py

← 返回文章
"""只读审计 ONNX 的接口和算子;不判断海思算子支持与精度。"""
import argparse
from collections import Counter
import hashlib
import json
from pathlib import Path
import onnx

def describe(value):
    tensor = value.type.tensor_type
    shape = [d.dim_value if d.HasField('dim_value') else d.dim_param or '?' for d in tensor.shape.dim]
    return {'name': value.name, 'dtype': onnx.TensorProto.DataType.Name(tensor.elem_type), 'shape': shape}

def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('model', type=Path)
    parser.add_argument('--output', required=True, type=Path)
    args = parser.parse_args()
    if args.output.exists():
        parser.error('输出已存在,请使用新的审计文件')
    model = onnx.load(str(args.model))
    onnx.checker.check_model(model)
    constants = {x.name for x in model.graph.initializer}
    report = {'model': str(args.model), 'bytes': args.model.stat().st_size,
              'main_file_sha256': hashlib.sha256(args.model.read_bytes()).hexdigest(),
              'ir_version': model.ir_version,
              'opsets': [{'domain': x.domain, 'version': x.version} for x in model.opset_import],
              'inputs': [describe(x) for x in model.graph.input if x.name not in constants],
              'outputs': [describe(x) for x in model.graph.output],
              'operators': dict(sorted(Counter((x.domain + '::' if x.domain else '') + x.op_type for x in model.graph.node).items())),
              'notes': ['checker 通过不等于 ATC 支持。', 'external data 模型还需单独保存和校验其外部权重文件。']}
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(report, ensure_ascii=False, indent=2) + '\n')
    print(json.dumps(report, ensure_ascii=False, indent=2))

if __name__ == '__main__':
    main()