Home | History | Annotate | Download | only in tests
      1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 // Tests of convolution variants -- kernel sizes, padding, and strides --
     17 // in small sized data.
     18 
     19 #include <algorithm>
     20 #include <initializer_list>
     21 #include <memory>
     22 #include <numeric>
     23 #include <random>
     24 #include <vector>
     25 
     26 #include "tensorflow/compiler/xla/array3d.h"
     27 #include "tensorflow/compiler/xla/array4d.h"
     28 #include "tensorflow/compiler/xla/client/computation_builder.h"
     29 #include "tensorflow/compiler/xla/client/local_client.h"
     30 #include "tensorflow/compiler/xla/client/padding.h"
     31 #include "tensorflow/compiler/xla/literal_util.h"
     32 #include "tensorflow/compiler/xla/reference_util.h"
     33 #include "tensorflow/compiler/xla/tests/client_library_test_base.h"
     34 #include "tensorflow/compiler/xla/tests/literal_test_util.h"
     35 #include "tensorflow/compiler/xla/tests/test_macros.h"
     36 #include "tensorflow/compiler/xla/xla_data.pb.h"
     37 #include "tensorflow/core/platform/test.h"
     38 #include "tensorflow/core/platform/types.h"
     39 
     40 namespace xla {
     41 namespace {
     42 
     43 class ConvolutionVariantsTest : public ClientLibraryTestBase {
     44  protected:
     45 #if XLA_TEST_BACKEND_GPU
     46   // XLA:GPU sometimes uses FFT convolution which isn't as precise as spatial
     47   // convolution. So relax the absolute error threshold.
     48   ErrorSpec error_spec_ = ErrorSpec(1e-1, 1e-5);
     49 #else
     50   ErrorSpec error_spec_ = ErrorSpec(1e-4, 1e-2);
     51 #endif
     52 };
     53 
     54 XLA_TEST_F(ConvolutionVariantsTest, Minimal) {
     55   ComputationBuilder builder(client_, TestName());
     56 
     57   const Array4D<float> input_array(1, 1, 1, 1, {2});
     58   auto input = builder.ConstantR4FromArray4D<float>(input_array);
     59 
     60   const Array4D<float> filter_array(1, 1, 1, 1, {3});
     61   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
     62 
     63   builder.Conv(input, filter, {1, 1}, Padding::kValid);
     64 
     65   const Array4D<float> expected(1, 1, 1, 1, {6});
     66   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
     67 }
     68 
     69 XLA_TEST_F(ConvolutionVariantsTest, MinimalWithBatch) {
     70   ComputationBuilder builder(client_, TestName());
     71 
     72   const Array4D<float> input_array(5, 1, 1, 1, {1, 2, 3, 4, 5});
     73   auto input = builder.ConstantR4FromArray4D<float>(input_array);
     74 
     75   const Array4D<float> filter_array(1, 1, 1, 1, {2});
     76   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
     77 
     78   builder.Conv(input, filter, {1, 1}, Padding::kValid);
     79 
     80   const Array4D<float> expected(5, 1, 1, 1, {2, 4, 6, 8, 10});
     81   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
     82 }
     83 
     84 XLA_TEST_F(ConvolutionVariantsTest, Flat1x1) {
     85   ComputationBuilder builder(client_, TestName());
     86 
     87   Array4D<float> input_array(2, 1, 3, 4);
     88   input_array.FillWithMultiples(1);
     89   auto input = builder.ConstantR4FromArray4D<float>(input_array);
     90 
     91   const Array4D<float> filter_array(1, 1, 1, 1, {2.3});
     92   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
     93 
     94   builder.Conv(input, filter, {1, 1}, Padding::kValid);
     95 
     96   Array4D<float> expected(2, 1, 3, 4);
     97   expected.FillWithMultiples(2.3);
     98   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
     99 }
    100 
    101 XLA_TEST_F(ConvolutionVariantsTest, Deep1x1) {
    102   ComputationBuilder builder(client_, TestName());
    103 
    104   Array4D<float> input_array(1, 2, 1, 1, {10, 1});
    105   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    106 
    107   const Array4D<float> filter_array(3, 2, 1, 1, {1, 2, 3, 4, 5, 6});
    108   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    109 
    110   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    111 
    112   Array4D<float> expected(1, 3, 1, 1, {12, 34, 56});
    113   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    114 }
    115 
    116 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2in1x2) {
    117   ComputationBuilder builder(client_, TestName());
    118 
    119   Array4D<float> input_array(1, 1, 1, 2, {1, 2});
    120   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    121 
    122   const Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    123   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    124 
    125   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    126 
    127   Array4D<float> expected(1, 1, 1, 1, {12});
    128   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    129 }
    130 
    131 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2in1x3) {
    132   ComputationBuilder builder(client_, TestName());
    133 
    134   Array4D<float> input_array(1, 1, 1, 3, {1, 2, 3});
    135   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    136 
    137   const Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    138   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    139 
    140   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    141 
    142   Array4D<float> expected(1, 1, 1, 2, {12, 23});
    143   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    144 }
    145 
    146 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2in2x2) {
    147   ComputationBuilder builder(client_, TestName());
    148 
    149   Array4D<float> input_array(1, 1, 2, 2, {1, 2, 3, 4});
    150   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    151 
    152   const Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    153   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    154 
    155   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    156 
    157   Array4D<float> expected(1, 1, 2, 1, {12, 34});
    158   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    159 }
    160 
    161 XLA_TEST_F(ConvolutionVariantsTest, Filter2x1in2x2) {
    162   ComputationBuilder builder(client_, TestName());
    163 
    164   Array4D<float> input_array(1, 1, 2, 2, {1, 2, 3, 4});
    165   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    166 
    167   const Array4D<float> filter_array(1, 1, 2, 1, {10, 1});
    168   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    169 
    170   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    171 
    172   Array4D<float> expected(1, 1, 1, 2, {13, 24});
    173   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    174 }
    175 
    176 XLA_TEST_F(ConvolutionVariantsTest, Filter2x2in2x2) {
    177   ComputationBuilder builder(client_, TestName());
    178 
    179   Array4D<float> input_array(1, 1, 2, 2, {1, 2, 3, 4});
    180   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    181 
    182   const Array4D<float> filter_array(1, 1, 2, 2, {1000, 100, 10, 1});
    183   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    184 
    185   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    186 
    187   Array4D<float> expected(1, 1, 1, 1, {1234});
    188   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    189 }
    190 
    191 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2in2x3WithDepthAndBatch) {
    192   ComputationBuilder builder(client_, TestName());
    193 
    194   Array4D<float> input_array(
    195       2, 2, 2, 3, {0, 1, 2, 3, 4, 5,  6,  7,  8,  9,  0, 0,    // plane 0
    196                    0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 0, 0});  // plane 1
    197   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    198 
    199   const Array4D<float> filter_array(
    200       2, 2, 1, 2, {1000, 100, 10, 1, 0.1, 0.01, 0.001, 0.0001});
    201   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    202 
    203   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    204 
    205   Array4D<float> expected(
    206       2, 2, 2, 2,
    207       {167, 1278, 3490, 4500, 0.0167, 0.1278, 0.3490, 0.4500,    // plane 0
    208        334, 2556, 6980, 9000, 0.0334, 0.2556, 0.6980, 0.9000});  // plane 1
    209   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    210 }
    211 
    212 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1stride1x2in1x4) {
    213   ComputationBuilder builder(client_, TestName());
    214 
    215   Array4D<float> input_array(1, 1, 1, 4, {1, 2, 3, 4});
    216   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    217 
    218   const Array4D<float> filter_array(1, 1, 1, 1, {10});
    219   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    220 
    221   builder.Conv(input, filter, {1, 2}, Padding::kValid);
    222 
    223   Array4D<float> expected(1, 1, 1, 2, {10, 30});
    224   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    225 }
    226 
    227 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1stride1x2in1x5) {
    228   ComputationBuilder builder(client_, TestName());
    229 
    230   Array4D<float> input_array(1, 1, 1, 5, {1, 2, 3, 4, 5});
    231   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    232 
    233   const Array4D<float> filter_array(1, 1, 1, 1, {10});
    234   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    235 
    236   builder.Conv(input, filter, {1, 2}, Padding::kValid);
    237 
    238   Array4D<float> expected(1, 1, 1, 3, {10, 30, 50});
    239   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    240 }
    241 
    242 XLA_TEST_F(ConvolutionVariantsTest, Filter1x3stride1x2in1x4) {
    243   ComputationBuilder builder(client_, TestName());
    244 
    245   Array4D<float> input_array(1, 1, 1, 4, {1, 2, 3, 4});
    246   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    247 
    248   const Array4D<float> filter_array(1, 1, 1, 3, {100, 10, 1});
    249   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    250 
    251   builder.Conv(input, filter, {1, 2}, Padding::kValid);
    252 
    253   Array4D<float> expected(1, 1, 1, 1, {123});
    254   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    255 }
    256 
    257 XLA_TEST_F(ConvolutionVariantsTest, Filter1x3stride1x2in1x5) {
    258   ComputationBuilder builder(client_, TestName());
    259 
    260   Array4D<float> input_array(1, 1, 1, 5, {1, 2, 3, 4, 5});
    261   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    262 
    263   const Array4D<float> filter_array(1, 1, 1, 3, {100, 10, 1});
    264   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    265 
    266   builder.Conv(input, filter, {1, 2}, Padding::kValid);
    267 
    268   Array4D<float> expected(1, 1, 1, 2, {123, 345});
    269   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    270 }
    271 
    272 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1stride2x2in3x3) {
    273   ComputationBuilder builder(client_, TestName());
    274 
    275   Array4D<float> input_array(1, 1, 3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9});
    276   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    277 
    278   const Array4D<float> filter_array(1, 1, 1, 1, {10});
    279   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    280 
    281   builder.Conv(input, filter, {2, 2}, Padding::kValid);
    282 
    283   Array4D<float> expected(1, 1, 2, 2, {10, 30, 70, 90});
    284   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    285 }
    286 
    287 XLA_TEST_F(ConvolutionVariantsTest, Filter3x1in1x1Padded) {
    288   ComputationBuilder builder(client_, TestName());
    289 
    290   Array4D<float> input_array(1, 1, 1, 1, {1});
    291   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    292 
    293   const Array4D<float> filter_array(1, 1, 1, 3, {10, 20, 30});
    294   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    295 
    296   builder.Conv(input, filter, {1, 1}, Padding::kSame);
    297 
    298   Array4D<float> expected(1, 1, 1, 1, {20});
    299   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    300 }
    301 
    302 XLA_TEST_F(ConvolutionVariantsTest, Filter5x1in3x1Padded) {
    303   ComputationBuilder builder(client_, TestName());
    304 
    305   Array4D<float> input_array(1, 1, 1, 3, {1, 2, 3});
    306   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    307 
    308   const Array4D<float> filter_array(1, 1, 1, 5, {10000, 1000, 100, 10, 1});
    309   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    310 
    311   builder.Conv(input, filter, {1, 1}, Padding::kSame);
    312 
    313   Array4D<float> expected(1, 1, 1, 3, {123, 1230, 12300});
    314   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    315 }
    316 
    317 XLA_TEST_F(ConvolutionVariantsTest, Filter3x3in2x2Padded) {
    318   ComputationBuilder builder(client_, TestName());
    319 
    320   Array4D<float> input_array(1, 1, 2, 2, {1, 2, 3, 4});
    321   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    322 
    323   const Array4D<float> filter_array(1, 1, 3, 3,
    324                                     {10000, 0, 1000,  // row 0
    325                                      0, 100, 0,       // row 1
    326                                      10, 0, 1});      // row 2
    327   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    328 
    329   builder.Conv(input, filter, {1, 1}, Padding::kSame);
    330 
    331   Array4D<float> expected(1, 1, 2, 2, {104, 230, 2300, 10400});
    332   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    333 }
    334 
    335 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1in2x1WithPaddingAndDepth) {
    336   ComputationBuilder builder(client_, TestName());
    337 
    338   Array4D<float> input_array(1, 2, 1, 2, {1, 2, 3, 4});
    339   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    340 
    341   const Array4D<float> filter_array(1, 2, 1, 1, {10, 1});
    342   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    343 
    344   builder.Conv(input, filter, {1, 1}, Padding::kSame);
    345 
    346   Array4D<float> expected(1, 1, 1, 2, {13, 24});
    347   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    348 }
    349 
    350 XLA_TEST_F(ConvolutionVariantsTest, Filter2x2Stride1x1Input3x3) {
    351   ComputationBuilder builder(client_, TestName());
    352 
    353   Array4D<float> input_array(1, 1, 3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9});
    354   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    355 
    356   const Array4D<float> filter_array(1, 1, 2, 2, {7, 13, 17, 23});
    357   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    358 
    359   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    360 
    361   Array4D<float> expected(1, 1, 2, 2, {216, 276, 396, 456});
    362   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    363 }
    364 
    365 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2Stride1x1Input1x3) {
    366   ComputationBuilder builder(client_, TestName());
    367 
    368   Array4D<float> input_array(1, 1, 1, 3, {1, 2, 3});
    369   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    370 
    371   const Array4D<float> filter_array(1, 1, 1, 2, {7, 13});
    372   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    373 
    374   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    375 
    376   Array4D<float> expected(1, 1, 1, 2, {33, 53});
    377   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    378 }
    379 
    380 XLA_TEST_F(ConvolutionVariantsTest, Filter2x1x8x8Input1x1x8x8) {
    381   ComputationBuilder builder(client_, TestName());
    382 
    383   std::vector<float> input_data(64);
    384   std::iota(input_data.begin(), input_data.end(), 0.0);
    385   Array4D<float> input_array(1, 1, 8, 8, input_data);
    386   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    387 
    388   std::vector<float> filter_data(128);
    389   std::fill(filter_data.begin(), filter_data.begin() + 64, 1.0);
    390   std::fill(filter_data.begin() + 64, filter_data.begin() + 128, 2.0);
    391   const Array4D<float> filter_array(2, 1, 8, 8, filter_data);
    392   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    393 
    394   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    395 
    396   Array4D<float> expected(1, 2, 1, 1, {2016, 4032});
    397   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    398 }
    399 
    400 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x1x1Input16x1x1x1) {
    401   ComputationBuilder builder(client_, TestName());
    402 
    403   std::vector<float> input_data(16 * 1 * 1 * 1);
    404   std::iota(input_data.begin(), input_data.end(), 1.0);
    405   Array4D<float> input_array(16, 1, 1, 1, input_data);
    406   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    407 
    408   std::vector<float> filter_data(1 * 1 * 1 * 1);
    409   std::iota(filter_data.begin(), filter_data.end(), 1.0);
    410   const Array4D<float> filter_array(1, 1, 1, 1, filter_data);
    411   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    412 
    413   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    414 
    415   std::vector<float> expected_data = {1, 2,  3,  4,  5,  6,  7,  8,
    416                                       9, 10, 11, 12, 13, 14, 15, 16};
    417   Array4D<float> expected(16, 1, 1, 1, expected_data);
    418   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    419 }
    420 
    421 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x2x2Input16x1x2x2) {
    422   ComputationBuilder builder(client_, TestName());
    423 
    424   constexpr int bs = 16;
    425   constexpr int kx = 2;
    426   constexpr int ky = 2;
    427   Array4D<float> input_array(bs, 1, ky, kx);
    428   for (int i0 = 0; i0 < bs; ++i0) {
    429     for (int i2 = 0; i2 < ky; ++i2) {
    430       for (int i3 = 0; i3 < kx; ++i3) {
    431         input_array(i0, 0, i2, i3) = i0 + 1;
    432       }
    433     }
    434   }
    435   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    436 
    437   std::vector<float> filter_data(1 * 1 * ky * kx);
    438   std::iota(filter_data.begin(), filter_data.end(), 1.0);
    439   const Array4D<float> filter_array(1, 1, ky, kx, filter_data);
    440   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    441 
    442   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    443 
    444   std::vector<float> expected_data(bs);
    445   for (int i = 0; i < bs; ++i) {
    446     expected_data[i] = 10 * (i + 1);
    447   }
    448   Array4D<float> expected(bs, 1, 1, 1, expected_data);
    449   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    450 }
    451 
    452 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x2x2Input3x1x2x2) {
    453   ComputationBuilder builder(client_, TestName());
    454 
    455   constexpr int kx = 2;
    456   constexpr int ky = 2;
    457   constexpr int bs = 3;
    458   Array4D<float> input_array(bs, 1, ky, kx);
    459   for (int i0 = 0; i0 < bs; ++i0) {
    460     for (int i2 = 0; i2 < ky; ++i2) {
    461       for (int i3 = 0; i3 < kx; ++i3) {
    462         input_array(i0, 0, i2, i3) = i0 + i2 + i3 + 1;
    463       }
    464     }
    465   }
    466   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    467 
    468   std::vector<float> filter_data(1 * 1 * ky * kx);
    469   std::iota(filter_data.begin(), filter_data.end(), 1.0);
    470   const Array4D<float> filter_array(1, 1, ky, kx, filter_data);
    471   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    472 
    473   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    474 
    475   std::vector<float> expected_data = {
    476       23,
    477       33,
    478       43,
    479   };
    480   Array4D<float> expected(bs, 1, 1, 1, expected_data);
    481   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    482 }
    483 
    484 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x8x8Input16x1x8x8) {
    485   ComputationBuilder builder(client_, TestName());
    486 
    487   Array4D<float> input_array(16, 1, 8, 8);
    488   for (int i0 = 0; i0 < 16; ++i0) {
    489     for (int i2 = 0; i2 < 8; ++i2) {
    490       for (int i3 = 0; i3 < 8; ++i3) {
    491         input_array(i0, 0, i2, i3) = i0 + i2 + i3 + 1;
    492       }
    493     }
    494   }
    495   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    496 
    497   std::vector<float> filter_data(1 * 1 * 8 * 8);
    498   std::iota(filter_data.begin(), filter_data.end(), 1.0);
    499   const Array4D<float> filter_array(1, 1, 8, 8, filter_data);
    500   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    501 
    502   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    503 
    504   std::vector<float> expected_data = {
    505       19664, 21744, 23824, 25904, 27984, 30064, 32144, 34224,
    506       36304, 38384, 40464, 42544, 44624, 46704, 48784, 50864,
    507   };
    508   Array4D<float> expected(16, 1, 1, 1, expected_data);
    509   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    510 }
    511 
    512 XLA_TEST_F(ConvolutionVariantsTest, Filter2x2x8x8Input1x2x8x8) {
    513   ComputationBuilder builder(client_, TestName());
    514 
    515   std::vector<float> input_data(2 * 8 * 8);
    516   std::iota(input_data.begin(), input_data.end(), 0.0);
    517   Array4D<float> input_array(1, 2, 8, 8, input_data);
    518   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    519 
    520   std::vector<float> filter_data(2 * 2 * 8 * 8);
    521   std::fill(filter_data.begin(), filter_data.begin() + filter_data.size() / 4,
    522             1.0);
    523   std::fill(filter_data.begin() + filter_data.size() / 4,
    524             filter_data.begin() + filter_data.size() / 2, 2.0);
    525   std::fill(filter_data.begin() + filter_data.size() / 2,
    526             filter_data.begin() + 3 * filter_data.size() / 4, 3.0);
    527   std::fill(filter_data.begin() + 3 * filter_data.size() / 4, filter_data.end(),
    528             4.0);
    529   const Array4D<float> filter_array(2, 2, 8, 8, filter_data);
    530   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    531 
    532   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    533 
    534   Array4D<float> expected(1, 2, 1, 1, {14240, 30496});
    535   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    536 }
    537 
    538 XLA_TEST_F(ConvolutionVariantsTest, Filter2x2x8x8Input2x2x8x8) {
    539   ComputationBuilder builder(client_, TestName());
    540 
    541   std::vector<float> input_data(2 * 2 * 8 * 8);
    542   std::iota(input_data.begin(), input_data.end(), 0.0);
    543   Array4D<float> input_array(2, 2, 8, 8, input_data);
    544   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    545 
    546   std::vector<float> filter_data(2 * 2 * 8 * 8);
    547   std::fill(filter_data.begin(), filter_data.begin() + filter_data.size() / 4,
    548             1.0);
    549   std::fill(filter_data.begin() + filter_data.size() / 4,
    550             filter_data.begin() + filter_data.size() / 2, 2.0);
    551   std::fill(filter_data.begin() + filter_data.size() / 2,
    552             filter_data.begin() + 3 * filter_data.size() / 4, 3.0);
    553   std::fill(filter_data.begin() + 3 * filter_data.size() / 4, filter_data.end(),
    554             4.0);
    555   const Array4D<float> filter_array(2, 2, 8, 8, filter_data);
    556   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    557 
    558   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    559 
    560   Array4D<float> expected(2, 2, 1, 1, {14240, 30496, 38816, 87840});
    561   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    562 }
    563 
    564 XLA_TEST_F(ConvolutionVariantsTest, Filter2x2x8x8Input32x2x8x8) {
    565   ComputationBuilder builder(client_, TestName());
    566 
    567   std::vector<float> input_data(32 * 2 * 8 * 8);
    568   std::iota(input_data.begin(), input_data.end(), 0.0);
    569   Array4D<float> input_array(32, 2, 8, 8, input_data);
    570   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    571 
    572   std::vector<float> filter_data(2 * 2 * 8 * 8);
    573   std::fill(filter_data.begin(), filter_data.begin() + filter_data.size() / 4,
    574             1.0);
    575   std::fill(filter_data.begin() + filter_data.size() / 4,
    576             filter_data.begin() + filter_data.size() / 2, 2.0);
    577   std::fill(filter_data.begin() + filter_data.size() / 2,
    578             filter_data.begin() + 3 * filter_data.size() / 4, 3.0);
    579   std::fill(filter_data.begin() + 3 * filter_data.size() / 4, filter_data.end(),
    580             4.0);
    581   const Array4D<float> filter_array(2, 2, 8, 8, filter_data);
    582   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    583 
    584   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    585 
    586   std::vector<float> expected_data = {
    587       14240,       30496,       38816,   87840,   63392,       145184,  87968,
    588       202528,      112544,      259872,  137120,  317216,      161696,  374560,
    589       186272,      431904,      210848,  489248,  235424,      546592,  260000,
    590       603936,      284576,      661280,  309152,  718624,      333728,  775968,
    591       358304,      833312,      382880,  890656,  407456,      948000,  432032,
    592       1005344,     456608,      1062688, 481184,  1120032,     505760,  1177376,
    593       530336,      1.23472e+06, 554912,  1292064, 579488,      1349408, 604064,
    594       1406752,     628640,      1464096, 653216,  1.52144e+06, 677792,  1578784,
    595       702368,      1636128,     726944,  1693472, 751520,      1750816, 776096,
    596       1.80816e+06,
    597   };
    598   Array4D<float> expected(32, 2, 1, 1, expected_data);
    599   // The output elements can be larger than 1e+5, making the absolute error
    600   // large sometimes. So, we focus on relative errors for this test case.
    601   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    602 }
    603 
    604 XLA_TEST_F(ConvolutionVariantsTest, Filter16x16x1x1Input16x16x1x1) {
    605   ComputationBuilder builder(client_, TestName());
    606 
    607   Array4D<float> input_array(16, 16, 1, 1);
    608   Array4D<float> filter_array(16, 16, 1, 1);
    609   for (int i0 = 0; i0 < 16; ++i0) {
    610     for (int i1 = 0; i1 < 16; ++i1) {
    611       input_array(i0, i1, 0, 0) = 1000 * i0 + i1;
    612       filter_array(i0, i1, 0, 0) = 1;
    613     }
    614   }
    615 
    616   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    617   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    618   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    619 
    620   Array4D<float> expected(16, 16, 1, 1);
    621   for (int i0 = 0; i0 < 16; ++i0) {
    622     for (int i1 = 0; i1 < 16; ++i1) {
    623       expected(i0, i1, 0, 0) = 16000 * i0 + 120;
    624     }
    625   }
    626 
    627   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    628 }
    629 
    630 XLA_TEST_F(ConvolutionVariantsTest, FlatRhsDilation) {
    631   ComputationBuilder builder(client_, TestName());
    632 
    633   std::vector<float> input_data(1 * 1 * 4 * 6);
    634   std::iota(input_data.begin(), input_data.end(), 0.0);
    635   Array4D<float> input_array(1, 1, 4, 6, input_data);
    636 
    637   Array4D<float> filter_array(1, 1, 2, 3, {1, 10, 100, 2, 20, 200});
    638   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    639   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    640   builder.ConvGeneralDilated(
    641       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{}, /*padding=*/{},
    642       /*lhs_dilation=*/{}, /*rhs_dilation=*/{2, 2},
    643       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    644 
    645   Array4D<float> expected(1, 1, 2, 2, {3924, 4257, 5922, 6255});
    646   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    647 }
    648 
    649 XLA_TEST_F(ConvolutionVariantsTest, FlatLhsDilation1D) {
    650   ComputationBuilder builder(client_, TestName());
    651 
    652   std::vector<float> input_data(1 * 1 * 1 * 5);
    653   std::iota(input_data.begin(), input_data.end(), 1.0);
    654   Array4D<float> input_array(1, 1, 1, 5, input_data);
    655 
    656   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    657   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    658   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    659   builder.ConvGeneralDilated(
    660       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{}, /*padding=*/{},
    661       /*lhs_dilation=*/{1, 2}, /*rhs_dilation=*/{},
    662       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    663 
    664   Array4D<float> expected(1, 1, 1, 8, {10, 2, 20, 3, 30, 4, 40, 5});
    665   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    666 }
    667 
    668 XLA_TEST_F(ConvolutionVariantsTest, FlatLhsDilation) {
    669   ComputationBuilder builder(client_, TestName());
    670 
    671   std::vector<float> input_data(1 * 1 * 3 * 4);
    672   std::iota(input_data.begin(), input_data.end(), 1.0);
    673   Array4D<float> input_array(1, 1, 3, 4, input_data);
    674 
    675   Array4D<float> filter_array(1, 1, 4, 3,
    676                               {100, 10, 1,  //
    677                                200, 20, 2,  //
    678                                300, 30, 3,  //
    679                                400, 40, 4});
    680   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    681   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    682   builder.ConvGeneralDilated(
    683       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{2, 1},
    684       /*padding=*/{{1, 0}, {0, 0}}, /*lhs_dilation=*/{3, 2},
    685       /*rhs_dilation=*/{},
    686       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    687 
    688   Array4D<float> expected(1, 1, 3, 5,
    689                           {204, 40, 406, 60, 608,       //
    690                            1518, 180, 1821, 210, 2124,  //
    691                            4146, 460, 4651, 510, 5156});
    692   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    693 }
    694 
    695 XLA_TEST_F(ConvolutionVariantsTest, NegativePaddingOnBothEnds) {
    696   ComputationBuilder builder(client_, TestName());
    697 
    698   std::vector<float> input_data(1 * 1 * 1 * 5);
    699   std::iota(input_data.begin(), input_data.end(), 1.0);
    700   Array4D<float> input_array(1, 1, 1, 5, input_data);
    701 
    702   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    703   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    704   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    705   builder.ConvGeneral(
    706       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{},
    707       /*padding=*/{{0, 0}, {-1, -1}},
    708       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    709 
    710   Array4D<float> expected(1, 1, 1, 2, {23, 34});
    711   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    712 }
    713 
    714 XLA_TEST_F(ConvolutionVariantsTest, NegativePaddingLowAndPositivePaddingHigh) {
    715   ComputationBuilder builder(client_, TestName());
    716 
    717   std::vector<float> input_data(1 * 1 * 1 * 5);
    718   std::iota(input_data.begin(), input_data.end(), 1.0);
    719   Array4D<float> input_array(1, 1, 1, 5, input_data);
    720 
    721   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    722   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    723   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    724   builder.ConvGeneral(
    725       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{},
    726       /*padding=*/{{0, 0}, {-1, 2}},
    727       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    728 
    729   Array4D<float> expected(1, 1, 1, 5, {23, 34, 45, 50, 0});
    730   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    731 }
    732 
    733 XLA_TEST_F(ConvolutionVariantsTest, PositivePaddingLowAndNegativePaddingHigh) {
    734   ComputationBuilder builder(client_, TestName());
    735 
    736   std::vector<float> input_data(1 * 1 * 1 * 5);
    737   std::iota(input_data.begin(), input_data.end(), 1.0);
    738   Array4D<float> input_array(1, 1, 1, 5, input_data);
    739 
    740   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    741   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    742   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    743   builder.ConvGeneral(
    744       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{},
    745       /*padding=*/{{0, 0}, {2, -1}},
    746       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    747 
    748   Array4D<float> expected(1, 1, 1, 5, {0, 1, 12, 23, 34});
    749   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    750 }
    751 
    752 XLA_TEST_F(ConvolutionVariantsTest, PositivePaddingAndDilation) {
    753   ComputationBuilder builder(client_, TestName());
    754 
    755   std::vector<float> input_data(1 * 1 * 1 * 5);
    756   std::iota(input_data.begin(), input_data.end(), 1.0);
    757   Array4D<float> input_array(1, 1, 1, 5, input_data);
    758 
    759   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    760   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    761   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    762   builder.ConvGeneralDilated(
    763       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{},
    764       /*padding=*/{{0, 0}, {3, 2}},
    765       /*lhs_dilation=*/{1, 2}, /*rhs_dilation=*/{1, 2},
    766       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    767 
    768   // input:
    769   //   [1, 2, 3, 4, 5] --dilate-> [1, 0, 2, 0, 3, 0, 4, 0, 5]
    770   //                   ---pad---> [0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0]
    771   // filter:
    772   //   [10, 1] --dilate-> [10, 0, 1]
    773   Array4D<float> expected(1, 1, 1, 12,
    774                           {0, 1, 0, 12, 0, 23, 0, 34, 0, 45, 0, 50});
    775   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    776 }
    777 XLA_TEST_F(ConvolutionVariantsTest, NegativePaddingAndDilation) {
    778   ComputationBuilder builder(client_, TestName());
    779 
    780   std::vector<float> input_data(1 * 1 * 1 * 5);
    781   std::iota(input_data.begin(), input_data.end(), 1.0);
    782   Array4D<float> input_array(1, 1, 1, 5, input_data);
    783 
    784   Array4D<float> filter_array(1, 1, 1, 2, {10, 1});
    785   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    786   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    787   builder.ConvGeneralDilated(
    788       /*lhs=*/input, /*rhs=*/filter, /*window_strides=*/{},
    789       /*padding=*/{{0, 0}, {-3, -2}},
    790       /*lhs_dilation=*/{1, 2}, /*rhs_dilation=*/{1, 2},
    791       ComputationBuilder::CreateDefaultConvDimensionNumbers());
    792 
    793   // input:
    794   //   [1, 2, 3, 4, 5] --dilate-> [1, 0, 2, 0, 3, 0, 4, 0, 5]
    795   //                   ---pad---> [0, 3, 0, 4]
    796   // filter:
    797   //   [10, 1] --dilate-> [10, 0, 1]
    798   Array4D<float> expected(1, 1, 1, 2, {0, 34});
    799   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
    800 }
    801 
    802 XLA_TEST_F(ConvolutionVariantsTest, RandomData_Input1x1x2x3_Filter2x1x1x2) {
    803   constexpr int bs = 1;
    804   constexpr int iz = 1;
    805   constexpr int oz = 2;
    806   constexpr int iy = 2;
    807   constexpr int ix = 3;
    808   constexpr int ky = 1;
    809   constexpr int kx = 2;
    810   std::mt19937 rng;
    811   std::uniform_real_distribution<float> distribution;
    812   std::vector<float> input_data(bs * iz * iy * ix);
    813   for (float& f : input_data) {
    814     f = distribution(rng);
    815   }
    816   std::vector<float> kernel_data(oz * iz * ky * kx);
    817   for (float& f : kernel_data) {
    818     f = distribution(rng);
    819   }
    820 
    821   Array4D<float> input_array(bs, iz, iy, ix, input_data);
    822   Array4D<float> filter_array(oz, iz, ky, kx, kernel_data);
    823 
    824   ComputationBuilder builder(client_, TestName());
    825   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    826   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    827   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    828 
    829   std::unique_ptr<Array4D<float>> expected = ReferenceUtil::ConvArray4D(
    830       input_array, filter_array, {1, 1}, Padding::kValid);
    831 
    832   ComputeAndCompareR4<float>(&builder, *expected, {}, error_spec_);
    833 }
    834 
    835 XLA_TEST_F(ConvolutionVariantsTest, RandomData_Input1x16x1x1_Filter1x16x1x1) {
    836   constexpr int bs = 1;
    837   constexpr int iz = 16;
    838   constexpr int oz = 1;
    839   constexpr int iy = 1;
    840   constexpr int ix = 1;
    841   constexpr int ky = 1;
    842   constexpr int kx = 1;
    843   std::mt19937 rng;
    844   std::uniform_real_distribution<float> distribution;
    845   std::vector<float> input_data(bs * iz * iy * ix);
    846   for (float& f : input_data) {
    847     f = distribution(rng);
    848   }
    849   std::vector<float> kernel_data(oz * iz * ky * kx);
    850   for (float& f : kernel_data) {
    851     f = distribution(rng);
    852   }
    853 
    854   Array4D<float> input_array(bs, iz, iy, ix, input_data);
    855   Array4D<float> filter_array(oz, iz, ky, kx, kernel_data);
    856 
    857   ComputationBuilder builder(client_, TestName());
    858   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    859   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    860   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    861 
    862   std::unique_ptr<Array4D<float>> expected = ReferenceUtil::ConvArray4D(
    863       input_array, filter_array, {1, 1}, Padding::kValid);
    864 
    865   ComputeAndCompareR4<float>(&builder, *expected, {}, error_spec_);
    866 }
    867 
    868 XLA_TEST_F(ConvolutionVariantsTest, RandomData_Input16x16x1x1_Filter1x16x1x1) {
    869   constexpr int bs = 16;
    870   constexpr int iz = 16;
    871   constexpr int oz = 1;
    872   constexpr int iy = 1;
    873   constexpr int ix = 1;
    874   constexpr int ky = 1;
    875   constexpr int kx = 1;
    876   std::mt19937 rng;
    877   std::uniform_real_distribution<float> distribution;
    878   std::vector<float> input_data(bs * iz * iy * ix);
    879   for (float& f : input_data) {
    880     f = distribution(rng);
    881   }
    882   std::vector<float> kernel_data(oz * iz * ky * kx);
    883   for (float& f : kernel_data) {
    884     f = distribution(rng);
    885   }
    886 
    887   Array4D<float> input_array(bs, iz, iy, ix, input_data);
    888   Array4D<float> filter_array(oz, iz, ky, kx, kernel_data);
    889 
    890   ComputationBuilder builder(client_, TestName());
    891   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    892   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    893   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    894 
    895   std::unique_ptr<Array4D<float>> expected = ReferenceUtil::ConvArray4D(
    896       input_array, filter_array, {1, 1}, Padding::kValid);
    897 
    898   ComputeAndCompareR4<float>(&builder, *expected, {}, error_spec_);
    899 }
    900 
    901 XLA_TEST_F(ConvolutionVariantsTest, RandomData_Input16x16x1x1_Filter16x16x1x1) {
    902   constexpr int bs = 16;
    903   constexpr int iz = 16;
    904   constexpr int oz = 16;
    905   constexpr int iy = 1;
    906   constexpr int ix = 1;
    907   constexpr int ky = 1;
    908   constexpr int kx = 1;
    909   std::mt19937 rng;
    910   std::uniform_real_distribution<float> distribution;
    911   std::vector<float> input_data(bs * iz * iy * ix);
    912   for (float& f : input_data) {
    913     f = distribution(rng);
    914   }
    915   std::vector<float> kernel_data(oz * iz * ky * kx);
    916   for (float& f : kernel_data) {
    917     f = distribution(rng);
    918   }
    919 
    920   Array4D<float> input_array(bs, iz, iy, ix, input_data);
    921   Array4D<float> filter_array(oz, iz, ky, kx, kernel_data);
    922 
    923   ComputationBuilder builder(client_, TestName());
    924   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    925   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    926   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    927 
    928   std::unique_ptr<Array4D<float>> expected = ReferenceUtil::ConvArray4D(
    929       input_array, filter_array, {1, 1}, Padding::kValid);
    930 
    931   ComputeAndCompareR4<float>(&builder, *expected, {}, error_spec_);
    932 }
    933 
    934 XLA_TEST_F(ConvolutionVariantsTest,
    935            RandomData_Input16x16x16x16_Filter16x16x16x16) {
    936   constexpr int bs = 16;
    937   constexpr int iz = 16;
    938   constexpr int oz = 16;
    939   constexpr int iy = 16;
    940   constexpr int ix = 16;
    941   constexpr int ky = 16;
    942   constexpr int kx = 16;
    943   std::mt19937 rng;
    944   std::uniform_real_distribution<float> distribution;
    945   std::vector<float> input_data(bs * iz * iy * ix);
    946   for (float& f : input_data) {
    947     f = distribution(rng);
    948   }
    949   std::vector<float> kernel_data(oz * iz * ky * kx);
    950   for (float& f : kernel_data) {
    951     f = distribution(rng);
    952   }
    953 
    954   Array4D<float> input_array(bs, iz, iy, ix, input_data);
    955   Array4D<float> filter_array(oz, iz, ky, kx, kernel_data);
    956 
    957   ComputationBuilder builder(client_, TestName());
    958   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    959   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    960   builder.Conv(input, filter, {1, 1}, Padding::kValid);
    961 
    962   std::unique_ptr<Array4D<float>> expected = ReferenceUtil::ConvArray4D(
    963       input_array, filter_array, {1, 1}, Padding::kValid);
    964 
    965   ComputeAndCompareR4<float>(&builder, *expected, {}, error_spec_);
    966 }
    967 
    968 XLA_TEST_F(ConvolutionVariantsTest, Filter1x2x1x1Input1x2x3x1GeneralPadding) {
    969   ComputationBuilder builder(client_, TestName());
    970 
    971   std::vector<float> input_data(1 * 2 * 3 * 1);
    972   std::iota(input_data.begin(), input_data.end(), 1.0);
    973   Array4D<float> input_array(1, 2, 3, 1, input_data);
    974   auto input = builder.ConstantR4FromArray4D<float>(input_array);
    975 
    976   std::vector<float> filter_data(1 * 2 * 1 * 1);
    977   std::iota(filter_data.begin(), filter_data.end(), 1.0);
    978   Array4D<float> filter_array(1, 2, 1, 1, filter_data);
    979   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
    980 
    981   ConvolutionDimensionNumbers dnums;
    982   // NHWC input format.
    983   dnums.set_input_batch_dimension(0);
    984   dnums.set_output_batch_dimension(0);
    985   dnums.add_input_spatial_dimensions(1);
    986   dnums.add_output_spatial_dimensions(1);
    987   dnums.add_input_spatial_dimensions(2);
    988   dnums.add_output_spatial_dimensions(2);
    989   dnums.set_input_feature_dimension(3);
    990   dnums.set_output_feature_dimension(3);
    991 
    992   // Tensorflow filter shape: [ H, W, inC, outC ]
    993   dnums.add_kernel_spatial_dimensions(0);
    994   dnums.add_kernel_spatial_dimensions(1);
    995   dnums.set_kernel_input_feature_dimension(2);
    996   dnums.set_kernel_output_feature_dimension(3);
    997 
    998   // Tests padding sizes that don't correspond either to SAME or VALID padding.
    999   builder.ConvGeneral(input, filter, {1, 1}, {{2, 1}, {2, 3}}, dnums);
   1000 
   1001   std::vector<float> expected_data = {
   1002       0, 0, 0,  0,  0, 0, 0,  //
   1003       0, 0, 0,  0,  0, 0, 0,  //
   1004       0, 2, 5,  8,  3, 0, 0,  //
   1005       0, 8, 14, 17, 6, 0, 0,  //
   1006       0, 0, 0,  0,  0, 0, 0   //
   1007   };
   1008   Array4D<float> expected(1, 5, 7, 1, expected_data);
   1009   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
   1010 }
   1011 
   1012 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x1x1Input1x2x3x1GeneralPadding) {
   1013   ComputationBuilder builder(client_, TestName());
   1014 
   1015   std::vector<float> input_data(1 * 2 * 3 * 1);
   1016   std::iota(input_data.begin(), input_data.end(), 1.0);
   1017   Array4D<float> input_array(1, 2, 3, 1, input_data);
   1018   auto input = builder.ConstantR4FromArray4D<float>(input_array);
   1019 
   1020   std::vector<float> filter_data(1 * 1 * 1 * 1);
   1021   std::iota(filter_data.begin(), filter_data.end(), 2.0);
   1022   Array4D<float> filter_array(1, 1, 1, 1, filter_data);
   1023   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
   1024 
   1025   ConvolutionDimensionNumbers dnums;
   1026   // NHWC input format.
   1027   dnums.set_input_batch_dimension(0);
   1028   dnums.set_output_batch_dimension(0);
   1029   dnums.add_input_spatial_dimensions(1);
   1030   dnums.add_output_spatial_dimensions(1);
   1031   dnums.add_input_spatial_dimensions(2);
   1032   dnums.add_output_spatial_dimensions(2);
   1033   dnums.set_input_feature_dimension(3);
   1034   dnums.set_output_feature_dimension(3);
   1035 
   1036   // Tensorflow filter shape: [ H, W, inC, outC ]
   1037   dnums.add_kernel_spatial_dimensions(0);
   1038   dnums.add_kernel_spatial_dimensions(1);
   1039   dnums.set_kernel_input_feature_dimension(2);
   1040   dnums.set_kernel_output_feature_dimension(3);
   1041 
   1042   // Tests padding sizes that don't correspond either to SAME or VALID padding.
   1043   builder.ConvGeneral(input, filter, {1, 1}, {{2, 1}, {2, 3}}, dnums);
   1044 
   1045   std::vector<float> expected_data = {
   1046       0, 0, 0, 0,  0,  0, 0, 0,  //
   1047       0, 0, 0, 0,  0,  0, 0, 0,  //
   1048       0, 0, 2, 4,  6,  0, 0, 0,  //
   1049       0, 0, 8, 10, 12, 0, 0, 0,  //
   1050       0, 0, 0, 0,  0,  0, 0, 0   //
   1051   };
   1052   Array4D<float> expected(1, 5, 8, 1, expected_data);
   1053   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
   1054 }
   1055 
   1056 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x1x1Input1x2x3x1NoPadding) {
   1057   ComputationBuilder builder(client_, TestName());
   1058 
   1059   std::vector<float> input_data(1 * 2 * 3 * 1);
   1060   std::iota(input_data.begin(), input_data.end(), 1.0);
   1061   Array4D<float> input_array(1, 2, 3, 1, input_data);
   1062   auto input = builder.ConstantR4FromArray4D<float>(input_array);
   1063 
   1064   std::vector<float> filter_data(1 * 1 * 1 * 1);
   1065   std::iota(filter_data.begin(), filter_data.end(), 2.0);
   1066   Array4D<float> filter_array(1, 1, 1, 1, filter_data);
   1067   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
   1068 
   1069   ConvolutionDimensionNumbers dnums;
   1070   // NHWC input format.
   1071   dnums.set_input_batch_dimension(0);
   1072   dnums.set_output_batch_dimension(0);
   1073   dnums.add_input_spatial_dimensions(1);
   1074   dnums.add_output_spatial_dimensions(1);
   1075   dnums.add_input_spatial_dimensions(2);
   1076   dnums.add_output_spatial_dimensions(2);
   1077   dnums.set_input_feature_dimension(3);
   1078   dnums.set_output_feature_dimension(3);
   1079 
   1080   // Tensorflow filter shape: [ H, W, inC, outC ]
   1081   dnums.add_kernel_spatial_dimensions(0);
   1082   dnums.add_kernel_spatial_dimensions(1);
   1083   dnums.set_kernel_input_feature_dimension(2);
   1084   dnums.set_kernel_output_feature_dimension(3);
   1085 
   1086   // Tests zero padding sizes. This can use matmul for computation.
   1087   builder.ConvGeneral(input, filter, {1, 1}, {{0, 0}, {0, 0}}, dnums);
   1088 
   1089   std::vector<float> expected_data = {
   1090       2, 4,  6,  //
   1091       8, 10, 12,
   1092   };
   1093   Array4D<float> expected(1, 2, 3, 1, expected_data);
   1094   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
   1095 }
   1096 
   1097 XLA_TEST_F(ConvolutionVariantsTest, Filter1x1x2x3Input1x2x3x2NoPadding) {
   1098   ComputationBuilder builder(client_, TestName());
   1099 
   1100   std::vector<float> input_data(1 * 2 * 3 * 2);
   1101   std::iota(input_data.begin(), input_data.end(), 1.0);
   1102   Array4D<float> input_array(1, 2, 3, 2, input_data);
   1103   auto input = builder.ConstantR4FromArray4D<float>(input_array);
   1104 
   1105   std::vector<float> filter_data(1 * 1 * 2 * 3);
   1106   std::iota(filter_data.begin(), filter_data.end(), 2.0);
   1107   Array4D<float> filter_array(1, 1, 2, 3, filter_data);
   1108   auto filter = builder.ConstantR4FromArray4D<float>(filter_array);
   1109 
   1110   ConvolutionDimensionNumbers dnums;
   1111   // NHWC input format.
   1112   dnums.set_input_batch_dimension(0);
   1113   dnums.set_output_batch_dimension(0);
   1114   dnums.add_input_spatial_dimensions(1);
   1115   dnums.add_output_spatial_dimensions(1);
   1116   dnums.add_input_spatial_dimensions(2);
   1117   dnums.add_output_spatial_dimensions(2);
   1118   dnums.set_input_feature_dimension(3);
   1119   dnums.set_output_feature_dimension(3);
   1120 
   1121   // Tensorflow filter shape: [ H, W, inC, outC ]
   1122   dnums.add_kernel_spatial_dimensions(0);
   1123   dnums.add_kernel_spatial_dimensions(1);
   1124   dnums.set_kernel_input_feature_dimension(2);
   1125   dnums.set_kernel_output_feature_dimension(3);
   1126 
   1127   // Tests zero padding sizes. This can use matmul for computation.
   1128   builder.ConvGeneral(input, filter, {1, 1}, {{0, 0}, {0, 0}}, dnums);
   1129 
   1130   std::vector<float> expected_data = {
   1131       12, 15,  18,   //
   1132       26, 33,  40,   //
   1133       40, 51,  62,   //
   1134       54, 69,  84,   //
   1135       68, 87,  106,  //
   1136       82, 105, 128,  //
   1137   };
   1138   Array4D<float> expected(1, 2, 3, 3, expected_data);
   1139   ComputeAndCompareR4<float>(&builder, expected, {}, error_spec_);
   1140 }
   1141 
   1142 // Regression test for b/32034796.
   1143 //
   1144 // XLA:GPU fuses
   1145 //   Conv([1,2,3], Reverse([5,6]), padding_low=1)
   1146 // into
   1147 //   BackwardInputConv([1,2,3], [5,6], padding_low=0, padding_high=1)
   1148 XLA_TEST_F(ConvolutionVariantsTest,
   1149            BackwardInputLowPaddingLessThanHighPadding) {
   1150   ComputationBuilder builder(client_, TestName());
   1151 
   1152   auto gradients = builder.ConstantR4FromArray4D<float>(
   1153       Array4D<float>(1, 1, 1, 3, /*values=*/{1, 2, 3}));
   1154   auto weights = builder.ConstantR4FromArray4D<float>(
   1155       Array4D<float>(1, 1, 1, 2, /*values=*/{5, 6}));
   1156   auto mirrored_weights = builder.Rev(weights, {2, 3});
   1157   builder.ConvWithGeneralPadding(gradients, mirrored_weights,
   1158                                  /*window_strides=*/{1, 1},
   1159                                  /*padding=*/{{0, 0}, {1, 0}});
   1160   ComputeAndCompareR4<float>(&builder, {{{{5, 16, 27}}}}, {}, error_spec_);
   1161 }
   1162 
   1163 // XLA:GPU fuses
   1164 //   Conv([1], Reverse([1,10,100]), padding_high=3, base_dilation=3)
   1165 // into
   1166 //   BackwardInputConv([1], [1,10,100], stride=3, padding=(2,1))
   1167 XLA_TEST_F(ConvolutionVariantsTest,
   1168            BackwardInputLowPaddingGreaterThanHighPadding) {
   1169   ComputationBuilder builder(client_, TestName());
   1170 
   1171   auto gradients = builder.ConstantR4FromArray4D<float>(
   1172       Array4D<float>(1, 1, 1, 1, /*values=*/{1}));
   1173   auto weights = builder.ConstantR4FromArray4D<float>(
   1174       Array4D<float>(1, 1, 1, 3, /*values=*/{1, 10, 100}));
   1175   auto mirrored_weights = builder.Rev(weights, {2, 3});
   1176   builder.ConvGeneralDilated(
   1177       gradients, mirrored_weights,
   1178       /*window_strides=*/{1, 1},
   1179       /*padding=*/{{0, 0}, {0, 3}},
   1180       /*lhs_dilation=*/{1, 3}, /*rhs_dilation=*/{},
   1181       ComputationBuilder::CreateDefaultConvDimensionNumbers());
   1182   ComputeAndCompareR4<float>(&builder, {{{{100, 0}}}}, {}, error_spec_);
   1183 }
   1184 
   1185 // XLA:GPU fuses
   1186 //   Conv([1], Reverse([1,10,100]), padding=(1,1))
   1187 // into
   1188 //   BackwardInputConv([1], [1,10,100], padding=(1,1))
   1189 XLA_TEST_F(ConvolutionVariantsTest, BackwardInputEvenPadding) {
   1190   ComputationBuilder builder(client_, TestName());
   1191 
   1192   auto gradients = builder.ConstantR4FromArray4D<float>(
   1193       Array4D<float>(1, 1, 1, 1, /*values=*/{1}));
   1194   auto weights = builder.ConstantR4FromArray4D<float>(
   1195       Array4D<float>(1, 1, 1, 3, /*values=*/{1, 10, 100}));
   1196   auto mirrored_weights = builder.Rev(weights, {2, 3});
   1197   builder.ConvWithGeneralPadding(gradients, mirrored_weights,
   1198                                  /*window_strides=*/{1, 1},
   1199                                  /*padding=*/{{0, 0}, {1, 1}});
   1200   ComputeAndCompareR4<float>(&builder, {{{{10}}}}, {}, error_spec_);
   1201 }
   1202 
   1203 // HLO pattern
   1204 //   Conv([1,2,3], Reverse([1,10], padding_high=2)
   1205 // could be fused to
   1206 //   BackwardInputConv([1,2,3], [1,10], padding_low=1, padding_high=-1)
   1207 //
   1208 // However, XLA:GPU doesn't actually fuse it because PadInsertion doesn't
   1209 // support negative padding on backward convolution yet (b/32744257).
   1210 XLA_TEST_F(ConvolutionVariantsTest, BackwardInputWithNegativePaddingHigh) {
   1211   ComputationBuilder builder(client_, TestName());
   1212 
   1213   auto gradients = builder.ConstantR4FromArray4D<float>(
   1214       Array4D<float>(1, 1, 1, 3, /*values=*/{1, 2, 3}));
   1215   auto weights = builder.ConstantR4FromArray4D<float>(
   1216       Array4D<float>(1, 1, 1, 2, /*values=*/{1, 10}));
   1217   auto mirrored_weights = builder.Rev(weights, {2, 3});
   1218   builder.ConvWithGeneralPadding(gradients, mirrored_weights,
   1219                                  /*window_strides=*/{1, 1},
   1220                                  /*padding=*/{{0, 0}, {0, 2}});
   1221 
   1222   ComputeAndCompareR4<float>(&builder, {{{{12, 23, 30, 0}}}}, {}, error_spec_);
   1223 }
   1224 
   1225 XLA_TEST_F(ConvolutionVariantsTest,
   1226            BackwardFilterLowPaddingLessThanHighPadding) {
   1227   ComputationBuilder builder(client_, TestName());
   1228 
   1229   // activations:      1,2,3,4  ---pad--> 0,1,2,3,4,0,0
   1230   // gradients:        100,10,1 -dilate-> 100,0,10,0,1
   1231   // weight gradients: 24,130,240
   1232   //
   1233   // This pattern will be fused to backward convolution with padding=(1,2).
   1234   auto activations = builder.ConstantR4FromArray4D<float>(
   1235       Array4D<float>(1, 1, 1, 4, /*values=*/{1, 2, 3, 4}));
   1236   auto gradients = builder.ConstantR4FromArray4D<float>(
   1237       Array4D<float>(1, 1, 1, 3, /*values=*/{100, 10, 1}));
   1238   auto forward_conv = builder.ConvGeneralDilated(
   1239       activations, gradients,
   1240       /*window_strides=*/{1, 1},
   1241       /*padding=*/{{0, 0}, {1, 2}},
   1242       /*lhs_dilation=*/{}, /*rhs_dilation=*/{1, 2},
   1243       ComputationBuilder::CreateDefaultConvDimensionNumbers());
   1244   builder.Transpose(forward_conv, {0, 1, 2, 3});
   1245 
   1246   ComputeAndCompareR4<float>(&builder, {{{{24, 130, 240}}}}, {}, error_spec_);
   1247 }
   1248 
   1249 XLA_TEST_F(ConvolutionVariantsTest,
   1250            BackwardFilterLowPaddingGreaterThanHighPadding) {
   1251   ComputationBuilder builder(client_, TestName());
   1252 
   1253   // activations:      1,2,3,4  ---pad--> 0,0,1,2,3,4
   1254   // gradients:        100,10,1 -dilate-> 100,0,10,0,1
   1255   // weight gradients: 13,24
   1256   //
   1257   // This pattern will be fused to backward convolution with padding=(2,1).
   1258   // Note: both (2,1) and (2,0) are valid padding for the backward convolution
   1259   // because the stride is 2.
   1260   auto activations = builder.ConstantR4FromArray4D<float>(
   1261       Array4D<float>(1, 1, 1, 4, /*values=*/{1, 2, 3, 4}));
   1262   auto gradients = builder.ConstantR4FromArray4D<float>(
   1263       Array4D<float>(1, 1, 1, 3, /*values=*/{100, 10, 1}));
   1264   auto forward_conv = builder.ConvGeneralDilated(
   1265       activations, gradients,
   1266       /*window_strides=*/{1, 1},
   1267       /*padding=*/{{0, 0}, {2, 0}},
   1268       /*lhs_dilation=*/{}, /*rhs_dilation=*/{1, 2},
   1269       ComputationBuilder::CreateDefaultConvDimensionNumbers());
   1270   builder.Transpose(forward_conv, {0, 1, 2, 3});
   1271 
   1272   ComputeAndCompareR4<float>(&builder, {{{{13, 24}}}}, {}, error_spec_);
   1273 }
   1274 
   1275 XLA_TEST_F(ConvolutionVariantsTest, BackwardFilterEvenPadding) {
   1276   ComputationBuilder builder(client_, TestName());
   1277 
   1278   // activations:      1,2,3,4  ---pad--> 0,0,1,2,3,4,0
   1279   // gradients:        100,10,1 -dilate-> 100,0,10,0,1
   1280   // weight gradients: 13,24,130
   1281   //
   1282   // This pattern will be fused to backward convolution with padding=(2,2).
   1283   // Note: both (2,1) and (2,2) are valid padding for the backward convolution
   1284   // because the stride is 2. ConvolutionFolding prefers (2,2) because cuDNN
   1285   // supports even padding only -- using (2,1) would need extra effort of
   1286   // canonicalization.
   1287   auto activations = builder.ConstantR4FromArray4D<float>(
   1288       Array4D<float>(1, 1, 1, 4, /*values=*/{1, 2, 3, 4}));
   1289   auto gradients = builder.ConstantR4FromArray4D<float>(
   1290       Array4D<float>(1, 1, 1, 3, /*values=*/{100, 10, 1}));
   1291   auto forward_conv = builder.ConvGeneralDilated(
   1292       activations, gradients,
   1293       /*window_strides=*/{1, 1},
   1294       /*padding=*/{{0, 0}, {2, 1}},
   1295       /*lhs_dilation=*/{}, /*rhs_dilation=*/{1, 2},
   1296       ComputationBuilder::CreateDefaultConvDimensionNumbers());
   1297   builder.Transpose(forward_conv, {0, 1, 2, 3});
   1298 
   1299   ComputeAndCompareR4<float>(&builder, {{{{13, 24, 130}}}}, {}, error_spec_);
   1300 }
   1301 
   1302 XLA_TEST_F(ConvolutionVariantsTest, BackwardInputEvenPadding1D) {
   1303   ComputationBuilder builder(client_, TestName());
   1304 
   1305   auto gradients = builder.ConstantR3FromArray3D<float>(
   1306       Array3D<float>(1, 1, 1, /*value=*/1));
   1307   auto weights =
   1308       builder.ConstantR3FromArray3D<float>(Array3D<float>({{{1, 10, 100}}}));
   1309   auto mirrored_weights = builder.Rev(weights, {2});
   1310   builder.ConvWithGeneralPadding(gradients, mirrored_weights,
   1311                                  /*window_strides=*/{1},
   1312                                  /*padding=*/{{1, 1}});
   1313   ComputeAndCompareR3<float>(&builder, {{{10}}}, {}, error_spec_);
   1314 }
   1315 
   1316 XLA_TEST_F(ConvolutionVariantsTest, BackwardFilterEvenPadding1D) {
   1317   ComputationBuilder builder(client_, TestName());
   1318 
   1319   auto activations =
   1320       builder.ConstantR3FromArray3D<float>(Array3D<float>({{{1, 2, 3, 4}}}));
   1321   auto gradients =
   1322       builder.ConstantR3FromArray3D<float>(Array3D<float>({{{100, 10, 1}}}));
   1323   auto forward_conv = builder.ConvGeneralDilated(
   1324       activations, gradients,
   1325       /*window_strides=*/{1},
   1326       /*padding=*/{{2, 1}},
   1327       /*lhs_dilation=*/{}, /*rhs_dilation=*/{2},
   1328       ComputationBuilder::CreateDefaultConvDimensionNumbers(
   1329           /*num_spatial_dims=*/1));
   1330   builder.Transpose(forward_conv, {0, 1, 2});
   1331 
   1332   ComputeAndCompareR3<float>(&builder, {{{13, 24, 130}}}, {}, error_spec_);
   1333 }
   1334 
   1335 XLA_TEST_F(ConvolutionVariantsTest, BackwardInputEvenPadding3D) {
   1336   ComputationBuilder builder(client_, TestName());
   1337 
   1338   auto gradients_flat = Literal::CreateR1<float>({1});
   1339   auto gradients_literal =
   1340       gradients_flat->Reshape({1, 1, 1, 1, 1}).ConsumeValueOrDie();
   1341   auto gradients = builder.ConstantLiteral(*gradients_literal);
   1342 
   1343   auto weights_flat = Literal::CreateR1<float>({1, 10, 100});
   1344   auto weights_literal =
   1345       weights_flat->Reshape({1, 1, 1, 1, 3}).ConsumeValueOrDie();
   1346   auto weights = builder.ConstantLiteral(*weights_literal);
   1347 
   1348   auto expected_flat = Literal::CreateR1<float>({10});
   1349   auto expected_literal =
   1350       expected_flat->Reshape({1, 1, 1, 1, 1}).ConsumeValueOrDie();
   1351 
   1352   auto mirrored_weights = builder.Rev(weights, {2, 3, 4});
   1353   builder.ConvWithGeneralPadding(gradients, mirrored_weights,
   1354                                  /*window_strides=*/{1, 1, 1},
   1355                                  /*padding=*/{{0, 0}, {0, 0}, {1, 1}});
   1356   ComputeAndCompareLiteral(&builder, *expected_literal, {}, error_spec_);
   1357 }
   1358 
   1359 XLA_TEST_F(ConvolutionVariantsTest, BackwardFilterEvenPadding3D) {
   1360   ComputationBuilder builder(client_, TestName());
   1361 
   1362   auto activations_flat = Literal::CreateR1<float>({1, 2, 3, 4});
   1363   auto activations_literal =
   1364       activations_flat->Reshape({1, 1, 1, 1, 4}).ConsumeValueOrDie();
   1365   auto activations = builder.ConstantLiteral(*activations_literal);
   1366 
   1367   auto gradients_flat = Literal::CreateR1<float>({100, 10, 1});
   1368   auto gradients_literal =
   1369       gradients_flat->Reshape({1, 1, 1, 1, 3}).ConsumeValueOrDie();
   1370   auto gradients = builder.ConstantLiteral(*gradients_literal);
   1371 
   1372   auto expected_flat = Literal::CreateR1<float>({13, 24, 130});
   1373   auto expected_literal =
   1374       expected_flat->Reshape({1, 1, 1, 1, 3}).ConsumeValueOrDie();
   1375 
   1376   auto forward_conv = builder.ConvGeneralDilated(
   1377       activations, gradients,
   1378       /*window_strides=*/{1, 1, 1},
   1379       /*padding=*/{{0, 0}, {0, 0}, {2, 1}},
   1380       /*lhs_dilation=*/{}, /*rhs_dilation=*/{1, 1, 2},
   1381       ComputationBuilder::CreateDefaultConvDimensionNumbers(
   1382           /*num_spatial_dims=*/3));
   1383   builder.Transpose(forward_conv, {0, 1, 2, 3, 4});
   1384   ComputeAndCompareLiteral(&builder, *expected_literal, {}, error_spec_);
   1385 }
   1386 
   1387 }  // namespace
   1388 }  // namespace xla
   1389