aten/src/ATen/native/cudnn/RNN.cpp
// We need this dispatcher because _cudnn_rnn_backward_weight has a stringent
// ordering requirement with _cudnn_rnn_backward_input
We need this dispatcher because _cudnn_rnn_backward_weight has a stringent
ordering requirement with _cudnn_rnn_backward_input
We need this dispatcher because _cudnn_rnn_backward_weight has a stringent ordering requirement with _cudnn_rnn_backward_input
std::tuple<Tensor, Tensor, Tensor, std::vector<Tensor>> _cudnn_rnn_backward(
    const Tensor& input, TensorList weight, int64_t weight_stride0, const Tensor& weight_buf, const Tensor& hx, const Tensor& cx,
    const Tensor& output, const Tensor& grad_output_r, const Tensor& grad_hy_r,
    const Tensor& grad_cy_r,
    int64_t mode, int64_t hidden_size,
    int64_t num_layers, bool batch_first, double dropout,
    bool train, bool bidirectional, IntList batch_sizes,
    const Tensor& dropout_state, const Tensor& reserve,
    std::array<bool, 4> output_mask
    ) {
  auto grad_output = grad_output_r.defined() ? grad_output_r : output.type().zeros_like(output);
  auto grad_hy = grad_hy_r.defined() ? grad_hy_r : hx.type().zeros_like(hx);
  auto grad_cy = cx.defined() ? (grad_cy_r.defined() ? grad_cy_r : cx.type().zeros_like(cx)) : grad_cy_r;
  Tensor dx, dhx, dcx;
  std::tie(dx, dhx, dcx) = at::native::_cudnn_rnn_backward_input(input, weight_buf, hx, cx, output, grad_output, grad_hy, grad_cy, mode, hidden_size, num_layers, batch_first, dropout, train, bidirectional, batch_sizes, dropout_state, reserve, {output_mask[0], output_mask[1], output_mask[2]});
  std::vector<Tensor> dw;
  if (output_mask[3]) {
    dw = at::native::_cudnn_rnn_backward_weight(input, weight, weight_stride0, weight_buf, hx, cx, output, mode, hidden_size, num_layers, batch_first, dropout, train, bidirectional, batch_sizes, dropout_state, reserve);
  }
  return std::tuple<Tensor, Tensor, Tensor, std::vector<Tensor>>{dx, dhx, dcx, dw};
}
std :: tuple < Tensor , Tensor , Tensor , std :: vector < Tensor > > _cudnn_rnn_backward ( const Tensor & input , TensorList weight , int64_t weight_stride0 , const Tensor & weight_buf , const Tensor & hx , const Tensor & cx , const Tensor & output , const Tensor & grad_output_r , const Tensor & grad_hy_r , const Tensor & grad_cy_r , int64_t mode , int64_t hidden_size , int64_t num_layers , bool batch_first , double dropout , bool train , bool bidirectional , IntList batch_sizes , const Tensor & dropout_state , const Tensor & reserve , std :: array < bool , 4 > output_mask ) { auto grad_output = grad_output_r . defined ( ) ? grad_output_r : output . type ( ) . zeros_like ( output ) ; auto grad_hy = grad_hy_r . defined ( ) ? grad_hy_r : hx . type ( ) . zeros_like ( hx ) ; auto grad_cy = cx . defined ( ) ? ( grad_cy_r . defined ( ) ? grad_cy_r : cx . type ( ) . zeros_like ( cx ) ) : grad_cy_r ; Tensor dx , dhx , dcx ; std :: tie ( dx , dhx , dcx ) = at :: native :: _cudnn_rnn_backward_input ( input , weight_buf , hx , cx , output , grad_output , grad_hy , grad_cy , mode , hidden_size , num_layers , batch_first , dropout , train , bidirectional , batch_sizes , dropout_state , reserve , { output_mask [ 0 ] , output_mask [ 1 ] , output_mask [ 2 ] } ) ; std :: vector < Tensor > dw ; if ( output_mask [ 3 ] ) { dw = at :: native :: _cudnn_rnn_backward_weight ( input , weight , weight_stride0 , weight_buf , hx , cx , output , mode , hidden_size , num_layers , batch_first , dropout , train , bidirectional , batch_sizes , dropout_state , reserve ) ; } return std :: tuple < Tensor , Tensor , Tensor , std :: vector < Tensor > > { dx , dhx , dcx , dw } ; }
We need this dispatcher because _cudnn_rnn_backward_weight has a stringent
ordering requirement with _cudnn_rnn_backward_input
We need this dispatcher because _cudnn_rnn_backward_weight has a stringent ordering requirement with _cudnn_rnn_backward_input
// NB: unconditionally compute this gradient, because it mutates reserve