Files
wehub-resource-sync 7254f7b4d1
Build / Build (macos-latest) (push) Waiting to run
Build / Build (ubuntu-latest) (push) Waiting to run
Build / Build (windows-latest) (push) Waiting to run
Build / Analyze (javascript) (push) Waiting to run
Build / Analyze (python) (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 12:37:45 +08:00

337 lines
13 KiB
Python

""" ONNX metadata script """
import collections
import json
import os
import re
import onnx.backend.test.case
import onnx.defs
import onnx.onnx_ml_pb2
import onnxruntime
attribute_type_table = [
"undefined",
"float32",
"int64",
"string",
"tensor",
"graph",
"float32[]",
"int64[]",
"string[]",
"tensor[]",
"graph[]",
"sparse_tensor",
"sparse_tensor[]",
"type_proto",
"type_proto[]"
]
def _format_description(description):
def replace_line(match):
link = match.group(1)
url = match.group(2)
if not url.startswith("http://") and not url.startswith("https://"):
url = "https://github.com/onnx/onnx/blob/master/docs/" + url
return "[" + link + "](" + url + ")"
return re.sub('\\[(.+)\\]\\(([^ ]+?)( "(.+)")?\\)', replace_line, description)
def _format_range(value):
return "∞" if value == 2147483647 else str(value)
class OnnxSchema:
""" ONNX schema """
def __init__(self, schema, snippets):
self.schema = schema
self.snippets = snippets
self.name = self.schema.name
self.module = self.schema.domain if self.schema.domain else "ai.onnx"
self.version = self.schema.since_version
self.key = self.name + ":" + self.module + ":" + str(self.version).zfill(4)
def _get_attr_type(self, attribute_type, attribute_name, op_type, op_domain):
key = op_domain + ":" + op_type + ":" + attribute_name
if key in (":Cast:to", ":EyeLike:dtype", ":RandomNormal:dtype"):
return "DataType"
return attribute_type_table[attribute_type]
def _get_attr_default_value(self, attr_value):
if attr_value.HasField("i"):
return attr_value.i
if attr_value.HasField("s"):
return attr_value.s.decode("utf8")
if attr_value.HasField("f"):
return attr_value.f
return None
def _update_attributes(self, value, schema):
target = value["attributes"] = []
attributes = sorted(schema.attributes.items())
for _ in collections.OrderedDict(attributes).values():
value = {}
value["name"] = _.name
attr_type = self._get_attr_type(_.type, _.name, schema.name, schema.domain)
if attr_type:
value["type"] = attr_type
value["required"] = _.required
default_value = self._get_attr_default_value(_.default_value)
if default_value:
value["default"] = default_value
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_inputs(self, value, inputs):
target = value["inputs"] = []
for _ in inputs:
value = {}
value["name"] = _.name
value["type"] = _.type_str
if _.option == onnx.defs.OpSchema.FormalParameterOption.Optional:
value["option"] = "optional"
elif _.option == onnx.defs.OpSchema.FormalParameterOption.Variadic:
value["list"] = True
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_outputs(self, value, outputs):
target = value["outputs"] = []
for _ in outputs:
value = {}
value["name"] = _.name
value["type"] = _.type_str
if _.option == onnx.defs.OpSchema.FormalParameterOption.Optional:
value["option"] = "optional"
elif _.option == onnx.defs.OpSchema.FormalParameterOption.Variadic:
value["list"] = True
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_type_constraints(self, value, type_constraints):
value["type_constraints"] = []
for _ in type_constraints:
value["type_constraints"].append({
"description": _.description,
"type_param_str": _.type_param_str,
"allowed_type_strs": _.allowed_type_strs
})
def _update_snippets(self, value, snippets):
target = value["examples"] = []
for summary, code in sorted(snippets):
lines = code.splitlines()
while len(lines) > 0 and re.search("\\s*#", lines[-1]):
lines.pop()
if len(lines) > 0 and len(lines[-1]) == 0:
lines.pop()
target.append({
"summary": summary,
"code": "\n".join(lines)
})
def to_dict(self):
""" Serialize model to JSON message """
value = {}
value["name"] = self.name
value["module"] = self.module
value["version"] = self.version
if self.schema.support_level != onnx.defs.OpSchema.SupportType.COMMON:
value["status"] = self.schema.support_level.name.lower()
description = _format_description(self.schema.doc.lstrip())
if len(description) > 0:
value["description"] = description
if self.schema.attributes:
self._update_attributes(value, self.schema)
if self.schema.inputs:
self._update_inputs(value, self.schema.inputs)
value["min_input"] = self.schema.min_input
value["max_input"] = self.schema.max_input
if self.schema.outputs:
self._update_outputs(value, self.schema.outputs)
value["min_output"] = self.schema.min_output
value["max_output"] = self.schema.max_output
if self.schema.min_input != self.schema.max_input:
value["inputs_range"] = _format_range(self.schema.min_input) + " - " \
+ _format_range(self.schema.max_input)
if self.schema.min_output != self.schema.max_output:
value["outputs_range"] = _format_range(self.schema.min_output) + " - " \
+ _format_range(self.schema.max_output)
if self.schema.type_constraints:
self._update_type_constraints(value, self.schema.type_constraints)
if self.name in self.snippets:
self._update_snippets(value, self.snippets[self.name])
return value
class OnnxRuntimeSchema:
""" ONNX Runtime schema """
def __init__(self, schema):
self.schema = schema
self.name = self.schema.name
self.module = self.schema.domain if self.schema.domain else "ai.onnx"
self.version = self.schema.since_version
self.key = self.name + ":" + self.module + ":" + str(self.version).zfill(4)
def _get_attr_type(self, attribute_type):
return attribute_type_table[attribute_type]
def _get_attr_default_value(self, attr_value):
if attr_value.HasField("i"):
return attr_value.i
if attr_value.HasField("s"):
return attr_value.s.decode("utf8")
if attr_value.HasField("f"):
return attr_value.f
return None
def _update_attributes(self, value, schema):
target = value["attributes"] = []
attributes = sorted(schema.attributes.items())
for _ in collections.OrderedDict(attributes).values():
value = {}
value["name"] = _.name
attribute_type = self._get_attr_type(_.type)
if attribute_type:
value["type"] = attribute_type
value["required"] = _.required
default_value = onnx.onnx_ml_pb2.AttributeProto()
default_value.ParseFromString(_._default_value)
default_value = self._get_attr_default_value(default_value)
if default_value:
value["default"] = default_value
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_inputs(self, value, inputs):
target = value["inputs"] = []
for _ in inputs:
value = {}
value["name"] = _.name
value["type"] = _.typeStr
schemadef = onnxruntime.capi.onnxruntime_pybind11_state.schemadef
if _.option == schemadef.OpSchema.FormalParameterOption.Optional:
value["option"] = "optional"
elif _.option == schemadef.OpSchema.FormalParameterOption.Variadic:
value["list"] = True
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_outputs(self, value, outputs):
target = value["outputs"] = []
for _ in outputs:
value = {}
value["name"] = _.name
value["type"] = _.typeStr
schemadef = onnxruntime.capi.onnxruntime_pybind11_state.schemadef
if _.option == schemadef.OpSchema.FormalParameterOption.Optional:
value["option"] = "optional"
elif _.option == schemadef.OpSchema.FormalParameterOption.Variadic:
value["list"] = True
description = _format_description(_.description)
if len(description) > 0:
value["description"] = description
target.append(value)
def _update_type_constraints(self, value, type_constraints):
value["type_constraints"] = []
for _ in type_constraints:
value["type_constraints"].append({
"description": _.description,
"type_param_str": _.type_param_str,
"allowed_type_strs": _.allowed_type_strs
})
def to_dict(self):
""" Serialize model to JSON message """
value = {}
value["name"] = self.name
value["module"] = self.module
value["version"] = self.version
schemadef = onnxruntime.capi.onnxruntime_pybind11_state.schemadef
if self.schema.support_level != schemadef.OpSchema.SupportType.COMMON:
value["status"] = self.schema.support_level.name.lower()
if self.schema.doc:
description = _format_description(self.schema.doc.lstrip())
if len(description) > 0:
value["description"] = description
if self.schema.attributes:
self._update_attributes(value, self.schema)
if self.schema.inputs:
self._update_inputs(value, self.schema.inputs)
value["min_input"] = self.schema.min_input
value["max_input"] = self.schema.max_input
if self.schema.outputs:
self._update_outputs(value, self.schema.outputs)
value["min_output"] = self.schema.min_output
value["max_output"] = self.schema.max_output
if self.schema.min_input != self.schema.max_input:
value["inputs_range"] = _format_range(self.schema.min_input) + " - " \
+ _format_range(self.schema.max_input)
if self.schema.min_output != self.schema.max_output:
value["outputs_range"] = _format_range(self.schema.min_output) + " - " \
+ _format_range(self.schema.max_output)
if self.schema.type_constraints:
self._update_type_constraints(value, self.schema.type_constraints)
return value
def _metadata():
root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
file = os.path.join(root_dir, "source", "onnx-metadata.json")
with open(file, encoding="utf-8") as handle:
content = handle.read()
categories = {}
content = json.loads(content)
for schema in content:
if "category" in schema:
name = schema["name"]
categories[name] = schema["category"]
types = collections.OrderedDict()
numpy = __import__("numpy")
with numpy.errstate(all="ignore"):
snippets = onnx.backend.test.case.collect_snippets()
for schema in onnx.defs.get_all_schemas_with_history():
schema = OnnxSchema(schema, snippets)
if schema.key not in types:
types[schema.key] = schema.to_dict()
for schema in onnxruntime.capi.onnxruntime_pybind11_state.get_all_operator_schema():
schema = OnnxRuntimeSchema(schema)
if schema.key not in types:
types[schema.key] = schema.to_dict()
for schema in content:
key = f"{schema['name']}:{schema['module']}:{str(schema['version']).zfill(4)}"
if key not in types:
types[key] = schema
types = [types[key] for key in sorted(types)]
for schema in types:
name = schema["name"]
# copy = schema.copy()
# schema.clear()
# schema['name'] = name
# schema['module'] = copy['module']
if name in categories:
schema["category"] = categories[name]
# for key, value in copy.items():
# if key not in schema:
# schema[key] = value
content = json.dumps(types, indent=2)
with open(file, "w", encoding="utf-8") as handle:
handle.write(content)
def main():
_metadata()
if __name__ == "__main__":
main()