Speed up Conv1D/Conv2D with large dilation_rate (closes #132) - #458
Merged
Conversation
Previously, Conv1D/Conv2D with dilation_rate > 1 inflated the filter with zeros at construction time (dilate_filter -> dilate_tensor). For example, a 3-tap kernel with dilation_rate=64 became a 129-tap kernel with 126 zero entries, and the Eigen GEMM still multiplied through every entry. Keep filters un-dilated and pass dilation_rate down to convolve(). For the strides=(1,1) fast path, loop over the un-dilated (y_filt, x_filt) positions and do one GEMM per position, indexing the input at (y_filt*dil_y, x_filt*dil_x). The s1x1 output_temp wraparound trick still works as long as out_width_temp = out_width + (f_width-1)*dil_x. Benchmark (3-stack WaveNet, 16 channels, input 18000x3, dilations 1..64): master: 159 ms this PR: 49 ms (3.3x faster; matches the no-dilation baseline of 46 ms) convolve_transposed and depthwise/separable conv keep pre-dilating filters (separate code paths, not the bottleneck reported in #132). Conv3D is left for a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the long-standing slowdown for
Conv1D/Conv2Dwith largedilation_ratereported in #132.The previous implementation inflated the filter with zeros at construction time (
dilate_filter→dilate_tensor). For a 3-tap kernel withdilation_rate=64, this produced a 129-tap kernel where 126 of the 129 entries are zero — but the Eigen GEMM still multiplied through every one of them.This PR keeps filters un-dilated and threads
dilation_ratethroughconvolve(). In thestrides=(1,1)fast path, the loop now iterates over the original(y_filt, x_filt)positions and runs one GEMM per position, indexing the padded input at(y_filt * dil_y, x_filt * dil_x). The existingoutput_tempwraparound trick keeps working as long asout_width_temp = out_width + (f_width - 1) * dil_x(which equals the padded input width).Benchmark
Stacked-WaveNet style net (3 levels × 7 branches at dilations 1, 2, 4, 8, 16, 32, 64; 16 channels; input shape
(18000, 3)):dilation_rate=1So the dilation tax drops from ~3.5× to ~6 %.
Scope
conv_2d_layer(coversConv1D+Conv2D) is updated.conv_2d_transpose_layer,depthwise_conv_2d_layer,separable_conv_2d_layerare unchanged — they continue to pre-dilate filters where applicable. Those paths are not the bottleneck reported in the issue.Conv3D'sdilate_filter_3dcould get the same treatment in a follow-up; left out of this PR to keep it focused.Test plan
test_model_exhaustive.json— passes within1e-5tolerance (coversConv1D dilation_rate=2 causal,Conv2D dilation_rate=(2,3) same,Conv3D dilation_rate=(2,2,3) same).1e-5against the Keras reference.padding='same'and asymmetric dilation(2, 3)— passes.s1x1and strided paths) — runs.🤖 Generated with Claude Code