From 7ed89341e43459ecdab61c758f22c95ca6670d8d Mon Sep 17 00:00:00 2001 From: Ahmet Date: Tue, 3 Mar 2026 18:39:36 +0100 Subject: [PATCH] Add Adam support for Generic and Siracusa platforms --- Deeploy/Targets/GAP9/Bindings.py | 31 ++++-- Deeploy/Targets/GAP9/Platform.py | 47 ++++----- Deeploy/Targets/GAP9/Tiler.py | 20 ++-- Deeploy/Targets/Generic/Bindings.py | 33 ++++--- Deeploy/Targets/Generic/Layers.py | 16 +++ Deeploy/Targets/Generic/Parsers.py | 45 +++++++++ Deeploy/Targets/Generic/Platform.py | 36 +++---- .../Generic/Templates/FloatAdamTemplate.py | 34 +++++++ Deeploy/Targets/Generic/TypeCheckers.py | 15 +++ Deeploy/Targets/PULPOpen/Bindings.py | 31 ++++-- Deeploy/Targets/PULPOpen/Platform.py | 36 +++---- .../PULPOpen/Templates/FloatAdamTemplate.py | 70 +++++++++++++ .../TileConstraints/AdamTileConstraint.py | 93 ++++++++++++++++++ Deeploy/Targets/PULPOpen/Tiler.py | 22 +++-- .../Kernels/FP32/Adam/Regular/inputs.npz | Bin 0 -> 132522 bytes .../Kernels/FP32/Adam/Regular/network.onnx | Bin 0 -> 392 bytes .../Kernels/FP32/Adam/Regular/outputs.npz | Bin 0 -> 33036 bytes DeeployTest/test_gap9_config.py | 2 +- DeeployTest/test_generic_config.py | 1 + DeeployTest/test_platforms.py | 80 ++++++++++++++- DeeployTest/test_siracusa_config.py | 1 + DeeployTest/test_siracusa_tiled_config.py | 10 ++ 22 files changed, 517 insertions(+), 106 deletions(-) create mode 100644 Deeploy/Targets/Generic/Templates/FloatAdamTemplate.py create mode 100644 Deeploy/Targets/PULPOpen/Templates/FloatAdamTemplate.py create mode 100644 Deeploy/Targets/PULPOpen/TileConstraints/AdamTileConstraint.py create mode 100644 DeeployTest/Tests/Kernels/FP32/Adam/Regular/inputs.npz create mode 100644 DeeployTest/Tests/Kernels/FP32/Adam/Regular/network.onnx create mode 100644 DeeployTest/Tests/Kernels/FP32/Adam/Regular/outputs.npz diff --git a/Deeploy/Targets/GAP9/Bindings.py b/Deeploy/Targets/GAP9/Bindings.py index 2bda98af8f..408331fbe9 100644 --- a/Deeploy/Targets/GAP9/Bindings.py +++ b/Deeploy/Targets/GAP9/Bindings.py @@ -23,10 +23,10 @@ # Import templates from PULPOpen and Generic from Deeploy.Targets.Generic.Templates import AddTemplate, ConcatTemplate, DequantTemplate, FloatReduceMeanTemplate, \ FloatReduceSumTemplate, GatherTemplate, QuantTemplate, RQSiGELUTemplate, SliceTemplate, iHardswishTemplate -from Deeploy.Targets.Generic.TypeCheckers import AddChecker, ConcatChecker, ConvChecker, DequantChecker, \ - GatherChecker, GELUChecker, GEMMChecker, HardswishChecker, LayerNormChecker, MatMulChecker, MulChecker, \ - QuantChecker, ReduceMeanChecker, ReluChecker, ReshapeChecker, RQAddChecker, RQHardswishChecker, SGDChecker, \ - SliceChecker, SoftmaxChecker, SoftmaxCrossEntropyLossChecker, TransposeChecker +from Deeploy.Targets.Generic.TypeCheckers import AddChecker, AdamChecker, ConcatChecker, ConvChecker, \ + DequantChecker, GatherChecker, GELUChecker, GEMMChecker, HardswishChecker, LayerNormChecker, MatMulChecker, \ + MulChecker, QuantChecker, ReduceMeanChecker, ReluChecker, ReshapeChecker, RQAddChecker, RQHardswishChecker, \ + SGDChecker, SliceChecker, SoftmaxChecker, SoftmaxCrossEntropyLossChecker, TransposeChecker from Deeploy.Targets.PULPOpen.Bindings import ForkClosure, L3MemoryAwareFunctionCallClosure, \ MemoryAwareForkTransformer, MemoryAwareFunctionCallClosure, TilingCallClosure from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPClusterSynch import PULPSynchCoresPass @@ -34,12 +34,12 @@ from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPL3Tiling import PULPL3Tiling from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPProfileUntiled import PULPProfileUntiled from Deeploy.Targets.PULPOpen.DataTypes import PULPDMAFuture -from Deeploy.Targets.PULPOpen.Templates import ConvTemplate, DMASliceTemplate, FloatAddTemplate, FloatConvTemplate, \ - FloatGELUTemplate, FloatGemmTemplate, FloatLayernormTemplate, FloatMatMulTemplate, FloatMaxPoolTemplate, \ - FloatMulTemplate, FloatReluTemplate, FloatSoftmaxTemplate, GEMMTemplate, MatrixVectorTemplate, MaxPoolTemplate, \ - MulTemplate, ReduceMeanTemplate, RequantShiftTemplate, ReshapeTemplate, RQAddTemplate, RQSiHardswishTemplate, \ - SGDTemplate, SoftmaxCrossEntropyLossTemplate, TallGEMMTemplate, TransposeTemplate, UniformRequantShiftTemplate, \ - iRMSNormTemplate, iSoftmaxTemplate +from Deeploy.Targets.PULPOpen.Templates import ConvTemplate, DMASliceTemplate, FloatAddTemplate, FloatAdamTemplate, \ + FloatConvTemplate, FloatGELUTemplate, FloatGemmTemplate, FloatLayernormTemplate, FloatMatMulTemplate, \ + FloatMaxPoolTemplate, FloatMulTemplate, FloatReluTemplate, FloatSoftmaxTemplate, GEMMTemplate, \ + MatrixVectorTemplate, MaxPoolTemplate, MulTemplate, ReduceMeanTemplate, RequantShiftTemplate, ReshapeTemplate, \ + RQAddTemplate, RQSiHardswishTemplate, SGDTemplate, SoftmaxCrossEntropyLossTemplate, TallGEMMTemplate, \ + TransposeTemplate, UniformRequantShiftTemplate, iRMSNormTemplate, iSoftmaxTemplate from Deeploy.Targets.PULPOpen.TypeCheckers import PULPConvChecker, PULPLinearChecker, PULPMaxPoolChecker, \ PULPRequantShiftChecker from Deeploy.TilingExtension.CodeTransformationPasses.TilingVariableReplacement import TilingVariableReplacement, \ @@ -317,6 +317,17 @@ SGDTemplate.referenceTemplate, GAP9Transformer) ] +GAP9AdamBindings = [ + NodeBinding( + AdamChecker( + [PointerClass(float32_t), PointerClass(int32_t), + PointerClass(float32_t), PointerClass(float32_t), + PointerClass(float32_t), PointerClass(float32_t)], # R, T, X, G, V, H + [PointerClass(float32_t)] # X_new + ), + FloatAdamTemplate.referenceTemplate, GAP9Transformer) +] + GAP9TransposeBindings = [ NodeBinding(TransposeChecker([PointerClass(type)], [PointerClass(type)]), TransposeTemplate.referenceTemplate, GAP9Transformer) for type in IntegerDataTypes diff --git a/Deeploy/Targets/GAP9/Platform.py b/Deeploy/Targets/GAP9/Platform.py index bad6f8d859..74cabbfd7f 100644 --- a/Deeploy/Targets/GAP9/Platform.py +++ b/Deeploy/Targets/GAP9/Platform.py @@ -11,29 +11,29 @@ from Deeploy.MemoryLevelExtension.NetworkDeployers.MemoryLevelDeployer import MemoryPlatform, MemoryPlatformWrapper from Deeploy.Targets.GAP9.Templates import AllocateTemplate, FreeTemplate # Import GAP9-specific tiler bindings -from Deeploy.Targets.GAP9.Tiler import GAP9AddTilingReadyBindings, GAP9ConcatTilingReadyBindings, \ - GAP9Conv2DTilingReadyBindings, GAP9DWConv2DTilingReadyBindings, GAP9FlattenTilingReadyBindings, \ - GAP9FPGELUTilingReadyBindings, GAP9FPGEMMTilingReadyBindings, GAP9GatherTilingReadyBindings, \ - GAP9iHardswishTilingReadyBindings, GAP9iRMSNormTilingReadyBindings, GAP9iRQSGELUTilingReadyBindings, \ - GAP9LayernormTilingReadyBindings, GAP9MatMulTilingReadyBindings, GAP9MaxPool2DTilingReadyBindings, \ - GAP9MulTilingReadyBindings, GAP9ReduceSumTilingReadyBindings, GAP9ReluTilingReadyBindings, \ - GAP9RQAddTilingReadyBindings, GAP9RQSConv2DTilingReadyBindings, GAP9RQSDWConv2DTilingReadyBindings, \ - GAP9RQSGEMMTilingReadyBindings, GAP9RQSiHardswishTilingReadyBindings, GAP9RQSMatrixVecTilingReadyBindings, \ - GAP9RQSTallGEMMTilingReadyBindings, GAP9RQSTilingReadyBindings, GAP9SGDTilingReadyBindings, \ - GAP9SoftmaxCrossEntropyGradTilingReadyBindings, GAP9SoftmaxCrossEntropyTilingReadyBindings, \ - GAP9SoftmaxGradTilingReadyBindings, GAP9SoftmaxTilingReadyBindings, GAP9TransposeTilingReadyBindings, \ - GAP9UniformRQSTilingReadyBindings +from Deeploy.Targets.GAP9.Tiler import GAP9AdamTilingReadyBindings, GAP9AddTilingReadyBindings, \ + GAP9ConcatTilingReadyBindings, GAP9Conv2DTilingReadyBindings, GAP9DWConv2DTilingReadyBindings, \ + GAP9FlattenTilingReadyBindings, GAP9FPGELUTilingReadyBindings, GAP9FPGEMMTilingReadyBindings, \ + GAP9GatherTilingReadyBindings, GAP9iHardswishTilingReadyBindings, GAP9iRMSNormTilingReadyBindings, \ + GAP9iRQSGELUTilingReadyBindings, GAP9LayernormTilingReadyBindings, GAP9MatMulTilingReadyBindings, \ + GAP9MaxPool2DTilingReadyBindings, GAP9MulTilingReadyBindings, GAP9ReduceSumTilingReadyBindings, \ + GAP9ReluTilingReadyBindings, GAP9RQAddTilingReadyBindings, GAP9RQSConv2DTilingReadyBindings, \ + GAP9RQSDWConv2DTilingReadyBindings, GAP9RQSGEMMTilingReadyBindings, GAP9RQSiHardswishTilingReadyBindings, \ + GAP9RQSMatrixVecTilingReadyBindings, GAP9RQSTallGEMMTilingReadyBindings, GAP9RQSTilingReadyBindings, \ + GAP9SGDTilingReadyBindings, GAP9SoftmaxCrossEntropyGradTilingReadyBindings, \ + GAP9SoftmaxCrossEntropyTilingReadyBindings, GAP9SoftmaxGradTilingReadyBindings, \ + GAP9SoftmaxTilingReadyBindings, GAP9TransposeTilingReadyBindings, GAP9UniformRQSTilingReadyBindings from Deeploy.Targets.Generic.Bindings import BasicGEMMBindings, BasicPad1DBindings, BasicPad2DBindings, \ BasicRQIntegerDivBinding -from Deeploy.Targets.Generic.Layers import AddLayer, ConcatLayer, ConvLayer, GatherLayer, GELULayer, GEMMLayer, \ - LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, QuantLayer, ReduceMeanLayer, ReduceSumLayer, \ - ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, RQSiGELULayer, RQSiHardswishLayer, SGDLayer, \ - SliceLayer, SoftmaxCrossEntropyLossGradLayer, SoftmaxCrossEntropyLossLayer, SoftmaxGradLayer, SoftmaxLayer, \ - TransposeLayer, iHardswishLayer, iRMSNormLayer -from Deeploy.Targets.Generic.Parsers import AddParser, ConcatParser, DequantParser, FlattenParser, GatherParser, \ - GELUParser, GEMMParser, LayerNormParser, MatMulParser, MaxPool2DParser, MulParser, Pad1DParser, Pad2DParser, \ - QuantParser, ReduceMeanParser, ReduceSumParser, ReluParser, RequantShiftParser, ReshapeParser, RQAddParser, \ - RQIntegerDivParser, RQSiGELUParser, RQSiHardswishParser, SGDParser, SliceParser, \ +from Deeploy.Targets.Generic.Layers import AdamLayer, AddLayer, ConcatLayer, ConvLayer, GatherLayer, GELULayer, \ + GEMMLayer, LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, QuantLayer, ReduceMeanLayer, \ + ReduceSumLayer, ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, RQSiGELULayer, \ + RQSiHardswishLayer, SGDLayer, SliceLayer, SoftmaxCrossEntropyLossGradLayer, SoftmaxCrossEntropyLossLayer, \ + SoftmaxGradLayer, SoftmaxLayer, TransposeLayer, iHardswishLayer, iRMSNormLayer +from Deeploy.Targets.Generic.Parsers import AdamParser, AddParser, ConcatParser, DequantParser, FlattenParser, \ + GatherParser, GELUParser, GEMMParser, LayerNormParser, MatMulParser, MaxPool2DParser, MulParser, Pad1DParser, \ + Pad2DParser, QuantParser, ReduceMeanParser, ReduceSumParser, ReluParser, RequantShiftParser, ReshapeParser, \ + RQAddParser, RQIntegerDivParser, RQSiGELUParser, RQSiHardswishParser, SGDParser, SliceParser, \ SoftmaxCrossEntropyLossGradParser, SoftmaxCrossEntropyLossParser, SoftmaxGradParser, SoftmaxParser, \ TransposeParser, UniformRequantShiftParser, UnsqueezeParser, iHardswishParser, iRMSNormParser, iSoftmaxParser from Deeploy.Targets.Generic.Templates import AllocateTemplate as BasicAllocateTemplate @@ -90,6 +90,7 @@ GAP9_SoftmaxCrossEntropyLossGradMapper = NodeMapper(SoftmaxCrossEntropyLossGradParser(), GAP9SoftmaxCrossEntropyGradTilingReadyBindings) GAP9_SGDMapper = NodeMapper(SGDParser(), GAP9SGDTilingReadyBindings) +GAP9_AdamMapper = NodeMapper(AdamParser(), GAP9AdamTilingReadyBindings) GAP9_QuantMapper = NodeMapper(QuantParser(), BasicQuantBindings) GAP9_DequantMapper = NodeMapper(DequantParser(), BasicDequantBindings) GAP9_GEMMDequantMapper = NodeMapper(PULPGEMMParser(), BasicGEMMBindings) @@ -171,7 +172,9 @@ 'SoftmaxCrossEntropyLossGrad': SoftmaxCrossEntropyLossGradLayer([GAP9_SoftmaxCrossEntropyLossGradMapper]), 'SGD': - SGDLayer([GAP9_SGDMapper]) + SGDLayer([GAP9_SGDMapper]), + 'Adam': + AdamLayer([GAP9_AdamMapper]) } diff --git a/Deeploy/Targets/GAP9/Tiler.py b/Deeploy/Targets/GAP9/Tiler.py index fefe12b6d7..ae419c5fd7 100644 --- a/Deeploy/Targets/GAP9/Tiler.py +++ b/Deeploy/Targets/GAP9/Tiler.py @@ -10,14 +10,14 @@ import copy -from Deeploy.Targets.GAP9.Bindings import GAP9AddBindings, GAP9ConcatBindings, GAP9FloatConv2DBindings, \ - GAP9FloatDWConv2DBindings, GAP9FloatGELUBinding, GAP9FloatGEMMBindings, GAP9GatherBindings, \ - GAP9iHardswishBindings, GAP9iRMSNormBindings, GAP9iRQSGELUBindings, GAP9LayernormBinding, GAP9MatMulBindings, \ - GAP9MaxPool2DBindings, GAP9MulBindings, GAP9ReduceSumBindings, GAP9ReluBinding, GAP9ReshapeBindings, \ - GAP9RQAddBindings, GAP9RQSBindings, GAP9RQSConv2DBindings, GAP9RQSDWConv2DBindings, GAP9RQSGEMMBindings, \ - GAP9RQSiHardswishBindings, GAP9RQSMatrixVecBindings, GAP9RQSTallGEMMBindings, GAP9SGDBindings, \ - GAP9SoftmaxBindings, GAP9SoftmaxCrossEntropyLossBindings, GAP9SoftmaxCrossEntropyLossGradBindings, \ - GAP9SoftmaxGradBindings, GAP9TransposeBindings, GAP9UniformRQSBindings +from Deeploy.Targets.GAP9.Bindings import GAP9AdamBindings, GAP9AddBindings, GAP9ConcatBindings, \ + GAP9FloatConv2DBindings, GAP9FloatDWConv2DBindings, GAP9FloatGELUBinding, GAP9FloatGEMMBindings, \ + GAP9GatherBindings, GAP9iHardswishBindings, GAP9iRMSNormBindings, GAP9iRQSGELUBindings, GAP9LayernormBinding, \ + GAP9MatMulBindings, GAP9MaxPool2DBindings, GAP9MulBindings, GAP9ReduceSumBindings, GAP9ReluBinding, \ + GAP9ReshapeBindings, GAP9RQAddBindings, GAP9RQSBindings, GAP9RQSConv2DBindings, GAP9RQSDWConv2DBindings, \ + GAP9RQSGEMMBindings, GAP9RQSiHardswishBindings, GAP9RQSMatrixVecBindings, GAP9RQSTallGEMMBindings, \ + GAP9SGDBindings, GAP9SoftmaxBindings, GAP9SoftmaxCrossEntropyLossBindings, \ + GAP9SoftmaxCrossEntropyLossGradBindings, GAP9SoftmaxGradBindings, GAP9TransposeBindings, GAP9UniformRQSBindings from Deeploy.Targets.Generic.TileConstraints.AddTileConstraint import AddTileConstraint from Deeploy.Targets.Generic.TileConstraints.ConcatTileConstraint import ConcatTileConstraint from Deeploy.Targets.Generic.TileConstraints.iHardswishTileConstraint import iHardswishTileConstraint @@ -39,6 +39,7 @@ from Deeploy.Targets.PULPOpen.TileConstraints.MatMulTileConstraint import MatMulTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.MaxPoolTileConstraint import MaxPoolCTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.RequantShiftTileConstraint import RequantShiftTileConstraint +from Deeploy.Targets.PULPOpen.TileConstraints.AdamTileConstraint import AdamTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.SGDTileConstraint import SGDTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.SoftmaxCrossEntropyTileConstraint import \ SoftmaxCrossEntropyGradTileConstraint, SoftmaxCrossEntropyTileConstraint @@ -142,3 +143,6 @@ GAP9SGDTilingReadyBindings = TilingReadyNodeBindings(nodeBindings = GAP9SGDBindings, tileConstraint = SGDTileConstraint()) + +GAP9AdamTilingReadyBindings = TilingReadyNodeBindings(nodeBindings = GAP9AdamBindings, + tileConstraint = AdamTileConstraint()) diff --git a/Deeploy/Targets/Generic/Bindings.py b/Deeploy/Targets/Generic/Bindings.py index 308b179aef..2b8972b581 100644 --- a/Deeploy/Targets/Generic/Bindings.py +++ b/Deeploy/Targets/Generic/Bindings.py @@ -12,19 +12,19 @@ from Deeploy.DeeployTypes import CodeTransformation, NodeBinding from Deeploy.FutureExtension.CodeTransformationPasses.FutureCodeTransformation import FutureGeneration from Deeploy.Targets.Generic.Templates import AddTemplate, BatchNormalizationTemplate, ConcatTemplate, ConvTemplate, \ - ConvTransposeTemplate, DebugPrintTemplate, DequantTemplate, DummyTemplate, DWConvTemplate, FloatAddTemplate, \ - FloatConvTemplate, FloatDivTemplate, FloatDWConvTemplate, FloatGELUTemplate, FloatGemmTemplate, \ - FloatLayernormTemplate, FloatMatMulTemplate, FloatMaxPoolTemplate, FloatMulTemplate, FloatPadTemplate, \ - FloatPowTemplate, FloatReduceMeanTemplate, FloatReluTemplate, FloatSoftmaxTemplate, FloatSqrtTemplate, \ - GatherTemplate, GemmTemplate, IntegerDivTemplate, ITAMaxTemplate, ITAPartialMaxTemplate, MatMulTemplate, \ - MaxPoolTemplate, MulTemplate, PadTemplate, QuantTemplate, ReduceMeanTemplate, ReduceSumTemplate, \ + ConvTransposeTemplate, DebugPrintTemplate, DequantTemplate, DummyTemplate, DWConvTemplate, FloatAdamTemplate, \ + FloatAddTemplate, FloatConvTemplate, FloatDivTemplate, FloatDWConvTemplate, FloatGELUTemplate, \ + FloatGemmTemplate, FloatLayernormTemplate, FloatMatMulTemplate, FloatMaxPoolTemplate, FloatMulTemplate, \ + FloatPadTemplate, FloatPowTemplate, FloatReduceMeanTemplate, FloatReluTemplate, FloatSoftmaxTemplate, \ + FloatSqrtTemplate, GatherTemplate, GemmTemplate, IntegerDivTemplate, ITAMaxTemplate, ITAPartialMaxTemplate, \ + MatMulTemplate, MaxPoolTemplate, MulTemplate, PadTemplate, QuantTemplate, ReduceMeanTemplate, ReduceSumTemplate, \ RequantShiftTemplate, ReshapeTemplate, RQIntegerDivTemplate, RQSiGELUTemplate, SliceTemplate, TransposeTemplate, \ iGELUTemplate, iLayernormTemplate, iRMSNormTemplate, iSoftmaxTemplate -from Deeploy.Targets.Generic.TypeCheckers import AddChecker, BatchNormChecker, ConcatChecker, ConvChecker, \ - DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, GEMMChecker, \ - LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, ReduceMeanChecker, \ - ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, SliceChecker, \ - SoftmaxChecker, TransposeChecker +from Deeploy.Targets.Generic.TypeCheckers import AdamChecker, AddChecker, BatchNormChecker, ConcatChecker, \ + ConvChecker, DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, \ + GEMMChecker, LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, \ + ReduceMeanChecker, ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, \ + SliceChecker, SoftmaxChecker, TransposeChecker BasicTransformer = CodeTransformation([ArgumentStructGeneration(), MemoryManagementGeneration(), FutureGeneration()]) @@ -312,6 +312,17 @@ for type in FloatDataTypes ] +BasicAdamBindings = [ + NodeBinding( + AdamChecker( + # Note: ONNX spec defines T as int64, but we use int32 for embedded compatibility + [PointerClass(float32_t), PointerClass(int32_t), PointerClass(float32_t), PointerClass(float32_t), + PointerClass(float32_t), PointerClass(float32_t)], # R, T, X, G, V, H + [PointerClass(float32_t)] # X_new only + ), + FloatAdamTemplate.referenceTemplate, BasicTransformer) +] + BasicConvTransposeBindings = [ NodeBinding( ConvChecker( diff --git a/Deeploy/Targets/Generic/Layers.py b/Deeploy/Targets/Generic/Layers.py index cc733937cc..62b90da168 100644 --- a/Deeploy/Targets/Generic/Layers.py +++ b/Deeploy/Targets/Generic/Layers.py @@ -492,6 +492,22 @@ def __init__(self, maps: List[NodeMapper]): super().__init__(maps) +class AdamLayer(ONNXLayer): + + def __init__(self, maps: List[NodeMapper]): + super().__init__(maps) + + def computeOps(self): + size = self.mapper.parser.operatorRepresentation['size'] + # Per element: + # m (V) update : 2 mul + 1 add = 3 ops + # v (H) update : 3 mul + 1 add = 4 ops (includes G*G) + # weight update: 1 sqrt + 1 div + + # 1 mul + 1 sub = 4 ops (epsilon=0, +eps eliminated) + # Total = 11 ops + return size * 11 + + class LinearAttentionLayer(ONNXLayer): def __init__(self, maps: List[NodeMapper]): diff --git a/Deeploy/Targets/Generic/Parsers.py b/Deeploy/Targets/Generic/Parsers.py index ad787d9e4b..7a31760a02 100644 --- a/Deeploy/Targets/Generic/Parsers.py +++ b/Deeploy/Targets/Generic/Parsers.py @@ -2697,6 +2697,51 @@ def parseNodeCtxt(self, return ctxt, True +class AdamParser(NodeParser): + + def __init__(self): + super().__init__() + + def parseNode(self, node: gs.Node) -> bool: + n_inputs = len(node.inputs) + n_outputs = len(node.outputs) + num_tensors = (n_inputs - 2) // 4 + valid_inputs = n_inputs >= 6 and (n_inputs - 2) % 4 == 0 + valid_outputs = n_outputs >= 1 and n_outputs == num_tensors + valid_attrs = all(a in node.attrs for a in ['alpha', 'beta', 'epsilon', 'norm_coefficient', 'norm_coefficient_post']) + + return all([valid_inputs, valid_outputs, valid_attrs]) + + def parseNodeCtxt(self, + ctxt: NetworkContext, + node: gs.Node, + channels_first: bool = True) -> Tuple[NetworkContext, bool]: + + R = ctxt.lookup(node.inputs[0].name) + T = ctxt.lookup(node.inputs[1].name) + X = ctxt.lookup(node.inputs[2].name) + G = ctxt.lookup(node.inputs[3].name) + V = ctxt.lookup(node.inputs[4].name) + H = ctxt.lookup(node.inputs[5].name) + + X_new = ctxt.lookup(node.outputs[0].name) + + self.operatorRepresentation['R'] = R.name + self.operatorRepresentation['T'] = T.name + self.operatorRepresentation['X'] = X.name + self.operatorRepresentation['G'] = G.name + self.operatorRepresentation['V'] = V.name + self.operatorRepresentation['H'] = H.name + self.operatorRepresentation['X_new'] = X_new.name + self.operatorRepresentation['size'] = np.prod(X.shape) + self.operatorRepresentation['alpha'] = node.attrs['alpha'] + self.operatorRepresentation['beta'] = node.attrs['beta'] + self.operatorRepresentation['epsilon'] = node.attrs['epsilon'] + self.operatorRepresentation['norm_coefficient'] = node.attrs['norm_coefficient'] + self.operatorRepresentation['norm_coefficient_post'] = node.attrs['norm_coefficient_post'] + return ctxt, True + + class BatchNormParser(NodeParser): def __init__(self): diff --git a/Deeploy/Targets/Generic/Platform.py b/Deeploy/Targets/Generic/Platform.py index e05e897270..3737ae466a 100644 --- a/Deeploy/Targets/Generic/Platform.py +++ b/Deeploy/Targets/Generic/Platform.py @@ -6,32 +6,33 @@ RemoveEmptyConvBiasPass, RemoveOnlySingletonReduceMeanPass from Deeploy.DeeployTypes import ConstantBuffer, DeploymentEngine, DeploymentPlatform, NodeMapper, NodeTemplate, \ StructBuffer, TopologyOptimizer, TransientBuffer, VariableBuffer -from Deeploy.Targets.Generic.Bindings import BasicAddBindings, BasicBatchNormBindings, BasicConcatBindings, \ - BasicConv1DBindings, BasicConv2DBindings, BasicConvTransposeBindings, BasicDebugPrintBindings, \ - BasicDequantBindings, BasicDivBindings, BasicDWConv1DBinding, BasicDWConv2DBindings, BasicGatherBindings, \ - BasicGELUBindings, BasicGEMMBindings, BasicITAPartialSoftmaxBinding, BasicITASoftmaxBinding, \ - BasicLayerNormBindings, BasicMatMulBindings, BasicMaxPool1DBindings, BasicMaxPool2DBindings, BasicMulBindings, \ - BasicPad1DBindings, BasicPad2DBindings, BasicPowBindings, BasicQuantBindings, BasicReduceMeanBindings, \ - BasicReduceSumBindings, BasicReluBinding, BasicReshapeBindings, BasicRQIntegerDivBinding, BasicRQSBindings, \ - BasicRQSGELUBinding, BasicSliceBindings, BasicSoftmaxBindings, BasicSqrtBindings, BasicTransposeBindings, \ - DummyBinding -from Deeploy.Targets.Generic.Layers import AddLayer, BatchNormalizationLayer, ConcatLayer, ConvLayer, \ +from Deeploy.Targets.Generic.Bindings import BasicAdamBindings, BasicAddBindings, BasicBatchNormBindings, \ + BasicConcatBindings, BasicConv1DBindings, BasicConv2DBindings, BasicConvTransposeBindings, \ + BasicDebugPrintBindings, BasicDequantBindings, BasicDivBindings, BasicDWConv1DBinding, BasicDWConv2DBindings, \ + BasicGatherBindings, BasicGELUBindings, BasicGEMMBindings, BasicITAPartialSoftmaxBinding, \ + BasicITASoftmaxBinding, BasicLayerNormBindings, BasicMatMulBindings, BasicMaxPool1DBindings, \ + BasicMaxPool2DBindings, BasicMulBindings, BasicPad1DBindings, BasicPad2DBindings, BasicPowBindings, \ + BasicQuantBindings, BasicReduceMeanBindings, BasicReduceSumBindings, BasicReluBinding, BasicReshapeBindings, \ + BasicRQIntegerDivBinding, BasicRQSBindings, BasicRQSGELUBinding, BasicSliceBindings, BasicSoftmaxBindings, \ + BasicSqrtBindings, BasicTransposeBindings, DummyBinding +from Deeploy.Targets.Generic.Layers import AdamLayer, AddLayer, BatchNormalizationLayer, ConcatLayer, ConvLayer, \ ConvTransposeLayer, DebugPrintLayer, DequantLayer, DivLayer, GatherLayer, GELULayer, GEMMLayer, ITAMaxLayer, \ LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, PowLayer, QuantLayer, ReduceMeanLayer, \ ReduceSumLayer, ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, RQSiGELULayer, SliceLayer, \ SoftmaxLayer, SqrtLayer, TransposeLayer -from Deeploy.Targets.Generic.Parsers import AddParser, BatchNormParser, ConcatParser, ConvTranspose1DParser, \ - DebugParser, DequantParser, DivParser, DummyParser, FlattenParser, GatherParser, GELUParser, GenericConv1DParser, \ - GenericConv2DParser, GenericDWConv1DParser, GenericDWConv2DParser, GenericGEMMParser, GenericMaxPool2DParser, \ - IntegerDivParser, ITAMaxParser, ITAPartialMaxParser, LayerNormParser, MatMulParser, MaxPool1DParser, MulParser, \ - Pad1DParser, Pad2DParser, PowParser, QuantParser, ReduceMeanParser, ReduceSumParser, ReluParser, \ - RequantShiftParser, ReshapeParser, RQIntegerDivParser, RQSiGELUParser, SliceParser, SoftmaxParser, SqrtParser, \ - TransposeParser, UnsqueezeParser, iLayerNormParser, iSoftmaxParser +from Deeploy.Targets.Generic.Parsers import AdamParser, AddParser, BatchNormParser, ConcatParser, \ + ConvTranspose1DParser, DebugParser, DequantParser, DivParser, DummyParser, FlattenParser, GatherParser, \ + GELUParser, GenericConv1DParser, GenericConv2DParser, GenericDWConv1DParser, GenericDWConv2DParser, \ + GenericGEMMParser, GenericMaxPool2DParser, IntegerDivParser, ITAMaxParser, ITAPartialMaxParser, LayerNormParser, \ + MatMulParser, MaxPool1DParser, MulParser, Pad1DParser, Pad2DParser, PowParser, QuantParser, ReduceMeanParser, \ + ReduceSumParser, ReluParser, RequantShiftParser, ReshapeParser, RQIntegerDivParser, RQSiGELUParser, SliceParser, \ + SoftmaxParser, SqrtParser, TransposeParser, UnsqueezeParser, iLayerNormParser, iSoftmaxParser from Deeploy.Targets.Generic.Templates import AllocateTemplate, FreeTemplate from Deeploy.Targets.Generic.TopologyOptimizationPasses.Passes import DequantPatternPass, ExtractPaddingFromConvPass, \ ExtractPaddingFromPoolPass, MatMulAddMergePass, MergeConstAddAndRequantPass, QuantPatternPass, \ iGELURequantMergePass +AdamMapper = NodeMapper(AdamParser(), BasicAdamBindings) AddMapper = NodeMapper(AddParser(), BasicAddBindings) Conv1DMapper = NodeMapper(GenericConv1DParser(), BasicConv1DBindings) Conv2DMapper = NodeMapper(GenericConv2DParser(), BasicConv2DBindings) @@ -79,6 +80,7 @@ DummyMapper = NodeMapper(DummyParser(), [DummyBinding]) GenericMapping = { + 'Adam': AdamLayer([AdamMapper]), 'Add': AddLayer([AddMapper]), 'Conv': ConvLayer([Conv2DMapper, DWConv2DMapper, Conv1DMapper, DWConv1DMapper]), 'Concat': ConcatLayer([ConcatMapper]), diff --git a/Deeploy/Targets/Generic/Templates/FloatAdamTemplate.py b/Deeploy/Targets/Generic/Templates/FloatAdamTemplate.py new file mode 100644 index 0000000000..76dbb47fd6 --- /dev/null +++ b/Deeploy/Targets/Generic/Templates/FloatAdamTemplate.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +from Deeploy.DeeployTypes import NodeTemplate + +referenceTemplate = NodeTemplate(""" +// Adam Weight Update (Name: ${nodeName}, Op: ${nodeOp}) +// inputs=[R, T, X, G, V, H], outputs=[X_new] +// V and H are NOT written back; V_new and H_new are local temporaries used only +// to compute the correct X_new. Use separate kernels to update V and H in memory. +BEGIN_SINGLE_CORE + float32_t R_val = *${R}; + // Note: ONNX spec defines T as int64, but we use int32 for embedded compatibility + int32_t T_val = *${T}; + float32_t alpha = ${alpha}; + float32_t beta_coeff = ${beta}; + float32_t epsilon = ${epsilon}; + float32_t norm_coef = ${norm_coefficient}; + float32_t norm_coef_post = ${norm_coefficient_post}; + float32_t R_adjusted; + if (T_val > 0) { + R_adjusted = R_val * sqrtf(1.0f - powf(beta_coeff, (float32_t)T_val)) / (1.0f - powf(alpha, (float32_t)T_val)); + } else { + R_adjusted = R_val; + } + for (uint32_t i = 0; i < ${size}; i++) { + float32_t G_reg = norm_coef * ${X}[i] + ${G}[i]; + float32_t V_new = alpha * ${V}[i] + (1.0f - alpha) * G_reg; + float32_t H_new = beta_coeff * ${H}[i] + (1.0f - beta_coeff) * G_reg * G_reg; + ${X_new}[i] = (1.0f - norm_coef_post) * (${X}[i] - R_adjusted * V_new / (sqrtf(H_new) + epsilon)); + } +END_SINGLE_CORE +""") diff --git a/Deeploy/Targets/Generic/TypeCheckers.py b/Deeploy/Targets/Generic/TypeCheckers.py index c2c8d436f8..21fc175f07 100644 --- a/Deeploy/Targets/Generic/TypeCheckers.py +++ b/Deeploy/Targets/Generic/TypeCheckers.py @@ -598,6 +598,21 @@ def _inferSignedness(self, inputs: List[VariableBuffer], return [True] +class AdamChecker(SignPropTypeChecker): + + def __init__(self, input_types: Sequence[Type[Pointer]], output_types: Sequence[Type[Pointer]]): + super().__init__(input_types, output_types) + + def _inferNumLevels(self, inputs: List[VariableBuffer], + operatorRepresentation: OperatorRepresentation) -> Optional[List[int]]: + # Only X_new is an output; V and H are read-only inputs. + return [2**(self.input_types[0].referencedType.typeWidth)] + + def _inferSignedness(self, inputs: List[VariableBuffer], + operatorRepresentation: OperatorRepresentation) -> Optional[List[bool]]: + return [True] + + class BatchNormChecker(SignPropTypeChecker): def __init__(self, input_types: Sequence[Type[Pointer]], output_types: Sequence[Type[Pointer]]): diff --git a/Deeploy/Targets/PULPOpen/Bindings.py b/Deeploy/Targets/PULPOpen/Bindings.py index 84ee2420e3..eb087a7ba0 100644 --- a/Deeploy/Targets/PULPOpen/Bindings.py +++ b/Deeploy/Targets/PULPOpen/Bindings.py @@ -16,10 +16,10 @@ from Deeploy.FutureExtension.CodeTransformationPasses.FutureCodeTransformation import FutureGeneration from Deeploy.Targets.Generic.Templates import AddTemplate, ConcatTemplate, DequantTemplate, FloatReduceSumTemplate, \ GatherTemplate, QuantTemplate, RQSiGELUTemplate, SliceTemplate, iHardswishTemplate -from Deeploy.Targets.Generic.TypeCheckers import AddChecker, ConcatChecker, ConvChecker, DequantChecker, \ - GatherChecker, GELUChecker, GEMMChecker, HardswishChecker, LayerNormChecker, MatMulChecker, MulChecker, \ - QuantChecker, ReduceMeanChecker, ReluChecker, ReshapeChecker, RQAddChecker, RQHardswishChecker, SGDChecker, \ - SliceChecker, SoftmaxChecker, SoftmaxCrossEntropyLossChecker, TransposeChecker +from Deeploy.Targets.Generic.TypeCheckers import AdamChecker, AddChecker, ConcatChecker, ConvChecker, \ + DequantChecker, GatherChecker, GELUChecker, GEMMChecker, HardswishChecker, LayerNormChecker, MatMulChecker, \ + MulChecker, QuantChecker, ReduceMeanChecker, ReluChecker, ReshapeChecker, RQAddChecker, RQHardswishChecker, \ + SGDChecker, SliceChecker, SoftmaxChecker, SoftmaxCrossEntropyLossChecker, TransposeChecker from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPClusterSynch import PULPSynchCoresPass from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPClusterTiling import PULPClusterTiling from Deeploy.Targets.PULPOpen.CodeTransformationPasses.PULPL3Tiling import PULPL3Tiling @@ -27,12 +27,12 @@ from Deeploy.Targets.PULPOpen.DataTypes import PULPDMAFuture from Deeploy.Targets.PULPOpen.DMA.L3Dma import l3DmaHack from Deeploy.Targets.PULPOpen.DMA.MchanDma import MchanDma -from Deeploy.Targets.PULPOpen.Templates import ConvTemplate, DMASliceTemplate, FloatAddTemplate, FloatConvTemplate, \ - FloatGELUTemplate, FloatGemmTemplate, FloatLayernormTemplate, FloatMatMulTemplate, FloatMaxPoolTemplate, \ - FloatMulTemplate, FloatReduceMeanTemplate, FloatReluTemplate, FloatSoftmaxTemplate, GEMMTemplate, \ - MatrixVectorTemplate, MaxPoolTemplate, MulTemplate, ReduceMeanTemplate, RequantShiftTemplate, ReshapeTemplate, \ - RQAddTemplate, RQSiHardswishTemplate, SGDTemplate, SoftmaxCrossEntropyLossTemplate, TallGEMMTemplate, \ - TransposeTemplate, UniformRequantShiftTemplate, iRMSNormTemplate, iSoftmaxTemplate +from Deeploy.Targets.PULPOpen.Templates import ConvTemplate, DMASliceTemplate, FloatAdamTemplate, FloatAddTemplate, \ + FloatConvTemplate, FloatGELUTemplate, FloatGemmTemplate, FloatLayernormTemplate, FloatMatMulTemplate, \ + FloatMaxPoolTemplate, FloatMulTemplate, FloatReduceMeanTemplate, FloatReluTemplate, FloatSoftmaxTemplate, \ + GEMMTemplate, MatrixVectorTemplate, MaxPoolTemplate, MulTemplate, ReduceMeanTemplate, RequantShiftTemplate, \ + ReshapeTemplate, RQAddTemplate, RQSiHardswishTemplate, SGDTemplate, SoftmaxCrossEntropyLossTemplate, \ + TallGEMMTemplate, TransposeTemplate, UniformRequantShiftTemplate, iRMSNormTemplate, iSoftmaxTemplate from Deeploy.Targets.PULPOpen.TypeCheckers import PULPConvChecker, PULPLinearChecker, PULPMaxPoolChecker, \ PULPRequantShiftChecker from Deeploy.TilingExtension.CodeTransformationPasses.TilingVariableReplacement import TilingVariableReplacement, \ @@ -367,6 +367,17 @@ SGDTemplate.referenceTemplate, ForkTransformer) ] +PULPAdamBindings = [ + NodeBinding( + AdamChecker( + # Note: ONNX spec defines T as int64, but we use int32 for embedded compatibility + [PointerClass(float32_t), PointerClass(int32_t), PointerClass(float32_t), PointerClass(float32_t), + PointerClass(float32_t), PointerClass(float32_t)], # R, T, X, G, V, H + [PointerClass(float32_t)] # X_new only + ), + FloatAdamTemplate.referenceTemplate, ForkTransformer) +] + PULPTransposeBindings = [ NodeBinding(TransposeChecker([PointerClass(type)], [PointerClass(type)]), TransposeTemplate.referenceTemplate, ForkTransformer) for type in IntegerDataTypes diff --git a/Deeploy/Targets/PULPOpen/Platform.py b/Deeploy/Targets/PULPOpen/Platform.py index 7456dd9e1b..84701e7886 100644 --- a/Deeploy/Targets/PULPOpen/Platform.py +++ b/Deeploy/Targets/PULPOpen/Platform.py @@ -13,13 +13,13 @@ from Deeploy.MemoryLevelExtension.NetworkDeployers.MemoryLevelDeployer import MemoryPlatform, MemoryPlatformWrapper from Deeploy.Targets.Generic.Bindings import BasicGEMMBindings, BasicPad1DBindings, BasicPad2DBindings, \ BasicRQIntegerDivBinding -from Deeploy.Targets.Generic.Layers import AddLayer, ConcatLayer, ConvLayer, GatherLayer, GELUGradLayer, GELULayer, \ - GEMMLayer, LayerNormGradLayer, LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, QuantLayer, \ - ReduceMeanLayer, ReduceSumLayer, ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, RQSiGELULayer, \ - RQSiHardswishLayer, SGDLayer, SliceLayer, SoftmaxCrossEntropyLossGradLayer, SoftmaxCrossEntropyLossLayer, \ - SoftmaxGradLayer, SoftmaxLayer, TransposeLayer, iHardswishLayer, iRMSNormLayer -from Deeploy.Targets.Generic.Parsers import AddParser, ConcatParser, DequantParser, FlattenParser, GatherParser, \ - GELUGradParser, GELUParser, GEMMParser, LayerNormGradParser, LayerNormParser, MatMulParser, MaxPool1DParser, \ +from Deeploy.Targets.Generic.Layers import AdamLayer, AddLayer, ConcatLayer, ConvLayer, GatherLayer, GELUGradLayer, \ + GELULayer, GEMMLayer, LayerNormGradLayer, LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, \ + QuantLayer, ReduceMeanLayer, ReduceSumLayer, ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, \ + RQSiGELULayer, RQSiHardswishLayer, SGDLayer, SliceLayer, SoftmaxCrossEntropyLossGradLayer, \ + SoftmaxCrossEntropyLossLayer, SoftmaxGradLayer, SoftmaxLayer, TransposeLayer, iHardswishLayer, iRMSNormLayer +from Deeploy.Targets.Generic.Parsers import AdamParser, AddParser, ConcatParser, DequantParser, FlattenParser, \ + GatherParser, GELUGradParser, GELUParser, GEMMParser, LayerNormGradParser, LayerNormParser, MatMulParser, MaxPool1DParser, \ MaxPool2DParser, MulParser, Pad1DParser, Pad2DParser, QuantParser, ReduceSumParser, ReluParser, \ RequantShiftParser, ReshapeParser, RQAddParser, RQIntegerDivParser, RQSiGELUParser, RQSiHardswishParser, \ SGDParser, SliceParser, SoftmaxCrossEntropyLossGradParser, SoftmaxCrossEntropyLossParser, SoftmaxGradParser, \ @@ -41,15 +41,15 @@ PULPFPGELUGradTilingReadyBindings, PULPFPGELUTilingReadyBindings, PULPFPGEMMTilingReadyBindings, \ PULPGatherTilingReadyBindings, PULPiHardswishTilingReadyBindings, PULPiRMSNormTilingReadyBindings, \ PULPiRQSGELUTilingReadyBindings, PULPLayernormGradTilingReadyBindings, PULPLayernormTilingReadyBindings, \ - PULPMatMulTilingReadyBindings, PULPMaxPool1DTilingReadyBindings, PULPMaxPool2DTilingReadyBindings, \ - PULPMulTilingReadyBindings, PULPReduceMeanTilingReadyBindings, PULPReduceSumTilingReadyBindings, \ - PULPReluTilingReadyBindings, PULPRQAddTilingReadyBindings, PULPRQSConv1DTilingReadyBindings, \ - PULPRQSConv2DTilingReadyBindings, PULPRQSDWConv2DTilingReadyBindings, PULPRQSGEMMTilingReadyBindings, \ - PULPRQSiHardswishTilingReadyBindings, PULPRQSMatrixVecTilingReadyBindings, PULPRQSTallGEMMTilingReadyBindings, \ - PULPRQSTilingReadyBindings, PULPSGDTilingReadyBindings, PULPSliceTilingReadyBindings, \ - PULPSoftmaxCrossEntropyGradTilingReadyBindings, PULPSoftmaxCrossEntropyTilingReadyBindings, \ - PULPSoftmaxGradTilingReadyBindings, PULPSoftmaxTilingReadyBindings, PULPTransposeTilingReadyBindings, \ - PULPUniformRQSTilingReadyBindings + PULPAdamTilingReadyBindings, PULPMatMulTilingReadyBindings, PULPMaxPool1DTilingReadyBindings, \ + PULPMaxPool2DTilingReadyBindings, PULPMulTilingReadyBindings, PULPReduceMeanTilingReadyBindings, \ + PULPReduceSumTilingReadyBindings, PULPReluTilingReadyBindings, PULPRQAddTilingReadyBindings, \ + PULPRQSConv1DTilingReadyBindings, PULPRQSConv2DTilingReadyBindings, PULPRQSDWConv2DTilingReadyBindings, \ + PULPRQSGEMMTilingReadyBindings, PULPRQSiHardswishTilingReadyBindings, PULPRQSMatrixVecTilingReadyBindings, \ + PULPRQSTallGEMMTilingReadyBindings, PULPRQSTilingReadyBindings, PULPSGDTilingReadyBindings, \ + PULPSliceTilingReadyBindings, PULPSoftmaxCrossEntropyGradTilingReadyBindings, \ + PULPSoftmaxCrossEntropyTilingReadyBindings, PULPSoftmaxGradTilingReadyBindings, PULPSoftmaxTilingReadyBindings, \ + PULPTransposeTilingReadyBindings, PULPUniformRQSTilingReadyBindings from Deeploy.Targets.PULPOpen.TopologyOptimizationPasses.Passes import PULPAddRequantMergePass, \ PULPConvRequantMergePass, PULPGEMMRequantMergePass, PULPMatMulRequantMergePass @@ -108,6 +108,7 @@ SoftmaxCrossEntropyLossGradMapper = NodeMapper(SoftmaxCrossEntropyLossGradParser(), PULPSoftmaxCrossEntropyGradTilingReadyBindings) SGDMapper = NodeMapper(SGDParser(), PULPSGDTilingReadyBindings) +AdamMapper = NodeMapper(AdamParser(), PULPAdamTilingReadyBindings) QuantMapper = NodeMapper(QuantParser(), BasicQuantBindings) DequantMapper = NodeMapper(DequantParser(), BasicDequantBindings) GEMMDequantMapper = NodeMapper(PULPGEMMParser(), BasicGEMMBindings) @@ -151,7 +152,8 @@ 'SoftmaxGrad': SoftmaxGradLayer([SoftmaxGradMapper]), 'SoftmaxCrossEntropyLoss': SoftmaxCrossEntropyLossLayer([SoftmaxCrossEntropyLossMapper]), 'SoftmaxCrossEntropyLossGrad': SoftmaxCrossEntropyLossGradLayer([SoftmaxCrossEntropyLossGradMapper]), - 'SGD': SGDLayer([SGDMapper]) + 'SGD': SGDLayer([SGDMapper]), + 'Adam': AdamLayer([AdamMapper]), } diff --git a/Deeploy/Targets/PULPOpen/Templates/FloatAdamTemplate.py b/Deeploy/Targets/PULPOpen/Templates/FloatAdamTemplate.py new file mode 100644 index 0000000000..3c160bd705 --- /dev/null +++ b/Deeploy/Targets/PULPOpen/Templates/FloatAdamTemplate.py @@ -0,0 +1,70 @@ +# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +from Deeploy.DeeployTypes import NodeTemplate + +referenceTemplate = NodeTemplate(""" +// Adam Weight Update - Parallel with 6x unrolling (Name: ${nodeName}, Op: ${nodeOp}) +// inputs=[R, T, X, G, V, H], outputs=[X_new] +// X, G, V, and H are L1 tile buffers (DMA'd from backing store, which may be L2 or L3). +// V and H are NOT written back; V_new and H_new are local temporaries used only +// to compute the correct X_new. Use separate kernels to update V and H in memory. +float32_t ${nodeName}_R_val = *${R}; +int32_t ${nodeName}_T_val = *${T}; +float32_t ${nodeName}_alpha = ${alpha}; +float32_t ${nodeName}_beta_coeff = ${beta}; +float32_t ${nodeName}_epsilon = ${epsilon}; +float32_t ${nodeName}_norm_coef = ${norm_coefficient}; +float32_t ${nodeName}_norm_coef_post = ${norm_coefficient_post}; +float32_t ${nodeName}_R_adjusted; +if (${nodeName}_T_val > 0) { + ${nodeName}_R_adjusted = ${nodeName}_R_val * sqrtf(1.0f - powf(${nodeName}_beta_coeff, (float32_t)${nodeName}_T_val)) / (1.0f - powf(${nodeName}_alpha, (float32_t)${nodeName}_T_val)); +} else { + ${nodeName}_R_adjusted = ${nodeName}_R_val; +} + +uint8_t ${nodeName}_core_id = (uint8_t) pi_core_id(); +uint8_t ${nodeName}_log2Core = (uint8_t) log2(NUM_CORES); +uint32_t ${nodeName}_chunk = (${size} >> ${nodeName}_log2Core) + ((${size} & (NUM_CORES-1))!=0); +uint32_t ${nodeName}_chunk_start = (uint32_t) MIN(${nodeName}_chunk*${nodeName}_core_id, (uint32_t) ${size}); +uint32_t ${nodeName}_chunk_stop = (uint32_t) MIN(${nodeName}_chunk_start + ${nodeName}_chunk, (uint32_t) ${size}); + +uint32_t i = ${nodeName}_chunk_start; +for (; i + 5 < ${nodeName}_chunk_stop; i += 6) { + float32_t ${nodeName}_G_reg_0 = ${nodeName}_norm_coef * ${X}[i+0] + ${G}[i+0]; + float32_t ${nodeName}_G_reg_1 = ${nodeName}_norm_coef * ${X}[i+1] + ${G}[i+1]; + float32_t ${nodeName}_G_reg_2 = ${nodeName}_norm_coef * ${X}[i+2] + ${G}[i+2]; + float32_t ${nodeName}_G_reg_3 = ${nodeName}_norm_coef * ${X}[i+3] + ${G}[i+3]; + float32_t ${nodeName}_G_reg_4 = ${nodeName}_norm_coef * ${X}[i+4] + ${G}[i+4]; + float32_t ${nodeName}_G_reg_5 = ${nodeName}_norm_coef * ${X}[i+5] + ${G}[i+5]; + + float32_t ${nodeName}_V_new_0 = ${nodeName}_alpha * ${V}[i+0] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_0; + float32_t ${nodeName}_V_new_1 = ${nodeName}_alpha * ${V}[i+1] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_1; + float32_t ${nodeName}_V_new_2 = ${nodeName}_alpha * ${V}[i+2] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_2; + float32_t ${nodeName}_V_new_3 = ${nodeName}_alpha * ${V}[i+3] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_3; + float32_t ${nodeName}_V_new_4 = ${nodeName}_alpha * ${V}[i+4] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_4; + float32_t ${nodeName}_V_new_5 = ${nodeName}_alpha * ${V}[i+5] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg_5; + + float32_t ${nodeName}_H_new_0 = ${nodeName}_beta_coeff * ${H}[i+0] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_0 * ${nodeName}_G_reg_0; + float32_t ${nodeName}_H_new_1 = ${nodeName}_beta_coeff * ${H}[i+1] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_1 * ${nodeName}_G_reg_1; + float32_t ${nodeName}_H_new_2 = ${nodeName}_beta_coeff * ${H}[i+2] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_2 * ${nodeName}_G_reg_2; + float32_t ${nodeName}_H_new_3 = ${nodeName}_beta_coeff * ${H}[i+3] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_3 * ${nodeName}_G_reg_3; + float32_t ${nodeName}_H_new_4 = ${nodeName}_beta_coeff * ${H}[i+4] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_4 * ${nodeName}_G_reg_4; + float32_t ${nodeName}_H_new_5 = ${nodeName}_beta_coeff * ${H}[i+5] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg_5 * ${nodeName}_G_reg_5; + + ${X_new}[i+0] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+0] - ${nodeName}_R_adjusted * ${nodeName}_V_new_0 / (sqrtf(${nodeName}_H_new_0) + ${nodeName}_epsilon)); + ${X_new}[i+1] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+1] - ${nodeName}_R_adjusted * ${nodeName}_V_new_1 / (sqrtf(${nodeName}_H_new_1) + ${nodeName}_epsilon)); + ${X_new}[i+2] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+2] - ${nodeName}_R_adjusted * ${nodeName}_V_new_2 / (sqrtf(${nodeName}_H_new_2) + ${nodeName}_epsilon)); + ${X_new}[i+3] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+3] - ${nodeName}_R_adjusted * ${nodeName}_V_new_3 / (sqrtf(${nodeName}_H_new_3) + ${nodeName}_epsilon)); + ${X_new}[i+4] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+4] - ${nodeName}_R_adjusted * ${nodeName}_V_new_4 / (sqrtf(${nodeName}_H_new_4) + ${nodeName}_epsilon)); + ${X_new}[i+5] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i+5] - ${nodeName}_R_adjusted * ${nodeName}_V_new_5 / (sqrtf(${nodeName}_H_new_5) + ${nodeName}_epsilon)); +} + +for (; i < ${nodeName}_chunk_stop; i++) { + float32_t ${nodeName}_G_reg = ${nodeName}_norm_coef * ${X}[i] + ${G}[i]; + float32_t ${nodeName}_V_new = ${nodeName}_alpha * ${V}[i] + (1.0f - ${nodeName}_alpha) * ${nodeName}_G_reg; + float32_t ${nodeName}_H_new = ${nodeName}_beta_coeff * ${H}[i] + (1.0f - ${nodeName}_beta_coeff) * ${nodeName}_G_reg * ${nodeName}_G_reg; + ${X_new}[i] = (1.0f - ${nodeName}_norm_coef_post) * (${X}[i] - ${nodeName}_R_adjusted * ${nodeName}_V_new / (sqrtf(${nodeName}_H_new) + ${nodeName}_epsilon)); +} +""") diff --git a/Deeploy/Targets/PULPOpen/TileConstraints/AdamTileConstraint.py b/Deeploy/Targets/PULPOpen/TileConstraints/AdamTileConstraint.py new file mode 100644 index 0000000000..c3f17f5761 --- /dev/null +++ b/Deeploy/Targets/PULPOpen/TileConstraints/AdamTileConstraint.py @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna +# +# SPDX-License-Identifier: Apache-2.0 + +from typing import Dict, List, Tuple + +import numpy as np + +from Deeploy.AbstractDataTypes import PointerClass +from Deeploy.CommonExtensions.DataTypes import uint16_t +from Deeploy.DeeployTypes import NetworkContext, OperatorRepresentation +from Deeploy.TilingExtension.MemoryConstraints import NodeMemoryConstraint +from Deeploy.TilingExtension.TileConstraint import TileConstraint +from Deeploy.TilingExtension.TilerModel import TilerModel +from Deeploy.TilingExtension.TilingCodegen import AbsoluteHyperRectangle, HyperRectangle, TilingSchedule, \ + VariableReplacementScheme + + +_TILED_TENSORS = ['R', 'T', 'X', 'G', 'V', 'H', 'X_new'] +# Array tensors that share tile geometry with X (excludes the shape-(1,) scalar tensors R and T) +_ARRAY_INPUT_TENSORS = ['X', 'G', 'V', 'H'] + + +class AdamTileConstraint(TileConstraint): + + @classmethod + def addGeometricalConstraint(cls, tilerModel: TilerModel, parseDict: Dict, + ctxt: NetworkContext) -> TilerModel: + + for name in _TILED_TENSORS: + tilerModel.addTensorDimToModel(ctxt, parseDict[name]) + + xShape = ctxt.lookup(parseDict['X']).shape + + for dim in range(len(xShape)): + xDimVar = tilerModel.getTensorDimVar(tensorName = parseDict['X'], dimIdx = dim) + for name in ['G', 'V', 'H', 'X_new']: + dimVar = tilerModel.getTensorDimVar(tensorName = parseDict[name], dimIdx = dim) + tilerModel.addConstraint(xDimVar == dimVar) + + return tilerModel + + @classmethod + def addPolicyConstraint(cls, tilerModel: TilerModel, parseDict: Dict, + ctxt: NetworkContext) -> TilerModel: + # Fix every dimension except the first to its full size so the tiler + # can only split along dim 0. + xShape = ctxt.lookup(parseDict['X']).shape + for dim in range(1, len(xShape)): + dimVar = tilerModel.getTensorDimVar(tensorName = parseDict['X'], dimIdx = dim) + tilerModel.addConstraint(dimVar == xShape[dim]) + return tilerModel + + @classmethod + def serializeTilingSolution( + cls, tilingSolution: NodeMemoryConstraint, + absoluteOutputCubes: List[AbsoluteHyperRectangle], targetMemLevel: str, + ctxt: NetworkContext, + operatorRepresentation: OperatorRepresentation) -> Tuple[VariableReplacementScheme, TilingSchedule]: + + outputCubes = [cube.rectangle for cube in absoluteOutputCubes] + + addrNames = _TILED_TENSORS + inputBaseOffsets, outputBaseOffsets = cls.extractBaseAddr(tilingSolution, targetMemLevel, + operatorRepresentation, addrNames) + + replacements = {"size": []} + replacementTypes = {"size": PointerClass(uint16_t)} + + for cubeAbs in absoluteOutputCubes: + cube = cubeAbs.rectangle + replacements["size"].append(int(np.prod(cube.dims))) + + inputLoadSchedule = [] + outputLoadSchedule = [] + + # Shape-(1,) rectangle for the scalar inputs R and T (1 element each). + scalar_cube = HyperRectangle((0,), (1,)) + + for cube in outputCubes: + tile_load = {name: cube for name in _ARRAY_INPUT_TENSORS} + tile_load['R'] = scalar_cube + tile_load['T'] = scalar_cube + inputLoadSchedule.append(tile_load) + + for cube in outputCubes: + outputLoadSchedule.append({'X_new': cube}) + + tilingSchedule = TilingSchedule(inputBaseOffsets, outputBaseOffsets, inputLoadSchedule, + outputLoadSchedule) + variableReplacementSchedule = VariableReplacementScheme(replacements, replacementTypes) + + return variableReplacementSchedule, tilingSchedule diff --git a/Deeploy/Targets/PULPOpen/Tiler.py b/Deeploy/Targets/PULPOpen/Tiler.py index 901106459e..21b1ef7963 100644 --- a/Deeploy/Targets/PULPOpen/Tiler.py +++ b/Deeploy/Targets/PULPOpen/Tiler.py @@ -14,15 +14,15 @@ from Deeploy.Targets.Generic.TileConstraints.RQSiHardswishTileConstraint import RQSiHardswishTileConstraint from Deeploy.Targets.Generic.TileConstraints.TransposeTileConstraint import TransposeTileConstraint from Deeploy.Targets.Generic.TileConstraints.UnaryTileConstraint import UnaryTileConstraint -from Deeploy.Targets.PULPOpen.Bindings import PULPAddBindings, PULPConcatBindings, PULPFloatConv2DBindings, \ - PULPFloatDWConv2DBindings, PULPFloatGELUBinding, PULPFloatGELUGradBinding, PULPFloatGEMMBindings, \ - PULPGatherBindings, PULPiHardswishBindings, PULPiRMSNormBindings, PULPiRQSGELUBindings, PULPLayernormBinding, \ - PULPLayernormGradBinding, PULPMatMulBindings, PULPMaxPool1DBindings, PULPMaxPool2DBindings, PULPMulBindings, \ - PULPReduceMeanBindings, PULPReduceSumBindings, PULPReluBinding, PULPReshapeBindings, PULPRQAddBindings, \ - PULPRQSBindings, PULPRQSConv1DBindings, PULPRQSConv2DBindings, PULPRQSDWConv2DBindings, PULPRQSGEMMBindings, \ - PULPRQSiHardswishBindings, PULPRQSMatrixVecBindings, PULPRQSTallGEMMBindings, PULPSGDBindings, PULPSliceBindings, \ - PULPSoftmaxBindings, PULPSoftmaxCrossEntropyLossBindings, PULPSoftmaxCrossEntropyLossGradBindings, \ - PULPSoftmaxGradBindings, PULPTransposeBindings, PULPUniformRQSBindings +from Deeploy.Targets.PULPOpen.Bindings import PULPAdamBindings, PULPAddBindings, PULPConcatBindings, \ + PULPFloatConv2DBindings, PULPFloatDWConv2DBindings, PULPFloatGELUBinding, PULPFloatGELUGradBinding, \ + PULPFloatGEMMBindings, PULPGatherBindings, PULPiHardswishBindings, PULPiRMSNormBindings, PULPiRQSGELUBindings, \ + PULPLayernormBinding, PULPLayernormGradBinding, PULPMatMulBindings, PULPMaxPool1DBindings, PULPMaxPool2DBindings, \ + PULPMulBindings, PULPReduceMeanBindings, PULPReduceSumBindings, PULPReluBinding, PULPReshapeBindings, \ + PULPRQAddBindings, PULPRQSBindings, PULPRQSConv1DBindings, PULPRQSConv2DBindings, PULPRQSDWConv2DBindings, \ + PULPRQSGEMMBindings, PULPRQSiHardswishBindings, PULPRQSMatrixVecBindings, PULPRQSTallGEMMBindings, \ + PULPSGDBindings, PULPSliceBindings, PULPSoftmaxBindings, PULPSoftmaxCrossEntropyLossBindings, \ + PULPSoftmaxCrossEntropyLossGradBindings, PULPSoftmaxGradBindings, PULPTransposeBindings, PULPUniformRQSBindings from Deeploy.Targets.PULPOpen.TileConstraints.ConvTileConstraint import Conv2DTileConstraint, RQConv1DTileConstraint, \ RQConv2DTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.DWConvTileConstraint import DWConv2DTileConstraint, \ @@ -39,6 +39,7 @@ from Deeploy.Targets.PULPOpen.TileConstraints.ReduceMeanConstraint import ReduceMeanTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.ReduceSumTileConstraint import ReduceSumTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.RequantShiftTileConstraint import RequantShiftTileConstraint +from Deeploy.Targets.PULPOpen.TileConstraints.AdamTileConstraint import AdamTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.SGDTileConstraint import SGDTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.SliceConstraint import SliceTileConstraint from Deeploy.Targets.PULPOpen.TileConstraints.SoftmaxCrossEntropyTileConstraint import \ @@ -155,6 +156,9 @@ PULPSGDTilingReadyBindings = TilingReadyNodeBindings(nodeBindings = PULPSGDBindings, tileConstraint = SGDTileConstraint()) +PULPAdamTilingReadyBindings = TilingReadyNodeBindings(nodeBindings = PULPAdamBindings, + tileConstraint = AdamTileConstraint()) + PULPSliceTilingReadyBindings = TilingReadyNodeBindings(nodeBindings = PULPSliceBindings, tileConstraint = SliceTileConstraint()) diff --git a/DeeployTest/Tests/Kernels/FP32/Adam/Regular/inputs.npz b/DeeployTest/Tests/Kernels/FP32/Adam/Regular/inputs.npz new file mode 100644 index 0000000000000000000000000000000000000000..7832aaf1d68839e772238ee1c44fd17f26e3049d GIT binary patch literal 132522 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%0A`VVve_7-yb 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 z

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 z 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 literal 0 HcmV?d00001 diff --git a/DeeployTest/test_gap9_config.py b/DeeployTest/test_gap9_config.py index 69b940f0c3..2bde0b06eb 100644 --- a/DeeployTest/test_gap9_config.py +++ b/DeeployTest/test_gap9_config.py @@ -10,7 +10,7 @@ "Kernels/Integer/Pad/Regular_2D", "Kernels/Integer/MatMul/Regular", "Kernels/Integer/MatMul/Add", "Kernels/Integer/Conv/DW_2D_RQ", "Kernels/Integer/Conv/Regular_2D_RQ", "Kernels/Integer/Softmax/Regular", "Kernels/Integer/Concat", "Kernels/Integer/Hardswish/Regular", "Others/Backtracking", "Kernels/FP32/Add/Regular", - "Kernels/FP32/GEMM/Regular", "Kernels/FP32/Conv/Regular_2D_Bias", "Kernels/FP32/Conv/Regular_2D_NoBias", + "Kernels/FP32/Adam/Regular", "Kernels/FP32/GEMM/Regular", "Kernels/FP32/Conv/Regular_2D_Bias", "Kernels/FP32/Conv/Regular_2D_NoBias", "Kernels/FP32/Conv/Regular_2D_ZeroValuedBias", "Kernels/FP32/Conv/DW_2D_Bias", "Kernels/FP32/Conv/DW_2D_NoBias", "Kernels/FP32/Conv/DW_2D_ZeroValuedBias", "Kernels/FP32/LayerNorm", "Kernels/FP32/ReLU", "Kernels/FP32/MaxPool/Regular_2D", "Kernels/FP32/MatMul", "Kernels/FP32/Softmax/Regular", "Kernels/FP32/Transpose", diff --git a/DeeployTest/test_generic_config.py b/DeeployTest/test_generic_config.py index b0d8c659ca..c52e653048 100644 --- a/DeeployTest/test_generic_config.py +++ b/DeeployTest/test_generic_config.py @@ -43,6 +43,7 @@ "Kernels/FP32/ReduceMean/NoKeepDims/Axis2", "Kernels/FP32/ReduceMean/NoKeepDims/ReduceMean_Add", "Kernels/FP32/Reshape/SkipConnection", + "Kernels/FP32/Adam/Regular", "Kernels/FP32/Sqrt", "Kernels/FP32/Transpose", # Integer Kernels diff --git a/DeeployTest/test_platforms.py b/DeeployTest/test_platforms.py index 6d9f3cfcd7..098c159268 100644 --- a/DeeployTest/test_platforms.py +++ b/DeeployTest/test_platforms.py @@ -34,7 +34,8 @@ from test_siracusa_neureka_tiled_config import L3_DOUBLEBUFFER_MODELS_WMEM as NEUREKA_L3_DOUBLEBUFFER_MODELS_WMEM from test_siracusa_neureka_tiled_config import L3_SINGLEBUFFER_MODELS as NEUREKA_L3_SINGLEBUFFER_MODELS from test_siracusa_tiled_config import L2_DOUBLEBUFFER_KERNELS, L2_DOUBLEBUFFER_MODELS, L2_SINGLEBUFFER_KERNELS, \ - L2_SINGLEBUFFER_MODELS, L3_DOUBLEBUFFER_MODELS, L3_SINGLEBUFFER_MODELS + L2_SINGLEBUFFER_MODELS, L3_DOUBLEBUFFER_KERNELS, L3_DOUBLEBUFFER_MODELS, L3_SINGLEBUFFER_KERNELS, \ + L3_SINGLEBUFFER_MODELS from test_snitch_config import DEFAULT_NUM_CORES as SNITCH_DEFAULT_NUM_CORES from test_snitch_config import KERNEL_TESTS as SNITCH_KERNEL_TESTS from test_snitch_config import MODEL_TESTS as SNITCH_MODEL_TESTS @@ -149,6 +150,17 @@ def param_id(param): @pytest.mark.parametrize("test_name", GENERIC_KERNEL_TESTS, ids = GENERIC_KERNEL_TESTS) def test_generic_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, cmake_args, skipgen, skipsim) -> None: platform_config = PLATFORM_CONFIGS["generic"] + + # Per-test generator arguments: some tests need type overrides to prevent + # Deeploy's signProp from misinterpreting non-activation integer inputs. + # All Adam variants share the same signProp fix: T=1 fits in uint8_t so + # signProp applies offset 128 and stores T=-127. Force int32_t with zero + # offset so the kernel sees T=1 as intended. + _ADAM_GEN_ARGS = ["--input-type-map", "T=int32_t", "--input-offset-map", "T=0"] + _PER_TEST_GEN_ARGS = { + "Kernels/FP32/Adam/Regular": _ADAM_GEN_ARGS, + } + config = create_test_config( test_name = test_name, platform = platform_config["platform"], @@ -158,6 +170,7 @@ def test_generic_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, toolchain_dir = toolchain_dir, cmake_args = cmake_args, tiling = False, + gen_args = _PER_TEST_GEN_ARGS.get(test_name), ) run_and_assert_test(test_name, config, skipgen, skipsim) @@ -265,6 +278,8 @@ def test_mempool_models(test_name, deeploy_test_dir, toolchain, toolchain_dir, c @pytest.mark.parametrize("test_name", SIRACUSA_KERNEL_TESTS, ids = SIRACUSA_KERNEL_TESTS) def test_siracusa_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, cmake_args, skipgen, skipsim, profile_untiled) -> None: + _ADAM_GEN_ARGS = ["--input-type-map", "T=int32_t", "--input-offset-map", "T=0"] + _PER_TEST_GEN_ARGS = {"Kernels/FP32/Adam/Regular": _ADAM_GEN_ARGS} config = create_test_config( test_name = test_name, platform = "Siracusa", @@ -276,6 +291,7 @@ def test_siracusa_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, tiling = False, cores = SIRACUSA_DEFAULT_CORES, profile_untiled = profile_untiled, + gen_args = _PER_TEST_GEN_ARGS.get(test_name), ) run_and_assert_test(test_name, config, skipgen, skipsim) @@ -358,6 +374,64 @@ def test_siracusa_tiled_kernels_l2_doublebuffer(test_params, deeploy_test_dir, t run_and_assert_test(test_name, config, skipgen, skipsim) +@pytest.mark.siracusa_tiled +@pytest.mark.kernels +@pytest.mark.singlebuffer +@pytest.mark.l3 +@pytest.mark.parametrize( + "test_params", + generate_test_params(L3_SINGLEBUFFER_KERNELS, "L3-singlebuffer"), + ids = param_id, +) +def test_siracusa_tiled_kernels_l3_singlebuffer(test_params, deeploy_test_dir, toolchain, toolchain_dir, cmake_args, + skipgen, skipsim) -> None: + test_name, l1, config_name = test_params + config = create_test_config( + test_name = test_name, + platform = "Siracusa", + simulator = "gvsoc", + deeploy_test_dir = deeploy_test_dir, + toolchain = toolchain, + toolchain_dir = toolchain_dir, + cmake_args = cmake_args, + tiling = True, + cores = SIRACUSA_DEFAULT_CORES, + l1 = l1, + default_mem_level = "L3", + double_buffer = False, + ) + run_and_assert_test(test_name, config, skipgen, skipsim) + + +@pytest.mark.siracusa_tiled +@pytest.mark.kernels +@pytest.mark.doublebuffer +@pytest.mark.l3 +@pytest.mark.parametrize( + "test_params", + generate_test_params(L3_DOUBLEBUFFER_KERNELS, "L3-doublebuffer"), + ids = param_id, +) +def test_siracusa_tiled_kernels_l3_doublebuffer(test_params, deeploy_test_dir, toolchain, toolchain_dir, cmake_args, + skipgen, skipsim) -> None: + test_name, l1, config_name = test_params + config = create_test_config( + test_name = test_name, + platform = "Siracusa", + simulator = "gvsoc", + deeploy_test_dir = deeploy_test_dir, + toolchain = toolchain, + toolchain_dir = toolchain_dir, + cmake_args = cmake_args, + tiling = True, + cores = SIRACUSA_DEFAULT_CORES, + l1 = l1, + default_mem_level = "L3", + double_buffer = True, + ) + run_and_assert_test(test_name, config, skipgen, skipsim) + + @pytest.mark.siracusa_tiled @pytest.mark.models @pytest.mark.singlebuffer @@ -756,6 +830,9 @@ def test_gap9_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, cma # Add GAP9-specific CMake args for number of cores gap9_cmake_args = cmake_args + [f"NUM_CORES={platform_config['default_num_cores']}"] + _ADAM_GEN_ARGS = ["--input-type-map", "T=int32_t", "--input-offset-map", "T=0"] + _PER_TEST_GEN_ARGS = {"Kernels/FP32/Adam/Regular": _ADAM_GEN_ARGS} + config = create_test_config( test_name = test_name, platform = platform_config["platform"], @@ -765,6 +842,7 @@ def test_gap9_kernels(test_name, deeploy_test_dir, toolchain, toolchain_dir, cma toolchain_dir = toolchain_dir, cmake_args = gap9_cmake_args, tiling = False, + gen_args = _PER_TEST_GEN_ARGS.get(test_name), ) run_and_assert_test(test_name, config, skipgen, skipsim) diff --git a/DeeployTest/test_siracusa_config.py b/DeeployTest/test_siracusa_config.py index 8fa105d9f4..01b7b7928f 100644 --- a/DeeployTest/test_siracusa_config.py +++ b/DeeployTest/test_siracusa_config.py @@ -45,6 +45,7 @@ "Kernels/FP32/ReduceSum", "Kernels/FP32/Reshape/SkipConnection", "Kernels/FP32/Transpose", + "Kernels/FP32/Adam/Regular", "Kernels/Integer/Hardswish/Regular", "Kernels/Integer/Softmax/Regular", "Kernels/Integer/Add/MultIO", diff --git a/DeeployTest/test_siracusa_tiled_config.py b/DeeployTest/test_siracusa_tiled_config.py index a687d9a489..aa97f90a6b 100644 --- a/DeeployTest/test_siracusa_tiled_config.py +++ b/DeeployTest/test_siracusa_tiled_config.py @@ -10,6 +10,7 @@ DEFAULT_SEARCH_STRATEGY = "random-max" L2_SINGLEBUFFER_KERNELS = { + "Kernels/FP32/Adam/Regular": [6200, 80000], "Kernels/FP32/ReLU": [2000], "Kernels/FP32/Softmax/Regular": [4000], "Kernels/FP32/Add/Large": [220000], @@ -58,6 +59,7 @@ } L2_DOUBLEBUFFER_KERNELS = { + "Kernels/FP32/Adam/Regular": [12400, 160000], "Kernels/FP32/ReLU": [20], "Kernels/FP32/Softmax/Regular": [8000], "Kernels/FP32/Conv/DW_2D_Bias": [10000], @@ -101,6 +103,14 @@ "Kernels/Integer/Hardswish/Regular_RQ": [800], } +L3_SINGLEBUFFER_KERNELS = { + "Kernels/FP32/Adam/Regular": [6200, 80000], +} + +L3_DOUBLEBUFFER_KERNELS = { + "Kernels/FP32/Adam/Regular": [12400, 160000], +} + L2_SINGLEBUFFER_MODELS = { "Models/CNN_Linear2": [45000, 30000, 15000], "Models/miniMobileNet": [60000, 12000, 6000, 3000],

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 literal 0 HcmV?d00001 diff --git a/DeeployTest/Tests/Kernels/FP32/Adam/Regular/network.onnx b/DeeployTest/Tests/Kernels/FP32/Adam/Regular/network.onnx new file mode 100644 index 0000000000000000000000000000000000000000..92ce791c17333cdd4f16b7e364a57719c27c09cd GIT binary patch literal 392 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