void Compute(OpKernelContext* context) override {
    const Tensor& input_sizes = context->input(0);
    const Tensor& filter = context->input(1);
    OP_REQUIRES(
        context, TensorShapeUtils::IsVector(input_sizes.shape()),
        errors::InvalidArgument(
            "Conv2DBackpropInput: input_sizes input must be 1-dim, not ",
            input_sizes.dims()));
    TensorShape input_shape;
    const int32* in_sizes_data = input_sizes.template flat<int32>().data();

    for (int i = 0; i < input_sizes.NumElements(); ++i) {
      OP_REQUIRES(context, in_sizes_data[i] >= 0,
                  errors::InvalidArgument("Dimension ", i,
                                          " of input_sizes must be >= 0"));
      OP_REQUIRES_OK(context, input_shape.AddDimWithStatus(in_sizes_data[i]));
    }
    const TensorShape& filter_shape = filter.shape();
    EXTRACT_AND_VERIFY_DIMENSIONS("DepthwiseConv2DBackpropInput");

    Tensor* in_backprop = nullptr;
    OP_REQUIRES_OK(context, context->forward_input_or_allocate_output(
                                {0}, 0, input_shape, &in_backprop));

    // If there is nothing to compute, return.
    if (input_shape.num_elements() == 0) {
      return;
    }

    // If in_depth==1, this operation is just a standard convolution.
    // Depthwise convolution is a special case of cuDNN's grouped convolution.
    bool use_cudnn = std::is_same<Device, GPUDevice>::value &&
                     (in_depth == 1 ||
                      (use_cudnn_grouped_conv_ &&
                       IsCudnnSupportedFilterSize(/*filter_rows=*/filter_rows,
                                                  /*filter_cols=*/filter_cols,
                                                  /*in_depth=*/in_depth,
                                                  /*out_depth=*/out_depth)));

    VLOG(2) << "DepthwiseConv2dNativeBackpropInput: "
            << " Input: [" << batch << ", " << input_rows << ", " << input_cols
            << ", " << in_depth << "]; Filter: [" << filter_rows << ", "
            << filter_cols << ", " << in_depth << ", " << depth_multiplier
            << "]; Output: [" << batch << ", " << out_rows << ", " << out_cols
            << ", " << out_depth << "], stride = " << stride_
            << ", pad_rows = " << pad_top << ", pad_cols = " << pad_left
            << ", Use cuDNN: " << use_cudnn;

    if (use_cudnn) {
      // Reshape from TF depthwise filter to cuDNN grouped convolution filter:
      //
      //                  | TensorFlow       | cuDNN
      // --------------------------------------------------------------------
      // filter_out_depth | depth_multiplier | depth_multiplier * group_count
      // filter_in_depth  | in_depth         | in_depth / group_count
      //
      // For depthwise convolution, we have group_count == in_depth.
      int32_t filter_in_depth = 1;
      TensorShape shape =
          TensorShape{filter_rows, filter_cols, filter_in_depth, out_depth};
      Tensor reshaped_filter(/*type=*/dtype_);
      OP_REQUIRES(
          context, reshaped_filter.CopyFrom(filter, shape),
          errors::Internal(
              "Failed to reshape filter tensor for grouped convolution."));
      // TODO(yangzihao): Send in arbitrary dilation rates after the dilated
      // conv is supported.
      launcher_(context, /*use_cudnn=*/true, cudnn_use_autotune_, out_backprop,
                reshaped_filter, /*row_dilation=*/1, /*col_dilation=*/1,
                stride_, stride_, padding_, explicit_paddings_, in_backprop,
                data_format_);
      return;
    }

    auto out_backprop_ptr = out_backprop.template flat<T>().data();
    auto filter_ptr = filter.template flat<T>().data();
    auto in_backprop_ptr = in_backprop->template flat<T>().data();
    LaunchDepthwiseConvBackpropInputOp<Device, T>()(
        context, args, out_backprop_ptr, filter_ptr, in_backprop_ptr,
        data_format_);
  }