-
Notifications
You must be signed in to change notification settings - Fork 47
Add SoCDAML Part III: hands-on lab for adding a new int8 operator #194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
0ace569
Add SoCDAML Exercise and update README
Victor-Jung 6bdfb42
Add SoCDAML Part III: hands-on lab for adding a new int8 operator (iL…
4d73284
Move Part III lab to docs/tutorials/introduction.md
adb9ffb
Apply pre-commit fixes (SPDX headers, yapf/clang-format/shfmt)
c512971
[docs] Add instructions to build container from scratch
bf63deb
[fix] Forward --neureka-wmem and --enable-3x3 from the runner to the …
0986239
[fix] Make Part III deploy.sh robust to Platform.py import rewrapping
2bc7385
[fix] Use addTileSizeDivisibleConstraint for the Step 6a SIMD alignme…
709997c
[docs] Fix Part III flags, paths and imports, and document the scratc…
e9cc2ea
[docs] Fix dangling SoCDAML.md reference
97ed2fd
[docs] Add changelog entries for the SoCDAML tutorial fixes
b1322f8
[docs] Fix duplicated article in the Part III intro paragraph
d7bb6a2
[docs] Fix profiling sentence grammar in the --profileTiling section
30ca7b5
[docs] Correct the Singularity installation step count to six
d3a82f4
[docs] Add language identifiers to the Part III code fences
5bf74e4
[fix] Include the positive int8 boundary in the iLeakyReLU fixtures
01fd265
[docs] Match the skeleton README SIMD row to what the file leaves as …
1d56459
[fix] Make deploy.sh undo remove only its own test artifacts
66adef2
[fix] Keep ccache and pip caches on scratch through --cleanenv
b18a122
[docs] Compress the SoCDAML changelog entries
d26f76f
[docs] Drop unreferenced image copies already present under docs/_static
d6c0e8e
[fix] Reject iLeakyReLU attributes the SIMD kernel cannot honour
ec95fba
[docs] Add the missing PR-list and Added entries for the Part III lab
a898924
[fix] Use GELUChecker so iLeakyReLU output keeps its signedness
e5db9ac
[fix] Make the deploy.sh recovery command work from the script's own …
d2b367d
[fix] Store the iLeakyReLU fixtures as int8 under the ONNX tensor names
ce21954
[docs] Document the bind-source failure when the cache variables are …
3d228f3
[build] Ignore the fixtures students generate from the Part III skeleton
1b6a4b5
[fix] Partition iLeakyReLU SIMD work by vector so no element is dropped
3b14e3a
[fix] Stop forwarding --enable-3x3, removed from the generator in #188
845a33b
[fix] Apply the Part III core-library edits as a git patch
7530369
[fix] Drop the redundant --neureka-wmem forwarding fixed upstream in …
04f5ed9
[fix] Keep the copied files when the core patch cannot be reverted
4ee0555
[fix] Scope deploy.sh recovery advice to the patched files only
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # SoCDAML Part III - Student skeletons for `iLeakyReLU` | ||
|
|
||
| These files are your starting points for the Part III lab. Each one | ||
| contains the surrounding boilerplate; the conceptually interesting | ||
| parts are marked with `TODO(student)` comments and short hints. | ||
|
|
||
| | File | What's in it | What to do | | ||
| |------|--------------|------------| | ||
| | `generate.py` | Complete ONNX + golden-value generator | Run it (Step 1) | | ||
| | `iLeakyReLU.h` | Complete kernel header | Copy to `TargetLibraries/PULPOpen/inc/kernel/` (Step 3) | | ||
| | `iLeakyReLU.c` | Multi-core chunking provided; inner loop TODO | Fill the TODO, copy to `TargetLibraries/PULPOpen/src/` (Step 3) | | ||
| | `iLeakyReLU_simd.c` | SIMD chunking and the vector load provided; packed shift, max and store are TODO | Fill in Step 6b after the scalar works | | ||
| | `iLeakyReLUParser.py` | `parseNode` and `parseNodeCtxt` are TODO | Fill in, paste class into `Deeploy/Targets/Generic/Parsers.py` (Step 2) | | ||
| | `iLeakyReLUTemplate.py` | Mako template body is TODO | Fill in, copy to `Deeploy/Targets/PULPOpen/Templates/` (Step 4) | | ||
| | `iLeakyReLUTileConstraint.py` | Inherits `UnaryTileConstraint`; performance constraint TODO | Fill in (Step 5 + Step 6a), copy to `Deeploy/Targets/PULPOpen/TileConstraints/` | | ||
|
|
||
| The `docs/tutorials/introduction.md` ("Adding a New Operator") | ||
| walks through the six steps in order and includes collapsed solutions to | ||
| peek at when you're stuck. | ||
|
|
||
| If you really need the answer key, look in | ||
| `Deeploy/Tutorials/PartIII_solution/iLeakyReLU/`, but try the lab | ||
| first; you'll learn far more. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #!/usr/bin/env python3 | ||
| # ---------------------------------------------------------------------- | ||
| # File: generate.py (SoCDAML Part III - Step 1, provided complete) | ||
| # | ||
| # Builds the single-node ONNX graph + golden tensors that DeeployTest's | ||
| # harness will use to validate your iLeakyReLU implementation. | ||
| # | ||
| # Run from this directory: | ||
| # python generate.py | ||
| # | ||
| # Outputs: | ||
| # network.onnx, inputs.npz, outputs.npz | ||
| # | ||
| # Quantization-friendly LeakyReLU formula used here: | ||
| # out[i] = x if x >= 0 | ||
| # (mul*x) >> shift otherwise | ||
| # ---------------------------------------------------------------------- | ||
| # SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import numpy as np | ||
| import onnx | ||
| from onnx import TensorProto, helper | ||
|
|
||
| SHAPE = (1, 16, 64, 64) | ||
| MUL = 1 | ||
| SHIFT = 3 | ||
| SEED = 0xC0FFEE | ||
|
|
||
|
|
||
| def golden(x, mul, shift): | ||
| pos = x.astype(np.int32) | ||
| neg = (mul * pos) >> shift | ||
| out = np.where(pos >= 0, pos, neg) | ||
| return np.clip(out, -128, 127).astype(np.int8) | ||
|
|
||
|
|
||
| def build_onnx(): | ||
| in_value = helper.make_tensor_value_info('data_in', TensorProto.INT8, SHAPE) | ||
| out_value = helper.make_tensor_value_info('data_out', TensorProto.INT8, SHAPE) | ||
| node = helper.make_node('iLeakyReLU', ['data_in'], ['data_out'], name = 'iLeakyReLU_0', mul = MUL, shift = SHIFT) | ||
| graph = helper.make_graph([node], 'iLeakyReLU_single_node', [in_value], [out_value]) | ||
| model = helper.make_model(graph, producer_name = 'SoCDAML-PartIII') | ||
| model.opset_import[0].version = 13 | ||
| model.ir_version = 7 | ||
| return model | ||
|
|
||
|
|
||
| def main(): | ||
| rng = np.random.default_rng(SEED) | ||
| x = rng.integers(low = -128, high = 128, size = SHAPE, dtype = np.int8) | ||
| y = golden(x, MUL, SHIFT) | ||
| onnx.save(build_onnx(), 'network.onnx') | ||
| np.savez('inputs.npz', data_in = x) | ||
| np.savez('outputs.npz', data_out = y) | ||
| print(f"OK: network.onnx, inputs.npz, outputs.npz " | ||
| f"(shape={SHAPE}, mul={MUL}, shift={SHIFT})") | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* ===================================================================== | ||
| * Title: iLeakyReLU.c (SoCDAML Part III - Step 3 skeleton) | ||
| * | ||
| * Plain-C int8 LeakyReLU. The per-core chunking boilerplate is provided. | ||
| * Fill in the inner loop body marked `TODO(student)`. | ||
| * | ||
| * Goal: out[i] = (in[i] >= 0) ? in[i] : ((mul * in[i]) >> shift) | ||
| * | ||
| * Hints: | ||
| * - Cast in[i] to int32_t before the multiply to avoid 8-bit overflow. | ||
| * - Cast the final result back to int8_t before storing. | ||
| * | ||
| * Drop into: TargetLibraries/PULPOpen/src/iLeakyReLU.c | ||
| * ===================================================================== */ | ||
| /* SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include "DeeployPULPMath.h" | ||
| #include "pmsis.h" | ||
|
|
||
| void PULPiLeakyReLU_i8_i8(int8_t *pIn, int8_t *pOut, uint32_t size, int32_t mul, | ||
| int32_t shift) { | ||
| uint32_t cid = pi_core_id(); | ||
| uint32_t nC = NUM_CORES; | ||
| uint32_t per = (size + nC - 1) / nC; | ||
| uint32_t start = cid * per; | ||
| uint32_t end = (start + per > size) ? size : (start + per); | ||
|
|
||
| for (uint32_t i = start; i < end; i++) { | ||
| // TODO(student): compute pOut[i] from pIn[i], mul, shift. | ||
| // Replace the following line: | ||
| pOut[i] = 0; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /* ===================================================================== | ||
| * Title: iLeakyReLU.h (SoCDAML Part III - Step 3, provided) | ||
| * | ||
| * Header for the iLeakyReLU PULP kernel. | ||
| * Drop into: TargetLibraries/PULPOpen/inc/kernel/iLeakyReLU.h | ||
| * and add `#include "kernel/iLeakyReLU.h"` to DeeployPULPMath.h. | ||
| * ===================================================================== */ | ||
| /* SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #ifndef __DEEPLOY_KERNEL_ILEAKYRELU_H_ | ||
| #define __DEEPLOY_KERNEL_ILEAKYRELU_H_ | ||
|
|
||
| #include "DeeployPULPMath.h" | ||
|
|
||
| void PULPiLeakyReLU_i8_i8(int8_t *pIn, int8_t *pOut, uint32_t size, int32_t mul, | ||
| int32_t shift); | ||
|
|
||
| #endif // __DEEPLOY_KERNEL_ILEAKYRELU_H_ |
35 changes: 35 additions & 0 deletions
35
Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUParser.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # ---------------------------------------------------------------------- | ||
| # File: iLeakyReLUParser.py (SoCDAML Part III - Step 2 skeleton) | ||
| # | ||
| # Paste this class into: | ||
| # Deeploy/Targets/Generic/Parsers.py | ||
| # | ||
| # Imports already present in that file (math, numpy as np, | ||
| # onnx_graphsurgeon as gs, NodeParser, NetworkContext). | ||
| # ---------------------------------------------------------------------- | ||
| # SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
|
|
||
| class iLeakyReLUParser(NodeParser): | ||
|
|
||
| def __init__(self): | ||
| super().__init__() | ||
|
|
||
| def parseNode(self, node: gs.Node) -> bool: | ||
| # TODO(student): return False if the node doesn't have exactly | ||
| # one input, exactly one output, and both 'mul' and 'shift' | ||
| # attributes. On success, store them into | ||
| # self.operatorRepresentation as ints and return True. | ||
| return False | ||
|
|
||
| def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True): | ||
| # TODO(student): look up the input and output tensors from ctxt | ||
| # using node.inputs[0].name / node.outputs[0].name, and populate | ||
| # self.operatorRepresentation with: | ||
| # 'data_in' -> input tensor name | ||
| # 'data_out' -> output tensor name | ||
| # 'size' -> int(np.prod(input_shape)) | ||
| # Return (ctxt, True). | ||
| return ctxt, False |
30 changes: 30 additions & 0 deletions
30
Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUTemplate.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # ---------------------------------------------------------------------- | ||
| # File: iLeakyReLUTemplate.py (SoCDAML Part III - Step 4 skeleton) | ||
| # | ||
| # Drop this file into: | ||
| # Deeploy/Targets/PULPOpen/Templates/iLeakyReLUTemplate.py | ||
| # ---------------------------------------------------------------------- | ||
| # SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| from Deeploy.DeeployTypes import NodeTemplate | ||
|
|
||
|
|
||
| class _iLeakyReLUTemplate(NodeTemplate): | ||
|
|
||
| def __init__(self, templateStr): | ||
| super().__init__(templateStr) | ||
|
|
||
|
|
||
| # TODO(student): fill in the Mako template body so it emits a single | ||
| # call to your C kernel: | ||
| # | ||
| # PULPiLeakyReLU_i8_i8(<data_in>, <data_out>, <size>, <mul>, <shift>); | ||
| # | ||
| # All five `${...}` substitutions correspond to keys you populated in | ||
| # the parser (or that Deeploy fills automatically for tensor names). | ||
| referenceTemplate = _iLeakyReLUTemplate(""" | ||
| // iLeakyReLU (Name: ${nodeName}, Op: ${nodeOp}) | ||
| // TODO(student): emit the kernel call here. | ||
| """) |
35 changes: 35 additions & 0 deletions
35
Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUTileConstraint.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # ---------------------------------------------------------------------- | ||
| # File: iLeakyReLUTileConstraint.py (SoCDAML Part III - Step 5+6a skeleton) | ||
| # | ||
| # Drop this file into: | ||
| # Deeploy/Targets/PULPOpen/TileConstraints/iLeakyReLUTileConstraint.py | ||
| # | ||
| # UnaryTileConstraint already implements the geometry and serializer | ||
| # you need for an elementwise op. You only have to subclass it. In | ||
| # Step 6a you'll add a performance constraint on top. | ||
| # ---------------------------------------------------------------------- | ||
| # SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| from typing import Dict | ||
|
|
||
| from Deeploy.DeeployTypes import NetworkContext | ||
| from Deeploy.Targets.Generic.TileConstraints.UnaryTileConstraint import UnaryTileConstraint | ||
| from Deeploy.TilingExtension.TilerModel import TilerModel | ||
|
|
||
|
|
||
| class iLeakyReLUTileConstraint(UnaryTileConstraint): | ||
|
|
||
| @staticmethod | ||
| def addGeometricalConstraint(tilerModel: TilerModel, parseDict: Dict, ctxt: NetworkContext) -> TilerModel: | ||
| tilerModel = UnaryTileConstraint.addGeometricalConstraint(tilerModel, parseDict, ctxt) | ||
|
|
||
| # TODO(student, Step 6a): add a performance constraint so the | ||
| # innermost tile dim is a multiple of 16. Helpful API: | ||
| # tilerModel.addTileSizeDivisibleConstraint(parseDict, name, | ||
| # tensorDimVar, modulo) | ||
| # See: Deeploy/Targets/PULPOpen/TileConstraints/GEMMTileConstraint.py | ||
| # for a usage example. | ||
|
|
||
| return tilerModel |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* ===================================================================== | ||
| * Title: iLeakyReLU_simd.c (SoCDAML Part III - Step 6b skeleton) | ||
| * | ||
| * SIMD version of iLeakyReLU using XPULP packed 4x8b operations. | ||
| * The per-core chunking is provided. Fill in the inner SIMD body. | ||
| * | ||
| * Key identity (worth deriving on paper before reading hints below): | ||
| * LeakyReLU(x) = (x >= 0) ? x : (x >> shift) | ||
| * = max(x, x >> shift) | ||
| * because arithmetic right shift makes a negative value LESS negative | ||
| * (or zero) and doesn't change the sign of a non-negative value. | ||
| * | ||
| * Strategy hint (one path, two intrinsic-level operations per 4 lanes): | ||
| * - load v4s lane: v4s x = vIn[i]; | ||
| * - per-lane signed shift: v4s s = x >> shift; (GCC vector ext) | ||
| * - signed packed max: __builtin_pulp_max4(x, s); | ||
| * | ||
| * For the lab we assume `mul == 1` (the generator picks mul=1, shift=3). | ||
| * | ||
| * Drop into: TargetLibraries/PULPOpen/src/iLeakyReLU.c (overwrite scalar) | ||
| * ===================================================================== */ | ||
| /* SPDX-FileCopyrightText: 2026 ETH Zurich and University of Bologna | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include "DeeployPULPMath.h" | ||
| #include "pmsis.h" | ||
|
|
||
| void PULPiLeakyReLU_i8_i8(int8_t *pIn, int8_t *pOut, uint32_t size, int32_t mul, | ||
| int32_t shift) { | ||
| (void)mul; // SIMD path assumes mul == 1 | ||
|
|
||
| uint32_t cid = pi_core_id(); | ||
| uint32_t nC = NUM_CORES; | ||
|
|
||
| // Whole 4-element vectors are split across the cores by vector index, so | ||
| // that no element is lost when size / nC is small or size is not a | ||
| // multiple of 4 * nC. | ||
| uint32_t nVec = size >> 2; | ||
| uint32_t perVec = (nVec + nC - 1) / nC; | ||
| uint32_t vStart = cid * perVec; | ||
| uint32_t vEnd = (vStart + perVec > nVec) ? nVec : (vStart + perVec); | ||
|
|
||
| v4s *vIn = (v4s *)pIn; | ||
| v4s *vOut = (v4s *)pOut; | ||
|
|
||
| for (uint32_t i = vStart; i < vEnd; i++) { | ||
| v4s x = vIn[i]; | ||
| // TODO(student): one line to compute `s` from `x` and `shift`, | ||
| // one line to blend `x` and `s` with the packed | ||
| // signed max intrinsic and store it. | ||
| vOut[i] = x; // <- placeholder, replace | ||
| } | ||
|
|
||
| // The trailing size % 4 elements never fill a vector; one core handles | ||
| // them. Disjoint from every vector chunk above, so no sync is needed. | ||
| if (cid == 0) { | ||
| for (uint32_t i = nVec << 2; i < size; i++) { | ||
| int32_t xs = (int32_t)pIn[i]; | ||
| pOut[i] = (int8_t)((xs >= 0) ? xs : (xs >> shift)); | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.