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

Add QDepthwiseConv2D, DepthwiseConv2D, DepthwiseConv1D support #834

Merged
merged 7 commits into from
Aug 28, 2023

Conversation

jmitrevs
Copy link
Contributor

@jmitrevs jmitrevs commented Jul 17, 2023

Description

There was a request to add support for QDepthwiseConv2D for QKeras. Previously we had Keras support for DepthwiseConv1D and DepthwiseConv2D but only as part of separable convolutions. This PR adds support for standalone DepthwiseConv1D and DepthwiseConv2D, and also QDepthwiseConv2D. Currently only depth_multiplier=1 is supported.

Note that QKeras doesn't support QDepthwiseConv1D.

Adding this found an issue in that arguments to activations passed as parameters to, e.g. QDense, such as activation='quantized_relu(3, 0)', were ignored. This had the same effect as activation='quantized_relu()'.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change which adds functionality)

Tests

Tests added to both test_keras_api.py and test_qkeras.py

Checklist

  • I have read the guidelines for contributing.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation.
  • My changes generate no new warnings.
  • I have installed and run pre-commit on the files I edited or added.
  • I have added tests that prove my fix is effective or that my feature works.

@jmitrevs jmitrevs added this to the v0.8.0 milestone Jul 17, 2023
@jmitrevs jmitrevs added bug enhancement please test Trigger testing by creating local PR branch labels Jul 17, 2023
@jmitrevs
Copy link
Contributor Author

I should also mention that this is only for 'io_stream` and only for Vivado and Vitis. There is not Quartus support.

@jmitrevs jmitrevs added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels Jul 17, 2023
Copy link
Contributor

@bo3z bo3z left a comment

Choose a reason for hiding this comment

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

Looks good to me - for some reason the PyTests weren't triggered, so probably need to be triggered manually.

As a separate PR it could be worth including a Resource implementation of depth-wise multiplications and parameterise the new tests for both strategies.

@@ -57,6 +57,21 @@ void depthwise_conv_1d_buffer_cl(hls::stream<data_T> &data, hls::stream<res_T> &
}
}

template <class data_T, class res_T, typename CONFIG_T>
Copy link
Contributor

Choose a reason for hiding this comment

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

For the sake of code brevity - this function can be directly called, instead of the switch statement on lines 112 - 122

Copy link
Contributor Author

@jmitrevs jmitrevs Jul 19, 2023

Choose a reason for hiding this comment

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

You are right. The reason is of course historic, since the function on 112 -122 existed before. But I think I'll make the suggested change.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should check if using it this way it get inlined or not, otherwise it costs a cycle.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Anyway, I pushed the change. I expect that it would cause no difference in the produced code.

@@ -75,6 +75,22 @@ void depthwise_conv_2d_buffer_cl(
}
}

template <class data_T, class res_T, typename CONFIG_T>
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment for using this function below, like in the 1D case.

@jmitrevs
Copy link
Contributor Author

I think we should also support depth_multiplier!=1. Or is that not used often?

@jmitrevs jmitrevs added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels Jul 19, 2023
@jmitrevs jmitrevs added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels Aug 27, 2023
@jmitrevs
Copy link
Contributor Author

@bo3z, are there any other things needed for this PR?

@bo3z
Copy link
Contributor

bo3z commented Aug 28, 2023

@bo3z, are there any other things needed for this PR?

Looks good to me. Maybe worth opening an issue to keep track of the TODOs from this PR (resource strategy and multiplier != 1).

model.add(DepthwiseConv2D(kernel_size=(3, 3), input_shape=(32, 32, 3)))
model.compile()

config = hls4ml.utils.config_from_keras_model(model, granularity='name', default_precision='fixed<32,12>')
Copy link
Contributor

Choose a reason for hiding this comment

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

If the input is clipped to exactly match <16,6>, why do we need to increase the precision this way? Should only accum be increased?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not clipped for the keras input, just the hls4ml input. The input is actually all in the [0,1) range. I didn't try to optimize the precision in the model and just sought to make it irrelevant.

kernel_size=(3, 3),
input_shape=(32, 32, 3),
depthwise_quantizer='quantized_bits(6, 0, alpha=1)',
depthwise_initializer='ones',
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this test cheating a bit? All the weights will be 1s and the biases 0s, no point in using quantizers. It doesn't really test the proper handling of quantizers and the accuracy of the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a leftover from me playing around with the initializer. Let me find better ones. For depthwise, the default is probably good ("he_normal"), so I'll move to that. The default for bias is 0. Let me see if I should change it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably worth changing the bias initialiser - just to be sure the bias is not ignored in the C++ implementation.

Choose a reason for hiding this comment

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

Hi @jmitrevs .
Did you tested with large kernel size?
For example: model.add(DepthwiseConv2D(kernel_size=(16,16), input_shape=(32, 32, 24))).

I'm facing some errors regarding parameters that are bigger than the int256 representation in the parameters.h file.

@jmitrevs jmitrevs added please test Trigger testing by creating local PR branch and removed please test Trigger testing by creating local PR branch labels Aug 28, 2023
@vloncar vloncar merged commit 4b4b5a0 into fastmachinelearning:main Aug 28, 2023
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug enhancement please test Trigger testing by creating local PR branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants