                       Tensor adj) {
   cudaSetDevice(adj->getDevice());
 
-  int rows = adj->shape()[0] * adj->shape()[2] * adj->shape()[3];
-  int cols = adj->shape()[1];
+  int rows = adj->shape().elements() / adj->shape().back();
+  int cols = adj->shape().back();
 
   int blocks = std::min(MAX_BLOCKS, rows);
   int threads = std::min(MAX_THREADS, cols);

void Att(Tensor out, Tensor va, Tensor context, Tensor state, Tensor coverage) {
  cudaSetDevice(out->getDevice());

  size_t m = out->shape()[0] * out->shape()[2] * out->shape()[3];

  size_t b = context->shape()[0];
  size_t k = context->shape()[1];
  size_t t = context->shape()[2];

  int blocks = std::min(MAX_BLOCKS, (int)m);
  int threads = std::min(MAX_THREADS, (int)k);

             Tensor adj) {
  cudaSetDevice(adj->getDevice());

  size_t m = adj->shape().elements() / adj->shape().back();

  size_t dims = context->shape().size();
  size_t k = context->shape()[dims - 1];
  size_t n = context->shape()[dims - 2];

  int blocks = std::min(MAX_BLOCKS, (int)n);
  int threads = std::min(MAX_THREADS, (int)k);
