Skip to content

Commit cdffb4f

Browse files
committed
Reduce the duplication of layout transfrom matrices
* Change the nhcwb16_to_nhwc matrix for binary and unary elementwise such that it matches the other NPU ops * Reduce the number of places where the same layout transform matrices are defined
1 parent cacd6f5 commit cdffb4f

File tree

11 files changed

+95
-174
lines changed

11 files changed

+95
-174
lines changed

python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
2323

2424
from .dma import dma_ofm_compute, dma_ifm_compute
25+
from .common import get_layout_transform_matrices
2526

2627

2728
def binary_elementwise_compute(
@@ -196,21 +197,8 @@ def binary_elementwise_compute(
196197
attrs=binary_elementwise_attrs,
197198
)
198199

199-
nhwc_to_nhcwb16 = [
200-
[1, 0, 0, 0, 0],
201-
[0, 1, 0, 0, 0],
202-
[0, 0, 0, 1 / 16, 0],
203-
[0, 0, 1, 0, 0],
204-
[0, 0, 0, 0, 16],
205-
[0, 0, 0, 0, 1],
206-
]
207-
nhcwb16_to_nhwc = [
208-
[1, 0, 0, 0, 0, 0],
209-
[0, 1, 0, 0, 0, 0],
210-
[0, 0, 0, 1, 0, 0],
211-
[0, 0, 16, 0, 1, -16],
212-
[0, 0, 0, 0, 0, 1],
213-
]
200+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ifm_channels))
201+
214202
ifm_matrix = [
215203
[1, 0, 0, 0, 0],
216204
[0, 1, 0, 0, 0],
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
"""Common methods for the NPU tensor expressions"""
18+
19+
from typing import Tuple, List
20+
21+
22+
def get_layout_transform_matrices(ofm_channels: int) -> Tuple[List[List[float]], List[List[float]]]:
23+
"""Get the NHWC->NHCWB16 and NHCWB16->NHWC layout transform matrices.
24+
25+
Parameters
26+
----------
27+
ofm_channels : int
28+
The number of output channels in a NHWC layout
29+
30+
Returns
31+
-------
32+
nhwc_to_nhcwb16, nhcwb16_to_nhwc : Tuple[List[List[float]], List[List[float]]]
33+
The layout transformation matrices
34+
"""
35+
36+
nhwc_to_nhcwb16 = [
37+
[1, 0, 0, 0, 0],
38+
[0, 1, 0, 0, 0],
39+
[0, 0, 0, 1 / 16, 0],
40+
[0, 0, 1, 0, 0],
41+
[0, 0, 0, 0, 16],
42+
[0, 0, 0, 0, 1],
43+
]
44+
45+
nhcwb16_to_nhwc = [
46+
[1, 0, 0, 0, 0, 0],
47+
[0, 1, 0, 0, 0, 0],
48+
[0, 0, 0, 1, 0, 0],
49+
[0, 0, 0, 0, 0, ofm_channels],
50+
[0, 0, 0, 0, 0, 1],
51+
]
52+
53+
return nhwc_to_nhcwb16, nhcwb16_to_nhwc

python/tvm/relay/backend/contrib/ethosu/te/convolution.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
2424

2525
from .dma import dma_ofm_compute, dma_ifm_compute
26+
from .common import get_layout_transform_matrices
2627

2728

2829
def conv2d_compute(
@@ -175,21 +176,8 @@ def conv2d_compute(
175176
attrs=conv2d_attrs,
176177
)
177178

178-
nhwc_to_nhcwb16 = [
179-
[1, 0, 0, 0, 0],
180-
[0, 1, 0, 0, 0],
181-
[0, 0, 0, 1 / 16, 0],
182-
[0, 0, 1, 0, 0],
183-
[0, 0, 0, 0, 16],
184-
[0, 0, 0, 0, 1],
185-
]
186-
nhcwb16_to_nhwc = [
187-
[1, 0, 0, 0, 0, 0],
188-
[0, 1, 0, 0, 0, 0],
189-
[0, 0, 0, 1, 0, 0],
190-
[0, 0, 0, 0, 0, ofm_channels],
191-
[0, 0, 0, 0, 0, 1],
192-
]
179+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)
180+
193181
ifm_matrix = [
194182
[1, 0, 0, 0, 0],
195183
[0, stride_h, 0, 0, (dilated_kernel_h - stride_h)],

python/tvm/relay/backend/contrib/ethosu/te/depthwise.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
2424

2525
from .dma import dma_ofm_compute, dma_ifm_compute
26+
from .common import get_layout_transform_matrices
2627

2728

2829
def depthwise_conv2d_compute(
@@ -169,21 +170,8 @@ def depthwise_conv2d_compute(
169170
attrs=depthwise_conv2d_attrs,
170171
)
171172

172-
nhwc_to_nhcwb16 = [
173-
[1, 0, 0, 0, 0],
174-
[0, 1, 0, 0, 0],
175-
[0, 0, 0, 1 / 16, 0],
176-
[0, 0, 1, 0, 0],
177-
[0, 0, 0, 0, 16],
178-
[0, 0, 0, 0, 1],
179-
]
180-
nhcwb16_to_nhwc = [
181-
[1, 0, 0, 0, 0, 0],
182-
[0, 1, 0, 0, 0, 0],
183-
[0, 0, 0, 1, 0, 0],
184-
[0, 0, 0, 0, 0, channels],
185-
[0, 0, 0, 0, 0, 1],
186-
]
173+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(channels)
174+
187175
ifm_matrix = [
188176
[1, 0, 0, 0, 0],
189177
[0, stride_h, 0, 0, (dilated_kernel_h - stride_h)],

python/tvm/relay/backend/contrib/ethosu/te/pooling.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
2424

2525
from .dma import dma_ofm_compute, dma_ifm_compute
26+
from .common import get_layout_transform_matrices
2627

2728

2829
def pooling_compute(
@@ -157,21 +158,8 @@ def pooling_compute(
157158
attrs=pooling_attrs,
158159
)
159160

160-
nhwc_to_nhcwb16 = [
161-
[1, 0, 0, 0, 0],
162-
[0, 1, 0, 0, 0],
163-
[0, 0, 0, 1 / 16, 0],
164-
[0, 0, 1, 0, 0],
165-
[0, 0, 0, 0, 16],
166-
[0, 0, 0, 0, 1],
167-
]
168-
nhcwb16_to_nhwc = [
169-
[1, 0, 0, 0, 0, 0],
170-
[0, 1, 0, 0, 0, 0],
171-
[0, 0, 0, 1, 0, 0],
172-
[0, 0, 0, 0, 0, int(ofm_channels)],
173-
[0, 0, 0, 0, 0, 1],
174-
]
161+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ofm_channels))
162+
175163
ifm_matrix = [
176164
[1, 0, 0, 0, 0],
177165
[0, stride_h, 0, 0, (pool_shape_h - stride_h)],

python/tvm/relay/backend/contrib/ethosu/te/unary_elementwise.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from tvm import te
2222
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
2323
from .dma import dma_ofm_compute, dma_ifm_compute
24+
from .common import get_layout_transform_matrices
2425

2526

2627
def unary_elementwise_compute(
@@ -129,21 +130,8 @@ def clz_imp(inp):
129130
attrs=unary_elementwise_attrs,
130131
)
131132

132-
nhwc_to_nhcwb16 = [
133-
[1, 0, 0, 0, 0],
134-
[0, 1, 0, 0, 0],
135-
[0, 0, 0, 1 / 16, 0],
136-
[0, 0, 1, 0, 0],
137-
[0, 0, 0, 0, 16],
138-
[0, 0, 0, 0, 1],
139-
]
140-
nhcwb16_to_nhwc = [
141-
[1, 0, 0, 0, 0, 0],
142-
[0, 1, 0, 0, 0, 0],
143-
[0, 0, 0, 1, 0, 0],
144-
[0, 0, 16, 0, 1, -16],
145-
[0, 0, 0, 0, 0, 1],
146-
]
133+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ofm_channels))
134+
147135
ifm_matrix = [
148136
[1, 0, 0, 0, 0],
149137
[0, 1, 0, 0, 0],

src/contrib/ethosu/cascader/block_config.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ BlockConfig::BlockConfig(const std::vector<int>& input_shape, const std::vector<
4646
auto n = make_object<BlockConfigNode>();
4747
n->input_shape_ = std::move(input_shape);
4848
n->output_shape_ = std::move(output_shape);
49-
n->compute_cycles_ = std::move(compute_cycles);
50-
n->output_cycles_ = std::move(output_cycles);
49+
n->compute_cycles_ = compute_cycles;
50+
n->output_cycles_ = output_cycles;
5151
data_ = std::move(n);
5252
}
5353

tests/python/contrib/test_ethosu/cascader/infra.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def make_simple_home_map(graph, var_region, const_region):
5555

5656
if ethosu_enabled:
5757
from tvm.relay.backend.contrib.ethosu.tir.compiler import extract_constants, lower_to_te
58+
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices
5859

5960
def create_te_graph(func):
6061
func, consts = extract_constants(func)
@@ -79,21 +80,9 @@ def make_matrices(
7980
dilation_h, dilation_w = dilation
8081
dilated_kernel_h = (kernel_h - 1) * dilation_h + 1
8182
dilated_kernel_w = (kernel_w - 1) * dilation_w + 1
82-
nhwc_to_nhcwb16 = [
83-
[1, 0, 0, 0, 0],
84-
[0, 1, 0, 0, 0],
85-
[0, 0, 0, 1 / 16, 0],
86-
[0, 0, 1, 0, 0],
87-
[0, 0, 0, 0, 16],
88-
[0, 0, 0, 0, 1],
89-
]
90-
nhcwb16_to_nhwc = [
91-
[1, 0, 0, 0, 0, 0],
92-
[0, 1, 0, 0, 0, 0],
93-
[0, 0, 0, 1, 0, 0],
94-
[0, 0, 0, 0, 0, ofm_channels],
95-
[0, 0, 0, 0, 0, 1],
96-
]
83+
84+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)
85+
9786
if op_type == "ethosu_conv2d":
9887
ifm_matrix = [
9988
[1, 0, 0, 0, 0],

tests/python/contrib/test_ethosu/cascader/test_ethosu_binary_elementwise_matcher.py

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,12 @@
2727
match_ethosu_binary_elementwise,
2828
binary_elementwise_compute,
2929
)
30+
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices
3031

3132

32-
def _make_matrices(broadcast, ifm_layout, ifm2_layout, ofm_layout):
33+
def _make_matrices(broadcast, ifm_layout, ifm2_layout, ofm_layout, ofm_channels):
3334
broadcast_h, broadcast_w, broadcast_c = broadcast
34-
nhwc_to_nhcwb16 = [
35-
[1, 0, 0, 0, 0],
36-
[0, 1, 0, 0, 0],
37-
[0, 0, 0, 1 / 16, 0],
38-
[0, 0, 1, 0, 0],
39-
[0, 0, 0, 0, 16],
40-
[0, 0, 0, 0, 1],
41-
]
42-
nhcwb16_to_nhwc = [
43-
[1, 0, 0, 0, 0, 0],
44-
[0, 1, 0, 0, 0, 0],
45-
[0, 0, 0, 1, 0, 0],
46-
[0, 0, 16, 0, 1, -16],
47-
[0, 0, 0, 0, 0, 1],
48-
]
35+
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)
4936
ifm_matrix = [
5037
[1, 0, 0, 0, 0],
5138
[0, 1, 0, 0, 0],
@@ -93,14 +80,8 @@ def test_ethosu_binary_elementwise_matcher(
9380
ifm2_shape = [1] + [1 if (b == 1) else a for a, b in zip(ofm_shape[1:], ifm2_broadcast)]
9481
ifm_channels = ifm_shape[3]
9582
ifm2_channels = ifm2_shape[3]
96-
nhwc_to_nhcwb16 = [
97-
[1, 0, 0, 0, 0],
98-
[0, 1, 0, 0, 0],
99-
[0, 0, 0, 1 / 16, 0],
100-
[0, 0, 1, 0, 0],
101-
[0, 0, 0, 0, 16],
102-
[0, 0, 0, 0, 1],
103-
]
83+
ofm_channels = ofm_shape[3]
84+
nhwc_to_nhcwb16, _ = get_layout_transform_matrices(ofm_channels)
10485
broadcast = [1 if a == 1 else 0 for a in ifm2_shape[1:]]
10586
if ifm_layout == "NHCWB16":
10687
ifm_shape = [
@@ -173,10 +154,7 @@ def test_ethosu_binary_elementwise_matcher(
173154
output_stripe_config = cs.StripeConfig(ofm_shape, ofm_shape, ofm_shape, order, stripes, offset)
174155

175156
(ifm_transform, ifm2_transform) = _make_matrices(
176-
broadcast,
177-
ifm_layout,
178-
ifm2_layout,
179-
ofm_layout,
157+
broadcast, ifm_layout, ifm2_layout, ofm_layout, ofm_channels
180158
)
181159

182160
device_config = cs.EthosuDeviceConfig("ethos-u55-256")
@@ -190,19 +168,10 @@ def test_ethosu_binary_elementwise_matcher(
190168
propagated_ifm = ifm_propagator.propagate(output_stripe_config).shape
191169
propagated_ifm2 = ifm2_propagator.propagate(output_stripe_config).shape
192170

193-
# Layout conversions will align the propagated IFMs to the brick, i.e. 16
194-
# so the expected ifm(2)_shape needs to be rounded up to 16
195-
if ifm_layout != ofm_layout:
196-
assert ifm_shape[:-1] == propagated_ifm[:-1]
197-
assert ((ifm_shape[-1] + 16 - 1) // 16) * 16 == propagated_ifm[-1]
198-
else:
199-
assert ifm_shape == propagated_ifm
200-
201-
if ifm2_layout != ofm_layout:
202-
assert ifm2_shape[:-1] == propagated_ifm2[:-1]
203-
assert ((ifm2_shape[-1] + 16 - 1) // 16) * 16 == propagated_ifm2[-1]
204-
else:
205-
assert ifm2_shape == propagated_ifm2
171+
# The layout transforms that have the exact number of output channels in them
172+
# will lose no information about the number of channels
173+
assert ifm_shape == propagated_ifm
174+
assert ifm2_shape == propagated_ifm2
206175

207176

208177
if __name__ == "__main__":

tests/python/contrib/test_ethosu/cascader/test_ethosu_block_config.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import math
2323

2424
import tvm.contrib.ethosu.cascader as cs
25+
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices
2526

2627
from .infra import make_matrices
2728

@@ -244,18 +245,11 @@ def test_best_block_config(
244245
acc_config,
245246
expected_block_configs,
246247
):
247-
nhwc_to_nhcwb16 = [
248-
[1, 0, 0, 0, 0],
249-
[0, 1, 0, 0, 0],
250-
[0, 0, 0, 1 / 16, 0],
251-
[0, 0, 1, 0, 0],
252-
[0, 0, 0, 0, 16],
253-
[0, 0, 0, 0, 1],
254-
]
255-
256248
ofm_channels = out_shape[3]
257249
ifm_channels = in_shape[3]
258250

251+
nhwc_to_nhcwb16, _ = get_layout_transform_matrices(ofm_channels)
252+
259253
ifm_matrix, ifm_offset, weight_matrix, weight_offset, _, _ = make_matrices(
260254
op_type,
261255
kernel,

0 commit comments

Comments
 (0)