Skip to content
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

[microNPU] Add the infrastructure for lookup table and TANH #9547

Merged
merged 3 commits into from
Dec 1, 2021

Conversation

ekalda
Copy link
Contributor

@ekalda ekalda commented Nov 22, 2021

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.

@ekalda
Copy link
Contributor Author

ekalda commented Nov 22, 2021

Copy link
Contributor

@lhutton1 lhutton1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ekalda, mostly minor things

def create_op_with_lut(self, call):
"""Extract the parameters and attributes from the NPU operator and create
a new operator with LUT.
----------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing Parameters and I think we need spacing for these doc strings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

lut_activations = ["TANH", "LUT"]

if (
call.op.name == "contrib.ethosu.identity"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a check here to make sure call is an op?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my digging of the code, it looks like tvm.relay.expr.Call always has an op attribute, so the equality check shouldn't fail with an error (but correct me if I'm wrong there)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that while it will always have an op attribute, op may not be a tvm.ir.Op and could, for example, be a Function. See here:

* - It can be tvm::Op which corresponds to the primitive operators.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok yes, I added the op type check :)


@relay.transform.function_pass(opt_level=1, name="LutOptimizer")
class LUTsOptimizer(Pass):
"""Register LutOptimizer as a relay pass."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: LUTsOptimizer and the same for name=LUTsOptimizer above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Parameters
----------
func : tvm.relay.function.Function
The function to apply the layout optimization pass to.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The function to apply the layout optimization pass to.
The function to apply the optimization pass for multiple LUTs to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Returns
-------
mod : tvm.IRModule
New module with augmented layouts.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
New module with augmented layouts.
New module with optimized LUTs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -123,6 +124,80 @@ def __call__(self, *args, **kwargs):
pass


def round_away_zero(f):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reuse round_away_zero from util.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice, I didn't know it was there, thanks for pointing this out! Changed it to use the one from util.py

input_zp = int(dequantize_args[2].data.asnumpy())

lut_values = find_tanh_values(input_scale, input_zp, output_scale, output_zp)
lut = relay.const(lut_values, dtype="uint8")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, can LUT be any other dtype?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the values are calculated for an int8 activation and then cast into uint8 due to that can of worms dtype problem in the tir_to_cs_translator.py

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, glad to see a fix for that issue will improve something else :)

ifm_shape = (1, 55, 55, 3)

def create_tflite_graph():
tf.config.run_functions_eagerly(True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to enable eager execution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No we don't :D Removed it!

Comment on lines 66 to 67
new_args = [ethosu_op.args[n] for n in range(len(ethosu_op.args) - 1)]
new_args.append(lut)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
new_args = [ethosu_op.args[n] for n in range(len(ethosu_op.args) - 1)]
new_args.append(lut)
new_args = ethosu_op.args[:-1] + [lut]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 75 to 85
a new NPU operator.
Parameters
----------
call : tvm.relay.expr.Call
The current call node being visited.
Returns
-------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
a new NPU operator.
Parameters
----------
call : tvm.relay.expr.Call
The current call node being visited.
Returns
-------
a new NPU operator.
Parameters
----------
call : tvm.relay.expr.Call
The current call node being visited.
Returns
-------

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 114 to 120
"""Visit relay nodes in the given module.
Parameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Visit relay nodes in the given module.
Parameters
"""Visit relay nodes in the given module.
Parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@ekalda
Copy link
Contributor Author

ekalda commented Nov 26, 2021

Thanks @lhutton1 and @NicolaLancellotti for the reviews! :)

Copy link
Contributor

@NicolaLancellotti NicolaLancellotti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor

@lhutton1 lhutton1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.

Change-Id: Ibe49759fd02724af869826663ff0babd352e5894
Copy link
Contributor

@manupak manupak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

I was hoping we could merge #9597 before this as it get conflicted :) -- but it got conflicted anyway. Therefore getting this in. Lets prioritize getting a version of #9597 otherwise it would be perma-conflicted.
cc : @leandron @mbaret

@manupak manupak merged commit 9ada371 into apache:main Dec 1, 2021
@manupak
Copy link
Contributor

manupak commented Dec 1, 2021

Thanks all!

masahi pushed a commit to masahi/tvm that referenced this pull request Dec 1, 2021
)

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.
ylc pushed a commit to ylc/tvm that referenced this pull request Jan 7, 2022
)

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.
yangulei pushed a commit to yangulei/tvm that referenced this pull request Jan 11, 2022
)

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.
yangulei pushed a commit to yangulei/tvm that referenced this pull request Jan 12, 2022
)

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.
ylc pushed a commit to ylc/tvm that referenced this pull request Jan 13, 2022
)

Some activation functions like TANH and SIGMOID are implemented
by calculating the values based on the QNN parameters and
recording the values into a lookup table (LUT).

This patch adds the LUT functionality alongside with the TANH
activation function and the tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants