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

Support for quantized SeparableConv1D/2D #861

Merged
merged 3 commits into from Oct 6, 2023

Conversation

vloncar
Copy link
Contributor

@vloncar vloncar commented Sep 1, 2023

Description

This PR adds support for parsing QSeparableConv1D/2D and exxtends the existing implementation to allow specifying the intermediate result of the depthwise step. Otherwise it is tricky to get bit accurate matching. This is mostly motivated by issues observed in Lindsey's model. I've added the tests for 1D and 2D. Supersedes #849.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

A "bug fix" in a sense that it fixes the issues observed in conversion of SeparableConv1D (whether Q or not). A "new feature" as it adds support for separable layers from QKeras. "Breaking change" in a sense that the HLS function call is changed to include the type of the intermediate result of depthwise step (implemented in both Vivado and Vitis for io_stream, no other implementations exist ATM).

Tests

There are two tests appended to 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.

@vloncar vloncar mentioned this pull request Sep 1, 2023
12 tasks
@vloncar vloncar changed the title Support for quantized SeparavleConv1D/2D Support for quantized SeparableConv1D/2D Sep 5, 2023
@vloncar vloncar added the please test Trigger testing by creating local PR branch label Sep 5, 2023
@lgray
Copy link

lgray commented Sep 23, 2023

putting this here from fastml slack:
The following setup doesn't close, unless I have at least one integer bit in the depthwise and pointwise quantizers.

x_in = Input((13,21,20))
x = QSeparableConv2D(
    5,3,
    depthwise_quantizer=quantized_bits(8, 0, 1, alpha=1),
    pointwise_quantizer=quantized_bits(8, 0, 1, alpha=1),
    bias_quantizer=quantized_bits(8, 0, alpha=1),
)(x_in)
model = Model(inputs=x_in, outputs=x)

config = hls4ml.utils.config_from_keras_model(model, granularity='name', default_precision='fixed<65,33>')
config['LayerName'][list(config["LayerName"].keys())[0]]['Precision']['result'] = 'fixed<8,1>'

print(config)

hls_model = hls4ml.converters.convert_from_keras_model(
    model, hls_config=config, output_dir='minimalrepro_hls4ml/hls4ml_prj', part='xcu250-figd2104-2L-e', io_type="io_stream",
)
hls_model.compile()

data = quantized_bits(8, 0, alpha=1)(np.random.rand(5000,13,21,20)).numpy()

qkeras_out = model.predict(data)
hls_out = hls_model.predict(data)

plt.figure()
plt.scatter(hls_out.flatten(), qkeras_out.flatten(), s=0.2)
min_x = min(np.amin(hls_out), np.amin(qkeras_out))
max_x = max(np.amax(hls_out), np.amax(qkeras_out))
plt.plot([min_x, max_x], [min_x, max_x], c='gray')
plt.xlabel('hls4ml')
plt.ylabel('QKeras');

image

With quantized_bits(8,1,1) for depthwise/pointwise it closes perfectly. (it would also be nice to know what the exact number of bits needed for the accumulator is, if there's a ~reasonable formula!)

@lgray
Copy link

lgray commented Sep 23, 2023

x_in = Input((13,21,20))
x = QSeparableConv2D(
    5,3,
    depthwise_quantizer=quantized_bits(8, 0, alpha=1),
    pointwise_quantizer=quantized_bits(8, 0, alpha=1),
    bias_quantizer=quantized_bits(8, 0, alpha=1),
)(x_in)
model = Model(inputs=x_in, outputs=x)

config = hls4ml.utils.config_from_keras_model(model, granularity='name', default_precision='fixed<65,33>')
config['LayerName'][list(config["LayerName"].keys())[0]]['Precision']['result'] = 'fixed<8,1>'

print(config)

hls_model = hls4ml.converters.convert_from_keras_model(
    model, hls_config=config, output_dir='minimalrepro_hls4ml/hls4ml_prj', part='xcu250-figd2104-2L-e', io_type="io_stream",
)
hls_model.compile()

data = quantized_bits(8, 0, alpha=1)(np.random.rand(5000,13,21,20)).numpy()

qkeras_out = model.predict(data)
hls_out = hls_model.predict(data)

plt.figure()
plt.scatter(hls_out.flatten(), qkeras_out.flatten(), s=0.2)
min_x = min(np.amin(hls_out), np.amin(qkeras_out))
max_x = max(np.amax(hls_out), np.amax(qkeras_out))
plt.plot([min_x, max_x], [min_x, max_x], c='gray')
plt.xlabel('hls4ml')
plt.ylabel('QKeras');

also fails to close.
image

@jmitrevs jmitrevs merged commit cd8329f into fastmachinelearning:main Oct 6, 2023
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
please test Trigger testing by creating local PR branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants