-
Notifications
You must be signed in to change notification settings - Fork 45
Add FP32 operators and tiling support for MicroLlama on Snitch #153
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
base: devel
Are you sure you want to change the base?
Changes from all commits
1a6308e
1bdf9c9
35d51ef
76a4678
c222810
497e9c1
bf5ddb7
7e3659d
28280fb
ac5d541
c90b35c
5669c28
cf4d9bd
c04bd6a
bdc550e
b53ff75
b355624
5306134
32d88c0
7092e35
b2199cb
7ad03a3
d76f6f1
1c62b68
32d4bfa
66c4b4f
be96413
89d382a
e55c7bc
13a4e64
55b6750
06010e4
85a68fd
182a2c3
03125c0
027ccab
064981a
9be8768
fdc0c82
7813684
4865516
fc8ea3f
b6b6eb5
4e8448b
7003801
e693be7
1633a71
0a66cf4
6b357cf
c7b9771
6e736f4
1062ec2
f7d62b0
ebf9009
ebe3e46
94aea9e
9fa6fd7
f87f98b
1924e5e
dfe3f0a
56e2d57
ba1b27e
c54195f
05b01ef
8338159
79c47fa
4ec3fb3
aae6667
e3c0ba8
205a3a5
ebac173
3eeb93a
802eecc
bf4490a
eea7af4
6d70bf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
diaconuccalin marked this conversation as resolved.
diaconuccalin marked this conversation as resolved.
|
|
diaconuccalin marked this conversation as resolved.
diaconuccalin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,3 +31,5 @@ ignore: | |
| - "**/toolchain/" | ||
| # Ignore all files in .git | ||
| - "**/.git/**" | ||
| # Ignore all files in .venv | ||
| - "**/.venv/" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,6 +72,10 @@ def parseNode(self, node: gs.Node) -> (bool): | |
| self.operatorRepresentation['n_levels'] = int(node.attrs['n_levels']) | ||
| self.operatorRepresentation['log2D'] = int(math.log2(node.attrs['D'])) | ||
|
|
||
| stash_type = node.attrs.get('stash_type', 1) | ||
| if stash_type != 1: | ||
| raise ValueError(f"iRMSNorm: only stash_type=1 (FP32) is supported, got {stash_type}") | ||
|
|
||
| return ret | ||
|
|
||
| def parseNodeCtxt(self, | ||
|
|
@@ -87,8 +91,15 @@ def parseNodeCtxt(self, | |
| for idx, outputNode in enumerate(node.outputs): | ||
| self.operatorRepresentation[outputs[idx]] = ctxt.lookup(outputNode.name).name | ||
|
|
||
| self.operatorRepresentation['size'] = np.prod(ctxt.lookup(node.inputs[0].name).shape) | ||
| self.operatorRepresentation['lastDimLength'] = ctxt.lookup(node.inputs[0].name).shape[-1] | ||
| input_shape = list(ctxt.lookup(node.inputs[0].name).shape) | ||
|
|
||
| axis = node.attrs.get('axis', -1) | ||
| if axis < 0: | ||
| axis = len(input_shape) + axis | ||
|
|
||
| self.operatorRepresentation['inputSize'] = int(np.prod(input_shape)) | ||
| self.operatorRepresentation['NormalizedAxesSize'] = int(np.prod(input_shape[axis:])) | ||
| self.operatorRepresentation['scale'] = node.inputs[1].values | ||
|
|
||
| return ctxt, True | ||
|
|
||
|
|
@@ -199,6 +210,32 @@ def parseNodeCtxt(self, | |
| self.operatorRepresentation['data_in_size'] = np.prod(data_in.shape) | ||
| self.operatorRepresentation['data_out_size'] = np.prod(data_out.shape) | ||
|
|
||
| # Transpose layout adaptation, derived purely from perm and the shapes. | ||
| # Kept here (in the parser) rather than in the per-platform templates: | ||
| # the multi-dim index strings and the outer-dim parallelization choice. | ||
| # The tiled Snitch/PULPOpen templates consume these; simple templates | ||
| # (CortexM/Generic/MemPool) just ignore the extra keys. | ||
| perm = self.operatorRepresentation['perm'] | ||
| in_shape = list(data_in.shape) | ||
| out_shape = list(data_out.shape) | ||
|
|
||
| self.operatorRepresentation['shapeStr'] = "".join(f"[dimLen_{idx + 1}]" for idx in range(len(perm) - 1)) | ||
| self.operatorRepresentation['outShapeStr'] = "".join( | ||
| f"[dimLen_{perm[idx + 1]}]" for idx in range(len(perm) - 1)) | ||
| self.operatorRepresentation['dimStr'] = "".join(f"[{dim}]" for dim in in_shape) | ||
| self.operatorRepresentation['accessStr'] = "".join(f"[i_{idx}]" for idx in range(len(perm))) | ||
| self.operatorRepresentation['outAccessStr'] = "".join(f"[i_{i}]" for i in perm) | ||
|
|
||
| # Parallelize over the outermost dim with at least one element per core | ||
| # (>= 8): each core then owns a contiguous slab, minimizing per-core | ||
| # loop-control overhead. Fall back to the largest dim so few cores idle. | ||
| parallelDims = [idx for idx, dim in enumerate(out_shape) if dim >= 8] | ||
| self.operatorRepresentation['parallelDim'] = parallelDims[0] if parallelDims else out_shape.index( | ||
| max(out_shape)) | ||
|
|
||
| for idx in range(len(perm)): | ||
| self.operatorRepresentation[f"dimLen_{idx}"] = in_shape[idx] | ||
|
|
||
| return ctxt, True | ||
|
|
||
|
|
||
|
|
@@ -488,23 +525,21 @@ def __init__(self): | |
| super().__init__() | ||
|
|
||
| def parseNode(self, node: gs.Node) -> bool: | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remember to run make format to fix these weird blank line changes
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
| ret = all([len(node.inputs) == 2, len(node.outputs) == 1]) | ||
|
|
||
| return ret | ||
|
|
||
| def parseNodeCtxt(self, | ||
| ctxt: NetworkContext, | ||
| node: gs.Node, | ||
| channels_first: bool = True) -> Tuple[NetworkContext, bool]: | ||
|
|
||
| data_in_1 = ctxt.lookup(node.inputs[0].name) | ||
| data_in_2 = ctxt.lookup(node.inputs[1].name) | ||
| data_out = ctxt.lookup(node.outputs[0].name) | ||
|
|
||
| self.operatorRepresentation['data_in_1'] = data_in_1.name | ||
| self.operatorRepresentation['data_in_2'] = data_in_2.name | ||
| self.operatorRepresentation['data_out'] = data_out.name | ||
| self.operatorRepresentation['size'] = np.prod(data_in_1.shape) | ||
| self.operatorRepresentation['size'] = np.prod(data_out.shape) | ||
|
|
||
| return ctxt, True | ||
|
|
||
|
|
@@ -2097,15 +2132,15 @@ def parseNodeCtxt(self, | |
| node: gs.Node, | ||
| channels_first: bool = True) -> Tuple[NetworkContext, bool]: | ||
|
|
||
| inputs = ["input1", "input2"] | ||
| outputs = ["output"] | ||
| inputs = ["A", "B"] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why changing that?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might have been a past nitpick comment of mine (it's been 4-5 months so I don't really remember 😅), but this is the naming used in the onnx standard. It would make sense for us to keep it like this, but we can also revert it, since it's slightly outside of the scope of this PR. |
||
| outputs = ["C"] | ||
| for idx, inputNode in enumerate(node.inputs): | ||
| if idx < len(inputs): | ||
| self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name | ||
| for idx, outputNode in enumerate(node.outputs): | ||
| self.operatorRepresentation[outputs[idx]] = ctxt.lookup(outputNode.name).name | ||
|
|
||
| self.operatorRepresentation['size'] = np.prod(ctxt.lookup(self.operatorRepresentation['input1']).shape) | ||
| self.operatorRepresentation['size'] = np.prod(ctxt.lookup(self.operatorRepresentation['A']).shape) | ||
|
|
||
| return ctxt, True | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,5 +6,5 @@ | |
|
|
||
| referenceTemplate = NodeTemplate(""" | ||
| // Division (Name: ${nodeName}, Op: ${nodeOp}) | ||
| SINGLE_CORE Div_fp${input1_type.referencedType.typeWidth}_fp${input2_type.referencedType.typeWidth}_fp${output_type.referencedType.typeWidth}(${input1}, ${input2}, ${output}, ${size}); | ||
| SINGLE_CORE Div_fp${A_type.referencedType.typeWidth}_fp${B_type.referencedType.typeWidth}_fp${C_type.referencedType.typeWidth}(${A}, ${B}, ${C}, ${size}); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change seems unnecessary.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember Calin advised me to do it to keep the input naming convention consistent.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, possibly an old nitpick comment of mine, this is the naming convention for Div in ONNX, can be reverted, no problem.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was trying to revert it from "A B C " to "input1 input2 output", however, the Deeploy/Targets/Generic/Templates/FloatMulTemplate.py use "A B C" in devel branch. At the same time the div and mul share the same tiler constraint in Deeploy/Deeploy/Targets/Generic/TileConstraints/MulTileConstraint.py, in the MulTileConstraint.py Deeploy devel branch using "A B C". In order to reuse MulTileConstraint and align with FloatMulTemplate.py. It better to use "A B C", but if you insist, I can change. |
||
| """) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,12 @@ def alignToContext(self, ctxt: NetworkContext, | |
| bufferIn.aliases.add(bufferOut.name) | ||
| bufferOut.aliases.add(bufferIn.name) | ||
|
|
||
| # Tiling still reads the legacy single-valued `_alias` attribute | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better practice to do the fix in the tiler (prevent it from relying on _alias and instead use the new alises parameter)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This workload is too heavy, it would touch the deeploy core:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to open a new pr to fix this
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's get a second opinion on this one from @Victor-Jung maybe
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is the intended behavior to instantiate a subclass to put this hack in place, just as it's done for the @lee2716 can you open an issue describing your fix to the tiler such that one can open a PR against it later?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done in #201 |
||
| # (TilerExtension / MemoryScheduler). Set it here so platforms that | ||
| # rely on Reshape pointer-passthrough during tiling don't each need | ||
| # to carry the same workaround in a subclass. | ||
| bufferOut._alias = bufferIn.name | ||
|
|
||
| return ctxt, operatorRepresentation, [] | ||
|
|
||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.