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

[DRAFT][compiler] Introduce FuseGRUPass #13602

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

BalyshevArtem
Copy link
Contributor

This pr introduces FuseGRUPass for fusing gru pattern into single CircleGRU op.

for issues: #12263 and for #13365

ONE-DCO-1.0-Signed-off-by: Artem Balyshev [email protected]

This pr introduces FuseGRUPass for fusing gru pattern into single CircleGRU op.

ONE-DCO-1.0-Signed-off-by: Artem Balyshev <[email protected]>
@chunseoklee
Copy link
Contributor

chunseoklee commented Aug 7, 2024

GRU_fusegru.zip

  import tensorflow as tf
  from tensorflow import keras
  from tensorflow.keras import regularizers
  import numpy as np

  normalization_layer = tf.keras.layers.Normalization()
  adapt_data = np.array([[0., 7., 4. , 0.5],
                         [2., 9., 6. , -0.5],
                         [0., 7., 4. , -0.5],
                         [2., 9., 6. , 0.5]], dtype='float32')
  #normalization_layer.adapt(adapt_data)
  classes = 4
  activation = 'tanh'
  model = tf.keras.models.Sequential([
      tf.keras.Input(shape=(10,4)),
      normalization_layer,
      tf.keras.layers.GRU(units=20, activation=activation),
      tf.keras.layers.Dense(classes, activation='softmax')
  ])

  model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001))

  model.summary()

  run_model = tf.function(lambda x: model(x))

  # This is important, let's fix the input size.
  BATCH_SIZE = 1
  X = 10
  Y = 4
  concrete_func = run_model.get_concrete_function(
      tf.TensorSpec([BATCH_SIZE, X,Y], model.inputs[0].dtype))

  # model directory.
  MODEL_DIR = "keras_model"
  model.save(MODEL_DIR, save_format="tf", signatures=concrete_func)

  converter = tf.lite.TFLiteConverter.from_saved_model(MODEL_DIR)
  converter.experimental_new_converter = True
  converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS,
                                         ]
  #converter.optimizations = [tf.lite.Optimize.DEFAULT]
  converted_model = converter.convert()
  save_to = "GRU.tflite"
  if save_to is not None:
      with open(save_to, 'wb') as tf_lite_file:
          tf_lite_file.write(converted_model)

@BalyshevArtem After applying this pass to gru model, while_cond / while_body subgraph are still alive in resulting graph.

@BalyshevArtem
Copy link
Contributor Author

@BalyshevArtem After applying this pass to gru model, while_cond / while_body subgraph are still alive in resulting graph.

Hmmm
For me it is worked (I used your python script to obtain model and then convert it into circle and then made fusing)

Screenshot from 2024-08-07 11-56-53

@BalyshevArtem
Copy link
Contributor Author

BalyshevArtem commented Aug 7, 2024

@chunseoklee, I checked your models from GRU_fusegru.zip.
I did not immediately understand what you mean, but now I understand, yes, this pass does not remove additional subgraphs, a new pass is needed for this task (check #12319 (comment)), only fusing takes place here (which works as you can see in above screen).

@BalyshevArtem
Copy link
Contributor Author

@chunseoklee, I have added the part that is responsible for removing dead graphs, please check :)

@BalyshevArtem BalyshevArtem force-pushed the gru_circle2circle_draft_support branch from a0d6933 to 5d77de3 Compare August 7, 2024 11:57
Comment on lines 101 to 102
if (m->size() == 0)
throw std::invalid_argument("No any graphs");
Copy link
Contributor

Choose a reason for hiding this comment

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

this is logically invalid case but we don't need to throw to stop the program.
just return false would be OK.

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

circle_gru->input(_p->_ifm);
circle_gru->hidden_hidden(weight_hh_cloned);
circle_gru->hidden_input(weight_ih_cloned);
circle_gru->hidden_hidden_bias(bias_hh_cloned);
Copy link
Contributor

@chunseoklee chunseoklee Aug 8, 2024

Choose a reason for hiding this comment

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

Those two bias tensor are not well generated in the fused GRU.

-> since original model's FC does not have bias.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

-> since original model's FC does not have bias.

Yes, that is the reason, they are empty is FC doesn't have bias

This pr introduces EliminateDeadSubgraphPass for removing dead subgraph.

ONE-DCO-1.0-Signed-off-by: Artem Balyshev <[email protected]>
@seanshpark
Copy link
Contributor

seanshpark commented Aug 12, 2024

To check pass(es) is(are) working correctly,

  • add one more more tflite recipe(s) with decomposed GRU
  • add to `compiler/circle2circle-dredd-recipe-test/test.lst
  • add to compiler/luci-pass-value-py-test/test.lst
  • update necessary modules

Artem Balyshev added 3 commits August 12, 2024 14:06
This pr adds recipe for decomposed GRU.

ONE-DCO-1.0-Signed-off-by: Artem Balyshev <[email protected]>
This commit adds fuse_gru test to circle2circle-dredd-recipe-test.

ONE-DCO-1.0-Signed-off-by: Artem Balyshev <[email protected]>
@BalyshevArtem
Copy link
Contributor Author

To check pass(es) is(are) working correctly,

* add one more more tflite recipe(s) with decomposed GRU

* add to `compiler/circle2circle-dredd-recipe-test/test.lst

* add to `compiler/luci-pass-value-py-test/test.lst`

* update necessary modules

I added tflite decomposed GRU recipe and circle2circle-dredd-recipe-test.
For luci-pass-value-py-test we need support this op in the luci-interpreter, right? Can we postpone the supporting of this test for later, after completing the main work on supporting this kernel in onert-micro and its training?

@seanshpark
Copy link
Contributor

For luci-pass-value-py-test we need support this op in the luci-interpreter, right?

Yes.

Can we postpone the supporting of this test for later, after completing the main work on supporting this kernel in onert-micro and its training?

How can you be certain without value check that the conversion pass is working correctly?
I think it's up to you for this. Anyway if you don't add the test, no one will.

@chunseoklee , I'd like to hear your opinion.

@BalyshevArtem
Copy link
Contributor Author

How can you be certain without value check that the conversion pass is working correctly?

I checked manually the result for onert-micro. After finishing with onert-micro supporting we will ad it into luci-interpreter :)

@chunseoklee
Copy link
Contributor

@chunseoklee , I'd like to hear your opinion.

I checked manually the result for onert-micro. After finishing with onert-micro supporting we will ad it into luci-interpreter :)

AFAIU, GRU kernel will be added into luci-interpreter after a while. Am I right ?

@seanshpark
Copy link
Contributor

we will ad it into luci-interpreter :)

OK, adding a issue for this task will do for now.

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.

3 participants