Skip to content

Commit

Permalink
Reduce the duplication of layout transfrom matrices
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ekalda committed Mar 28, 2022
1 parent aab1d7c commit b0d1ae6
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 174 deletions.
18 changes: 3 additions & 15 deletions python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher

from .dma import dma_ofm_compute, dma_ifm_compute
from .common import get_layout_transform_matrices


def binary_elementwise_compute(
Expand Down Expand Up @@ -196,21 +197,8 @@ def binary_elementwise_compute(
attrs=binary_elementwise_attrs,
)

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 16, 0, 1, -16],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ifm_channels))

ifm_matrix = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
Expand Down
53 changes: 53 additions & 0 deletions python/tvm/relay/backend/contrib/ethosu/te/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Common methods for the NPU tensor expressions"""

from typing import Tuple, List


def get_layout_transform_matrices(ofm_channels: int) -> Tuple[List[List[float]], List[List[float]]]:
"""Get the NHWC->NHCWB16 and NHCWB16->NHWC layout transform matrices.
Parameters
----------
ofm_channels : int
The number of output channels in a NHWC layout
Returns
-------
nhwc_to_nhcwb16, nhcwb16_to_nhwc : Tuple[List[List[float]], List[List[float]]]
The layout transformation matrices
"""

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]

nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, ofm_channels],
[0, 0, 0, 0, 0, 1],
]

return nhwc_to_nhcwb16, nhcwb16_to_nhwc
18 changes: 3 additions & 15 deletions python/tvm/relay/backend/contrib/ethosu/te/convolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher

from .dma import dma_ofm_compute, dma_ifm_compute
from .common import get_layout_transform_matrices


def conv2d_compute(
Expand Down Expand Up @@ -175,21 +176,8 @@ def conv2d_compute(
attrs=conv2d_attrs,
)

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, ofm_channels],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)

ifm_matrix = [
[1, 0, 0, 0, 0],
[0, stride_h, 0, 0, (dilated_kernel_h - stride_h)],
Expand Down
18 changes: 3 additions & 15 deletions python/tvm/relay/backend/contrib/ethosu/te/depthwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher

from .dma import dma_ofm_compute, dma_ifm_compute
from .common import get_layout_transform_matrices


def depthwise_conv2d_compute(
Expand Down Expand Up @@ -169,21 +170,8 @@ def depthwise_conv2d_compute(
attrs=depthwise_conv2d_attrs,
)

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, channels],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(channels)

ifm_matrix = [
[1, 0, 0, 0, 0],
[0, stride_h, 0, 0, (dilated_kernel_h - stride_h)],
Expand Down
18 changes: 3 additions & 15 deletions python/tvm/relay/backend/contrib/ethosu/te/pooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher

from .dma import dma_ofm_compute, dma_ifm_compute
from .common import get_layout_transform_matrices


def pooling_compute(
Expand Down Expand Up @@ -157,21 +158,8 @@ def pooling_compute(
attrs=pooling_attrs,
)

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, int(ofm_channels)],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ofm_channels))

ifm_matrix = [
[1, 0, 0, 0, 0],
[0, stride_h, 0, 0, (pool_shape_h - stride_h)],
Expand Down
18 changes: 3 additions & 15 deletions python/tvm/relay/backend/contrib/ethosu/te/unary_elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from tvm import te
from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, register_matcher
from .dma import dma_ofm_compute, dma_ifm_compute
from .common import get_layout_transform_matrices


def unary_elementwise_compute(
Expand Down Expand Up @@ -129,21 +130,8 @@ def clz_imp(inp):
attrs=unary_elementwise_attrs,
)

nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 16, 0, 1, -16],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(int(ofm_channels))

ifm_matrix = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
Expand Down
4 changes: 2 additions & 2 deletions src/contrib/ethosu/cascader/block_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ BlockConfig::BlockConfig(const std::vector<int>& input_shape, const std::vector<
auto n = make_object<BlockConfigNode>();
n->input_shape_ = std::move(input_shape);
n->output_shape_ = std::move(output_shape);
n->compute_cycles_ = std::move(compute_cycles);
n->output_cycles_ = std::move(output_cycles);
n->compute_cycles_ = compute_cycles;
n->output_cycles_ = output_cycles;
data_ = std::move(n);
}

Expand Down
19 changes: 4 additions & 15 deletions tests/python/contrib/test_ethosu/cascader/infra.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def make_simple_home_map(graph, var_region, const_region):

if ethosu_enabled:
from tvm.relay.backend.contrib.ethosu.tir.compiler import extract_constants, lower_to_te
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices

def create_te_graph(func):
func, consts = extract_constants(func)
Expand All @@ -79,21 +80,9 @@ def make_matrices(
dilation_h, dilation_w = dilation
dilated_kernel_h = (kernel_h - 1) * dilation_h + 1
dilated_kernel_w = (kernel_w - 1) * dilation_w + 1
nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, ofm_channels],
[0, 0, 0, 0, 0, 1],
]

nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)

if op_type == "ethosu_conv2d":
ifm_matrix = [
[1, 0, 0, 0, 0],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,12 @@
match_ethosu_binary_elementwise,
binary_elementwise_compute,
)
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices


def _make_matrices(broadcast, ifm_layout, ifm2_layout, ofm_layout):
def _make_matrices(broadcast, ifm_layout, ifm2_layout, ofm_layout, ofm_channels):
broadcast_h, broadcast_w, broadcast_c = broadcast
nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
nhcwb16_to_nhwc = [
[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 16, 0, 1, -16],
[0, 0, 0, 0, 0, 1],
]
nhwc_to_nhcwb16, nhcwb16_to_nhwc = get_layout_transform_matrices(ofm_channels)
ifm_matrix = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
Expand Down Expand Up @@ -93,14 +80,8 @@ def test_ethosu_binary_elementwise_matcher(
ifm2_shape = [1] + [1 if (b == 1) else a for a, b in zip(ofm_shape[1:], ifm2_broadcast)]
ifm_channels = ifm_shape[3]
ifm2_channels = ifm2_shape[3]
nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]
ofm_channels = ofm_shape[3]
nhwc_to_nhcwb16, _ = get_layout_transform_matrices(ofm_channels)
broadcast = [1 if a == 1 else 0 for a in ifm2_shape[1:]]
if ifm_layout == "NHCWB16":
ifm_shape = [
Expand Down Expand Up @@ -173,10 +154,7 @@ def test_ethosu_binary_elementwise_matcher(
output_stripe_config = cs.StripeConfig(ofm_shape, ofm_shape, ofm_shape, order, stripes, offset)

(ifm_transform, ifm2_transform) = _make_matrices(
broadcast,
ifm_layout,
ifm2_layout,
ofm_layout,
broadcast, ifm_layout, ifm2_layout, ofm_layout, ofm_channels
)

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

# Layout conversions will align the propagated IFMs to the brick, i.e. 16
# so the expected ifm(2)_shape needs to be rounded up to 16
if ifm_layout != ofm_layout:
assert ifm_shape[:-1] == propagated_ifm[:-1]
assert ((ifm_shape[-1] + 16 - 1) // 16) * 16 == propagated_ifm[-1]
else:
assert ifm_shape == propagated_ifm

if ifm2_layout != ofm_layout:
assert ifm2_shape[:-1] == propagated_ifm2[:-1]
assert ((ifm2_shape[-1] + 16 - 1) // 16) * 16 == propagated_ifm2[-1]
else:
assert ifm2_shape == propagated_ifm2
# The layout transforms that have the exact number of output channels in them
# will lose no information about the number of channels
assert ifm_shape == propagated_ifm
assert ifm2_shape == propagated_ifm2


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import math

import tvm.contrib.ethosu.cascader as cs
from tvm.relay.backend.contrib.ethosu.te.common import get_layout_transform_matrices

from .infra import make_matrices

Expand Down Expand Up @@ -244,18 +245,11 @@ def test_best_block_config(
acc_config,
expected_block_configs,
):
nhwc_to_nhcwb16 = [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1 / 16, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 16],
[0, 0, 0, 0, 1],
]

ofm_channels = out_shape[3]
ifm_channels = in_shape[3]

nhwc_to_nhcwb16, _ = get_layout_transform_matrices(ofm_channels)

ifm_matrix, ifm_offset, weight_matrix, weight_offset, _, _ = make_matrices(
op_type,
kernel,
Expand Down
Loading

0 comments on commit b0d1ae6

Please sign in to comment.