Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions python/tvm/driver/tvmc/composite_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
Provides support to composite target on TVMC.
"""
import logging
import warnings

# Make sure Vitis AI codegen is registered
import tvm.contrib.target.vitis_ai # pylint: disable=unused-import
Expand Down Expand Up @@ -72,11 +71,6 @@
"config_key": "relay.ext.vitis_ai.options",
"pass_pipeline": partition_for_vitis_ai,
},
# Deprecated in favour of "ethos-n".
"ethos-n78": {
"config_key": "relay.ext.ethos-n.options",
"pass_pipeline": partition_for_ethosn,
},
}


Expand Down Expand Up @@ -105,12 +99,6 @@ def get_codegen_by_target(name):
requested target codegen information
"""
try:
if name == "ethos-n78":
warnings.warn(
"Please use 'ethos-n' instead of the deprecated 'ethos-n78' target, "
"which will be removed in a later release of TVM.",
DeprecationWarning,
)
return REGISTERED_CODEGEN[name]
except KeyError:
raise TVMCException("Composite target %s is not defined in TVMC." % name)
17 changes: 2 additions & 15 deletions python/tvm/relay/op/contrib/ethosn.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
# pylint: disable=invalid-name, unused-argument
"""Arm(R) Ethos(TM)-N NPU supported operators."""
from enum import Enum
import warnings
from distutils.version import LooseVersion

import tvm.ir
Expand Down Expand Up @@ -97,6 +96,8 @@ def is_inline_non_compute_intensive_partitions_enabled() -> bool:
True if inlining should happen, False if not.
"""
compiler_attrs = tvm.get_global_func("relay.ext.ethos-n.get_compiler_attrs")()
if not compiler_attrs:
return False
return compiler_attrs.inline_non_compute_intensive_partitions


Expand All @@ -115,20 +116,6 @@ def partition_for_ethosn(mod, params=None, **opts):
-------
ret : annotated and partitioned module.
"""
opts = opts or {}
if "variant" not in opts:
raise ValueError("Please specify a variant in the target string, e.g. -variant=n78.")

# -variant=ethos-n78 deprecated in favour of -variant=n78
if opts["variant"].lower() == "ethos-n78":
warnings.warn(
"Please use '-variant=n78' instead of the deprecated "
"'-variant=ethos-n78', which will be removed in TVM v0.9.",
DeprecationWarning,
)
elif opts["variant"] != "n78":
raise ValueError("When targeting Ethos(TM)-N78, -variant=n78 should be set.")

api_version = ethosn_api_version()
supported_api_versions = ["3.1.0"]
if all(api_version != LooseVersion(exp_ver) for exp_ver in supported_api_versions):
Expand Down
85 changes: 35 additions & 50 deletions src/relay/backend/contrib/ethosn/codegen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,36 +226,27 @@ sl::TensorsAndId MakeOps(const sl::TensorAndId<sl::Operand>& op) {
return ops;
}

String MakeVariant(Optional<EthosnCompilerConfig> configuration) {
String variant = configuration.value()->variant;
// Transform variant string to lowercase for comparison
std::string variant_string = variant.c_str();

// Checking deprecated variant format. Support for specifying
// the variant in this way only remains for backwards compatibility
// and will be removed in a later release of TVM.
std::string deprecated_variant_string = variant_string;
std::transform(deprecated_variant_string.begin(), deprecated_variant_string.end(),
deprecated_variant_string.begin(), ::tolower);
if (variant_string == "n78" || deprecated_variant_string == "ethos-n78") {
String tops = configuration.value()->tops;
String ple_ratio = configuration.value()->ple_ratio;
variant = "Ethos-N78_" + tops + "TOPS_" + ple_ratio + "PLE_RATIO";
}
return variant;
sl::EthosNVariant MakeVariant(EthosnCompilerConfig configuration) {
String variant = configuration->variant;
String tops = configuration->tops;
String ple_ratio = configuration->ple_ratio;

std::string capitalized_variant = variant;
std::transform(capitalized_variant.begin(), capitalized_variant.end(),
capitalized_variant.begin(), ::toupper);
std::string sl_variant_string =
"Ethos-" + capitalized_variant + "_" + tops + "TOPS_" + ple_ratio + "PLE_RATIO";
return sl::EthosNVariantFromString(sl_variant_string.c_str());
}

NetworkWithIDs ConstructNetworkVisitor::Construct(const Function& func) {
// Initialise everything
auto ctx = transform::PassContext::Current();
auto cfg = ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options");
if (!cfg.defined()) {
cfg = AttrsWithDefaultValues<EthosnCompilerConfig>();
}
EthosnCompilerConfig cfg = GetCompilerAttrs();
sl::EthosNVariant variant = MakeVariant(cfg);

NetworkWithIDs network_with_ids;
network_ = sl::CreateNetwork(
sl::GetFwAndHwCapabilities(sl::EthosNVariantFromString(MakeVariant(cfg).c_str()),
static_cast<uint32_t>(std::stoul(cfg.value()->sram_size))));
sl::GetFwAndHwCapabilities(variant, static_cast<uint32_t>(std::stoul(cfg->sram_size))));
network_with_ids.network = network_;
operand_table_.clear();

Expand Down Expand Up @@ -744,28 +735,24 @@ runtime::ethosn::OrderedCompiledNetwork EthosnCompiler::CompileEthosnFunc(const
}

sl::CompilationOptions EthosnCompiler::CreateOptions() {
auto ctx = transform::PassContext::Current();
auto cfg = ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options");
if (!cfg.defined()) {
cfg = AttrsWithDefaultValues<EthosnCompilerConfig>();
}
EthosnCompilerConfig cfg = GetCompilerAttrs();

sl::CompilationOptions options;
options.m_Strategy0 = cfg.value()->strategy0;
options.m_Strategy1 = cfg.value()->strategy1;
options.m_Strategy3 = cfg.value()->strategy3;
options.m_Strategy4 = cfg.value()->strategy4;
options.m_Strategy6 = cfg.value()->strategy6;
options.m_Strategy7 = cfg.value()->strategy7;
options.m_DebugInfo.m_DumpRam = cfg.value()->dump_ram;
options.m_DebugInfo.m_InitialSramDump = cfg.value()->initial_sram_dump;
options.m_BlockConfig16x16 = cfg.value()->block_config_16x16;
options.m_BlockConfig32x8 = cfg.value()->block_config_32x8;
options.m_BlockConfig8x32 = cfg.value()->block_config_8x32;
options.m_BlockConfig8x8 = cfg.value()->block_config_8x8;
options.m_EnableIntermediateCompression = cfg.value()->enable_intermediate_compression;
options.m_DisableWinograd = cfg.value()->disable_winograd;
options.m_DebugInfo.m_DebugDir = cfg.value()->debug_dir;
options.m_Strategy0 = cfg->strategy0;
options.m_Strategy1 = cfg->strategy1;
options.m_Strategy3 = cfg->strategy3;
options.m_Strategy4 = cfg->strategy4;
options.m_Strategy6 = cfg->strategy6;
options.m_Strategy7 = cfg->strategy7;
options.m_DebugInfo.m_DumpRam = cfg->dump_ram;
options.m_DebugInfo.m_InitialSramDump = cfg->initial_sram_dump;
options.m_BlockConfig16x16 = cfg->block_config_16x16;
options.m_BlockConfig32x8 = cfg->block_config_32x8;
options.m_BlockConfig8x32 = cfg->block_config_8x32;
options.m_BlockConfig8x8 = cfg->block_config_8x8;
options.m_EnableIntermediateCompression = cfg->enable_intermediate_compression;
options.m_DisableWinograd = cfg->disable_winograd;
options.m_DebugInfo.m_DebugDir = cfg->debug_dir;
return options;
}

Expand Down Expand Up @@ -806,12 +793,10 @@ std::unique_ptr<sl::SupportQueries> EthosnCompiler::m_Queries;

EthosnError EthosnCompiler::SupportedSetup() {
if (m_Queries == nullptr) {
auto ctx = transform::PassContext::Current();
auto cfg = ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options").defined()
? ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options")
: AttrsWithDefaultValues<EthosnCompilerConfig>();
m_Queries = std::make_unique<sl::SupportQueries>(sl::GetFwAndHwCapabilities(
sl::EthosNVariantFromString(MakeVariant(cfg).c_str()), std::stoul(cfg.value()->sram_size)));
EthosnCompilerConfig cfg = GetCompilerAttrs();
sl::EthosNVariant variant = MakeVariant(cfg);
m_Queries = std::make_unique<sl::SupportQueries>(
sl::GetFwAndHwCapabilities(variant, std::stoul(cfg->sram_size)));
if (m_Queries == nullptr) {
return EthosnError("Could not initialise Arm(R) Ethos(TM)-N compiler isSupported");
}
Expand Down
9 changes: 5 additions & 4 deletions src/relay/backend/contrib/ethosn/codegen_ethosn.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,14 @@ class EthosnCompilerConfig : public Attrs {
TVM_REGISTER_NODE_TYPE(EthosnCompilerConfigNode);
TVM_REGISTER_PASS_CONFIG_OPTION("relay.ext.ethos-n.options", EthosnCompilerConfig);

auto GetCompilerAttrs() {
EthosnCompilerConfig GetCompilerAttrs() {
auto ctx = transform::PassContext::Current();
auto cfg = ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options");
Optional<EthosnCompilerConfig> cfg =
ctx->GetConfig<EthosnCompilerConfig>("relay.ext.ethos-n.options");
if (!cfg.defined()) {
cfg = AttrsWithDefaultValues<EthosnCompilerConfig>();
return AttrsWithDefaultValues<EthosnCompilerConfig>();
}
return cfg;
return cfg.value();
}
TVM_REGISTER_GLOBAL("relay.ext.ethos-n.get_compiler_attrs").set_body_typed(GetCompilerAttrs);

Expand Down
39 changes: 21 additions & 18 deletions tests/python/contrib/test_ethosn/infrastructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from tvm import relay
from tvm.contrib import utils, graph_executor, download
from tvm.relay.op.contrib import partition_for_ethosn
from tvm.driver.tvmc.target import parse_target

from . import _infrastructure

Expand Down Expand Up @@ -143,7 +144,9 @@ def visit_call(self, call):
return c.count


def build(mod, params, npu=True, expected_host_ops=0, npu_partitions=1, optimize_partitions=True):
def build(
mod, params, npu=True, expected_host_ops=0, npu_partitions=1, additional_config_args=None
):
"""Build a network with or without Ethos-N offloading.

Parameters
Expand All @@ -158,22 +161,18 @@ def build(mod, params, npu=True, expected_host_ops=0, npu_partitions=1, optimize
The number of ops expected to remain on the host.
npu_partitions : int, optional
The number of Ethos-N partitions expected.
optimize_partitions : bool, optional
Disable the pass that optimizes NPU partitions post partitioning.
additional_config_args : dict, optional
Additional compiler config options for the NPU.
"""
relay.backend.te_compiler.get().clear()
with tvm.transform.PassContext(
opt_level=3,
config={
"relay.ext.ethos-n.options": {
"variant": get_ethosn_variant(),
"inline_non_compute_intensive_partitions": optimize_partitions,
}
},
):
if not additional_config_args:
additional_config_args = {}
npu_config = {**get_ethosn_device_options(), **additional_config_args}
print(npu_config)
with tvm.transform.PassContext(opt_level=3, config={"relay.ext.ethos-n.options": npu_config}):
with tvm.target.Target("llvm"):
if npu:
mod = partition_for_ethosn(mod, params, variant="n78")
mod = partition_for_ethosn(mod, params)
host_op_count = get_host_op_count(mod)
assert (
host_op_count == expected_host_ops
Expand Down Expand Up @@ -244,12 +243,12 @@ def build_and_run(
npu=True,
expected_host_ops=0,
npu_partitions=1,
optimize_partitions=True,
additional_config_args=None,
):
"""
Convenient wrapper for building and running a module on the NPU.
"""
lib = build(mod, params, npu, expected_host_ops, npu_partitions, optimize_partitions)
lib = build(mod, params, npu, expected_host_ops, npu_partitions, additional_config_args)
return run(lib, inputs, outputs, npu)


Expand Down Expand Up @@ -285,7 +284,7 @@ def test_error(mod, params, err_msg):

caught = None
with tvm.transform.PassContext(
opt_level=3, config={"relay.ext.ethos-n.options": {"variant": get_ethosn_variant()}}
opt_level=3, config={"relay.ext.ethos-n.options": get_ethosn_device_options()}
):
with tvm.target.Target("llvm"):
try:
Expand Down Expand Up @@ -403,5 +402,9 @@ def get_same_padding(
return (pad_top, pad_left, pad_bottom, pad_right)


def get_ethosn_variant():
return os.getenv("ETHOSN_VARIANT_CONFIG", default="Ethos-N78_1TOPS_2PLE_RATIO")
def get_ethosn_device_options():
"""Determine the NPU configuration used for testing."""
default_target_string = "ethos-n -variant=n78 -tops=1 -ple_ratio=2"
target_string = os.getenv("ETHOSN_TEST_TARGET_CONFIG", default_target_string)
target = parse_target(target_string)
return target[0]["opts"]
22 changes: 20 additions & 2 deletions tests/python/contrib/test_ethosn/test_addition.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,16 @@ def test_addition(dtype, shape):
model = _get_model(shape, shape, lhs_zp, lhs_sc, rhs_zp, rhs_sc, out_zp, out_sc, dtype)
for npu in [False, True]:
mod = tei.make_module(model, [])
outputs.append(tei.build_and_run(mod, inputs, 1, {}, npu=npu, optimize_partitions=False))
outputs.append(
tei.build_and_run(
mod,
inputs,
1,
{},
npu=npu,
additional_config_args={"inline_non_compute_intensive_partitions": False},
)
)

tei.verify(outputs, dtype, 1)

Expand Down Expand Up @@ -227,7 +236,16 @@ def test_addition_to_reinterpret_quantize(lhs_shape, lhs_is_constant, rhs_shape,
outputs = []
for npu in [False, True]:
mod = tei.make_module(model, {})
outputs.append(tei.build_and_run(mod, inputs, 1, {}, npu=npu, optimize_partitions=False))
outputs.append(
tei.build_and_run(
mod,
inputs,
1,
{},
npu=npu,
additional_config_args={"inline_non_compute_intensive_partitions": False},
)
)
tei.verify(outputs, dtype, 1)


Expand Down
52 changes: 52 additions & 0 deletions tests/python/contrib/test_ethosn/test_codegen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 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.

"""NPU codegen tests"""

import pytest
import numpy as np

import tvm
from tvm import relay
from tvm.testing import requires_ethosn

from . import infrastructure as tei


@requires_ethosn
def test_compile_with_unsupported_variant():
"""Test compilation with unsupported variant."""
dtype = "int8"
input_shape = (1, 2, 2, 2)

x = relay.var("x", shape=input_shape, dtype=dtype)
y = relay.reshape(x, newshape=(1, 1, 1, 8))
mod = tei.make_ethosn_partition(y)

additional_config_args = {
"variant": "foo",
"inline_non_compute_intensive_partitions": False,
}

inputs = {
"x": np.random.randint(
low=np.iinfo(dtype).min, high=np.iinfo(dtype).max, size=input_shape, dtype=dtype
)
}

with pytest.raises(tvm.TVMError, match=r"Unknown NPU type"):
tei.build_and_run(mod, inputs, 1, {}, True, additional_config_args=additional_config_args)
11 changes: 10 additions & 1 deletion tests/python/contrib/test_ethosn/test_concatenate.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,16 @@ def test_concatenate(dtype, shapes, axis):
for npu in [False, True]:
model = _get_model(shapes, dtype, axis)
mod = tei.make_module(model, {})
outputs.append(tei.build_and_run(mod, inputs, 1, {}, npu=npu, optimize_partitions=False))
outputs.append(
tei.build_and_run(
mod,
inputs,
1,
{},
npu=npu,
additional_config_args={"inline_non_compute_intensive_partitions": False},
)
)

tei.verify(outputs, dtype, 0)

Expand Down
Loading