From 351bd8c303df27e77053f1d479a65d3f4b8e9412 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Tue, 28 Jan 2025 11:20:21 +0100 Subject: [PATCH] [WIP] add frontends for benchmarking cmsis_nn and cmsis_dsp kernels --- mlonmcu/models/__init__.py | 4 ++ mlonmcu/models/frontend.py | 86 +++++++++++++++++++++++++++++++++++++ mlonmcu/models/model.py | 88 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) diff --git a/mlonmcu/models/__init__.py b/mlonmcu/models/__init__.py index d469e2372..0a2996710 100644 --- a/mlonmcu/models/__init__.py +++ b/mlonmcu/models/__init__.py @@ -34,6 +34,8 @@ MibenchFrontend, LayerGenFrontend, OpenASIPFrontend, + CmsisDSPFrontend, + CmsisNNFrontend, ) SUPPORTED_FRONTENDS = { @@ -53,6 +55,8 @@ "mibench": MibenchFrontend, "layergen": LayerGenFrontend, "openasip": OpenASIPFrontend, + "cmsis_dsp": CmsisDSPFrontend, + "cmsis_nn": CmsisNNFrontend, } # TODO: use registry instead __all__ = [ diff --git a/mlonmcu/models/frontend.py b/mlonmcu/models/frontend.py index 76c4227a1..0ba1f1807 100644 --- a/mlonmcu/models/frontend.py +++ b/mlonmcu/models/frontend.py @@ -39,6 +39,8 @@ MathisProgram, MibenchProgram, OpenASIPProgram, + CmsisDSPProgram, + CmsisNNProgram, ) from mlonmcu.models.lookup import lookup_models from mlonmcu.feature.type import FeatureType @@ -2142,3 +2144,87 @@ def get_platform_config(self, platform): if platform == "mlif": ret["template"] = "openasip" return ret + + +class CmsisDSPFrontend(SimpleFrontend): + + def __init__(self, features=None, config=None): + super().__init__( + "cmsis_dsp", + ModelFormats.NONE, + features=features, + config=config, + ) + + @property + def supported_names(self): + return [ + "arm_abs_q15", + "arm_abs_q31", + ] + + def lookup_models(self, names, config=None, context=None): + ret = [] + for name in names: + name = name.replace("cmsis_dsp/", "") + if name in self.supported_names: + hint = CmsisDSPProgram( + name, + alt=f"cmsis_dsp/{name}", + config=config, + ) + ret.append(hint) + return ret + + def generate(self, model) -> Tuple[dict, dict]: + artifacts = [Artifact("dummy_model", raw=bytes(), fmt=ArtifactFormat.RAW, flags=["model", "dummy"])] + + return {"default": artifacts}, {} + + def get_platform_config(self, platform): + ret = {} + if platform == "mlif": + ret["template"] = "cmsis_dsp_bench" + return ret + + +class CmsisNNFrontend(SimpleFrontend): + + def __init__(self, features=None, config=None): + super().__init__( + "cmsis_nn", + ModelFormats.NONE, + features=features, + config=config, + ) + + @property + def supported_names(self): + return [ + "arm_nn_activation_s16_tanh", + "arm_nn_activation_s16_sigmoid", + ] + + def lookup_models(self, names, config=None, context=None): + ret = [] + for name in names: + name = name.replace("cmsis_nn/", "") + if name in self.supported_names: + hint = CmsisNNProgram( + name, + alt=f"cmsis_nn/{name}", + config=config, + ) + ret.append(hint) + return ret + + def generate(self, model) -> Tuple[dict, dict]: + artifacts = [Artifact("dummy_model", raw=bytes(), fmt=ArtifactFormat.RAW, flags=["model", "dummy"])] + + return {"default": artifacts}, {} + + def get_platform_config(self, platform): + ret = {} + if platform == "mlif": + ret["template"] = "cmsis_nn_bench" + return ret diff --git a/mlonmcu/models/model.py b/mlonmcu/models/model.py index d6afccc20..f5a332848 100644 --- a/mlonmcu/models/model.py +++ b/mlonmcu/models/model.py @@ -431,3 +431,91 @@ def get_platform_defs(self, platform): if self.name == "crc": ret["OPENASIP_CRC_MODE"] = self.crc_mode return ret + + +class CmsisDSPProgram(Program): + DEFAULTS = { + "size": 16, # hoch much data to operate on + "batch_size": 16, # num_batches=ceil(size/batch_size) + "number": 10, # how often to repeat (TODO: use existing bench feature) + } + + @property + def size(self): + value = self.config["size"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return value + + @property + def batch_size(self): + value = self.config["batch_size"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return min(value, self.size) # batch size should not exceed size + + @property + def number(self): + value = self.config["number"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return value + + def get_platform_defs(self, platform): + ret = {} + if platform == "mlif": + ret["CMSIS_DSP_BENCHMARK"] = self.name + ret["CMSIS_DSP_SIZE"] = self.size + ret["CMSIS_DSP_BATCH_SIZE"] = self.batch_size + ret["CMSIS_DSP_NUMBER"] = self.number + return ret + + +class CmsisNNProgram(Program): + DEFAULTS = { + "size": 16, # hoch much data to operate on + "batch_size": 16, # num_batches=ceil(size/batch_size) + "number": 10, # how often to repeat (TODO: use existing bench feature) + } + + @property + def size(self): + value = self.config["size"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return value + + @property + def batch_size(self): + value = self.config["batch_size"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return min(value, self.size) # batch size should not exceed size + + @property + def number(self): + value = self.config["number"] + if isinstance(value, str): + value = int(value) + assert isinstance(value, int) + assert value > 0 + return value + + def get_platform_defs(self, platform): + ret = {} + if platform == "mlif": + ret["CMSIS_NN_BENCHMARK"] = self.name + ret["CMSIS_NN_SIZE"] = self.size + ret["CMSIS_NN_BATCH_SIZE"] = self.batch_size + ret["CMSIS_NN_NUMBER"] = self.number + return ret