-
Notifications
You must be signed in to change notification settings - Fork 86
Added pattern matching and new optimization passes #53
Added pattern matching and new optimization passes #53
Conversation
a16c303
to
b4ca6f7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How effective this PR when we add new operator ?
Adding a new operator require change much less code. |
@antonionevado How to test this? |
dlk/python/dlk/core/operators.py
Outdated
@@ -56,6 +55,8 @@ def __init__(self, | |||
self._check_consistency() | |||
self._rank = len(shape) | |||
self._available_buffer = '' | |||
self._visited = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, will delete.
dlk/python/dlk/core/operators.py
Outdated
@@ -56,6 +55,8 @@ def __init__(self, | |||
self._check_consistency() | |||
self._rank = len(shape) | |||
self._available_buffer = '' | |||
self._visited = False | |||
self._prop_details = Dict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, Does it need ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not, old code I forgot to delete. I will delete it. Thank you!
dlk/tests/test_optimizer.py
Outdated
from core.operators import Add, AveragePool, BatchNormalization, Constant, Conv, Identity, Input, \ | ||
MaxPool, Operator, Output, Transpose, QTZ_binary_mean_scaling, QTZ_linear_mid_tread_half, Reshape, Softmax | ||
|
||
import numpy as np | ||
from typing import Any, Dict, List, Tuple | ||
from typing import Tuple | ||
|
||
|
||
class TestOptimizer(unittest.TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't understand what is verified in this test. Is it not unit test ?
I think need to add unit tests for each passes, and some public graph matcher functions and classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonionevado @nlpng How is this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better, The passes of changing node property like pass_compute_thresholds()
, pass_propagate_quantization_details_into_conv()
have document of which property change to, I think.
BTW, what is different of run()
and run_forward()
in Operator class ?
""" | ||
def __init__(self, op=str(), inputs=list()): | ||
self.op = op | ||
self.inputs = inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What case self.inputs
is used ? It seems not be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is necessary to support more complex patterns. For example, imagine you want to write a pass that need to process sub-graphs where you have a quantizer with an input which is a batch normalization. And that batch normalization node has an input which is a convolution node. Then you can specify the pattern:
p = Pattern('QTZ_linear_mid_tread_half',
[
Pattern('BatchNormalization',
[
Pattern('Conv'),
Pattern('*'),
Pattern('*'),
Pattern('*'),
Pattern('*')
]),
Pattern('*'),
Pattern('*'),
])
Note that the pattern *
means that you don't care about that node, could be any type of operator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which pass is used the pattern?
I think it is no need to implement this, If the pattern is not used.
Or, should implement unit test and write document at least for future work.
|
||
Returns | ||
------- | ||
result : [NodeMatch] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this is a list of NodeMatch
object, not list of Operator
?
If we can use list of Operator
, Maybe we don't need NodeMatch
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is necessary to have this class because the return type is a list of sub-graphs. The NodeMatch class is a graph type (resursive) data structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NodeMatch
is not subclass of Graph
, but is it sub graph? it looks strange implementation.
Operator
objects have inputs and outputs, that means you can retrieve path and nodes, it is already graph type structure.
why it is necessary?
dlk/python/dlk/core/operators.py
Outdated
mean = np.float64(self._input_ops['mean'].data) | ||
var = np.float64(self._input_ops['var'].data) | ||
|
||
kwargs['nega_idx'] = [v for v in range(len(scale)) if scale[v] < 0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nega_idx
is not relate invert function of batch norm, it is related only for threshold skip. Why the nega_idx
calculation is not move into pass of threshold skipping?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it was more straightforward to retrieve the values from the batch norm rather than the threshold skipping pass, but I agree this will go to the optimization pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the nega_idx
is moved inside the optimization pass with a7f73bc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the line remain ?
dlk/python/dlk/core/optimizer.py
Outdated
p = Pattern('*') | ||
matches = find_pattern(graph, p) | ||
|
||
def find_input(node, otype): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of the find_input
function is set dtype
.
The find_input
function name is confuse for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, maybe rename it to dtype_changer
or output_type_changer
dlk/python/dlk/core/optimizer.py
Outdated
|
||
if p[-1].op_type != 'Conv': | ||
continue | ||
quantizer_conv_output_node = p[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is quantizer_conv_output_node
activation quantization node ? confuse...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @nlpng already changed the name. Yes, sorry, it is a bad name.
5bdce90
to
46207f1
Compare
""" | ||
def __init__(self, op=str(), inputs=list()): | ||
self.op = op | ||
self.inputs = inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which pass is used the pattern?
I think it is no need to implement this, If the pattern is not used.
Or, should implement unit test and write document at least for future work.
|
||
Returns | ||
------- | ||
result : [NodeMatch] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NodeMatch
is not subclass of Graph
, but is it sub graph? it looks strange implementation.
Operator
objects have inputs and outputs, that means you can retrieve path and nodes, it is already graph type structure.
why it is necessary?
dlk/python/dlk/core/operators.py
Outdated
mean = np.float64(self._input_ops['mean'].data) | ||
var = np.float64(self._input_ops['var'].data) | ||
|
||
kwargs['nega_idx'] = [v for v in range(len(scale)) if scale[v] < 0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the line remain ?
n = 2 ** nbit - 1 | ||
ch = conv_node.channel | ||
# assume that the threshold values will be a 13-bit signed integer | ||
max_th_value = 2 ** 12 - 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we can change, why 12 is not variable?
dlk/python/dlk/core/optimizer.py
Outdated
# get nodes to be removed after being disconnected | ||
get_nodes_in_branch(m.node, None, to_be_removed) | ||
|
||
new_constant.add_outputs({'output': m.node.output_ops.values()}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why these several lines are in here? looks general manupulation of graph and op.
How is to implement like replace_op()
in Graph
class and use graph.replace_op(m.node, new_constant)
?
dlk/tests/test_optimizer.py
Outdated
from core.operators import Add, AveragePool, BatchNormalization, Constant, Conv, Identity, Input, \ | ||
MaxPool, Operator, Output, Transpose, QTZ_binary_mean_scaling, QTZ_linear_mid_tread_half, Reshape, Softmax | ||
|
||
import numpy as np | ||
from typing import Any, Dict, List, Tuple | ||
from typing import Tuple | ||
|
||
|
||
class TestOptimizer(unittest.TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonionevado @nlpng How is this?
continue | ||
|
||
quantizer_conv_weights = conv_node.quantizer | ||
quantizer_conv_weights.run_forward_no_scaling_factor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonionevado @nlpng How is this ?
f9f099f
to
8dd88be
Compare
@antonionevado @nlpng Thanks, I will review this PR next week 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonionevado @nlpng
Thanks, so so nice refactoring.
I wrote some nite things. Plz see it.
continue | ||
|
||
quantizer_conv_weights = conv_node.quantizer | ||
quantizer_conv_weights.run_forward_no_scaling_factor() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think run_forward_no_scaling_factor()
should be in scaling_factor
getter.
But it's not need to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@antonionevado @nlpng
Thanks a lot 😄 😄 😄
we can get very simple and easy to understand code, and improve graph optimize speed 🥇
Added pattern matching and new optimization passes
This PR simplify the current optimization mechanism.
The idea is to only have a collection of simple passes that perform some actions over every sub-graph that match some given pattern.
The benefits of this PR are: