microsoft/onnxruntime-extensions

Public

mirrored from https://github.com/microsoft/onnxruntime-extensionsAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
edgchen1/fix_ci

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

onnxruntime_extensions/tools/pre_post_processing/steps/general.py

207lines · modecode

1# Copyright (c) Microsoft Corporation. All rights reserved.
2# Licensed under the MIT License.
3
4import onnx
5from typing import List, Optional
6from ..step import Step
7
8
9class ReverseAxis(Step):
10 """
11 Reverses the data in an axis by splitting and concatenating in reverse order.
12 e.g. convert RGB ordered data to BGR.
13 Output data type and shape is the same as the input.
14 """
15
16 def __init__(self, axis: int = -1, dim_value: int = -1, name: Optional[str] = None):
17 """
18 Args:
19 axis: Axis to reverse. Default is last axis.
20 dim_value: Explicit value for size of dimension being reversed.
21 This can be provided if the axis being reversed currently has a symbolic value.
22 Note that this will fail during graph execution if the actual value at runtime does not match.
23 If not provided, the size of the dimension to reverse is inferred from the input shape.
24 name: Optional Step name. Defaults to 'ReverseAxis'
25 """
26 super().__init__(["data"], ["data_with_reversed_axis"], name)
27 self._axis = axis
28 self._dim_value = dim_value
29
30 def _create_graph_for_step(self, graph: onnx.GraphProto, onnx_opset: int):
31 input_type_str, input_shape_str = self._get_input_type_and_shape_strs(graph, 0)
32 input_dims = input_shape_str.split(",")
33 split_dim = input_dims[self._axis]
34
35 if split_dim.isdigit():
36 dim_value = int(split_dim)
37 if self._dim_value != -1:
38 # TODO: Technically we don't require a match here. For now expect it to match.
39 assert dim_value == self._dim_value
40 else:
41 self._dim_value = dim_value
42
43 split_outs = []
44 for i in range(0, self._dim_value):
45 split_outs.append(f"split_out_{i}")
46
47 reverse_graph = onnx.parser.parse_graph(
48 f"""\
49 reverse_axis ({input_type_str}[{input_shape_str}] {self.input_names[0]})
50 => ({input_type_str}[{input_shape_str}] {self.output_names[0]})
51 {{
52 {','.join(split_outs)} = Split <axis = {self._axis}> ({self.input_names[0]})
53 {self.output_names[0]} = Concat <axis = {self._axis}> ({','.join(reversed(split_outs))})
54 }}
55 """
56 )
57
58 return reverse_graph
59
60
61class Squeeze(Step):
62 """
63 ONNX Squeeze
64 """
65
66 def __init__(self, axes: Optional[List[int]] = None, name: Optional[str] = None):
67 """
68 Args:
69 axes: Axes to remove.
70 If None, remove all axes with size of 1. Requires all dimensions to have explicit values.
71 name: Optional Step name. Defaults to 'Squeeze'
72 """
73 super().__init__(["data"], ["squeezed"], name)
74 self._axes = axes
75
76 def _create_graph_for_step(self, graph: onnx.GraphProto, onnx_opset: int):
77 input_type_str, input_shape_str = self._get_input_type_and_shape_strs(graph, 0)
78 dims = input_shape_str.split(",")
79
80 axes = self._axes
81 if not axes:
82 axes = []
83 for idx, dim in enumerate(dims):
84 if not dim.isnumeric():
85 # we can't infer the output shape if there are symbolic dims
86 raise ValueError("Axes must be specified if there are symbolic dimensions.")
87
88 if dim == '1':
89 axes.append(int(idx))
90
91 output_dims = [dim for idx, dim in enumerate(dims) if idx not in axes]
92 output_shape_str = ",".join(output_dims)
93
94 axes_strs = [str(axis) for axis in axes]
95
96 squeeze_graph = onnx.parser.parse_graph(
97 f"""\
98 squeeze ({input_type_str}[{input_shape_str}] {self.input_names[0]})
99 => ({input_type_str}[{output_shape_str}] {self.output_names[0]})
100 {{
101 axes = Constant <value = int64[{len(axes)}] {{{','.join(axes_strs)}}}> ()
102 {self.output_names[0]} = Squeeze({self.input_names[0]}, axes)
103 }}
104 """
105 )
106
107 return squeeze_graph
108
109
110class Transpose(Step):
111 """
112 ONNX Transpose.
113 """
114
115 def __init__(self, perms: List[int], name: Optional[str] = None):
116 """
117 Args:
118 perms: List of integers with permutations to apply.
119 name: Optional Step name. Defaults to 'Transpose'
120 """
121 super().__init__(["X"], ["transposed"], name)
122 self.perms = perms
123
124 def _create_graph_for_step(self, graph: onnx.GraphProto, onnx_opset: int):
125 input_type_str, input_shape_str = self._get_input_type_and_shape_strs(graph, 0)
126 perms_str = ",".join([str(idx) for idx in self.perms])
127 dims = input_shape_str.split(",")
128 output_dims = [dims[axis] for axis in self.perms]
129 output_shape_str = ",".join(output_dims)
130
131 transpose_graph = onnx.parser.parse_graph(
132 f"""\
133 transpose ({input_type_str}[{input_shape_str}] {self.input_names[0]})
134 => ({input_type_str}[{output_shape_str}] {self.output_names[0]})
135 {{
136 {self.output_names[0]} = Transpose <perm = [{perms_str}]> ({self.input_names[0]})
137 }}
138 """
139 )
140
141 return transpose_graph
142
143
144class Softmax(Step):
145 """
146 ONNX Softmax
147 """
148
149 def __init__(self, name: Optional[str] = None):
150 """
151 Args:
152 name: Optional Step name. Defaults to 'Softmax'
153 """
154 super().__init__(["data"], ["probabilities"], name)
155
156 def _create_graph_for_step(self, graph: onnx.GraphProto, onnx_opset: int):
157 input_type_str, input_shape_str = self._get_input_type_and_shape_strs(graph, 0)
158
159 softmax_graph = onnx.parser.parse_graph(
160 f"""\
161 softmax ({input_type_str}[{input_shape_str}] {self.input_names[0]})
162 => ({input_type_str}[{input_shape_str}] {self.output_names[0]})
163 {{
164 {self.output_names[0]} = Softmax ({self.input_names[0]})
165 }}
166 """
167 )
168
169 return softmax_graph
170
171
172class Unsqueeze(Step):
173 """
174 ONNX Unsqueeze
175 """
176
177 def __init__(self, axes: List[int], name: Optional[str] = None):
178 """
179 Args:
180 axes: List of integers indicating the dimensions to be inserted.
181 name: Optional Step name. Defaults to 'Unsqueeze'
182 """
183 super().__init__(["data"], ["expanded"], name)
184 self._axes = axes
185
186 def _create_graph_for_step(self, graph: onnx.GraphProto, onnx_opset: int):
187 input_type_str, input_shape_str = self._get_input_type_and_shape_strs(graph, 0)
188 dims = input_shape_str.split(",")
189
190 for idx in self._axes:
191 dims.insert(idx, "1")
192
193 output_shape_str = ",".join(dims)
194 axes_strs = [str(axis) for axis in self._axes]
195
196 unsqueeze_graph = onnx.parser.parse_graph(
197 f"""\
198 unsqueeze ({input_type_str}[{input_shape_str}] {self.input_names[0]})
199 => ({input_type_str}[{output_shape_str}] {self.output_names[0]})
200 {{
201 axes = Constant <value = int64[{len(self._axes)}] {{{','.join(axes_strs)}}}> ()
202 {self.output_names[0]} = Unsqueeze ({self.input_names[0]}, axes)
203 }}
204 """
205 )
206
207 return unsqueeze_graph
208