code: def backward(ctx, dout):
      # retrieve from context
      out, lut = ctx.saved_tensors
      # relative logits gradients
      dr = None
      if ctx.needs_input_grad[3]:
          dr = torch.zeros(
              ctx.rel_shape, dtype=ctx.rel_dtype, device=out.device
          )
      # run kernel
      M = out.shape[0]
      grid = (ctx.spdims[0], ctx.spdims[1] * ctx.block, M)
      da = torch.empty_like(dout)
      _blocksparse_softmax_bwd[grid](
          da,
          da.stride(0),  #
          dout,
          dout.stride(0),  #
          out,
          out.stride(0),  #
          ctx.scale,  #
          lut,  #
          dr,
          ctx.rel_shape[-1],
          ctx.rel_strides[0],
          ctx.rel_strides[1],
          ctx.rel_strides[2],  #
          ctx.is_causal,  #
          BLOCK_SIZE=ctx.block,  #
          ROW_SIZE=next_power_of_2(ctx.maxlut),  #
          IS_DENSE=ctx.is_dense,  #
          num_warps=num_warps(ctx.maxlut),  #
      )
      return (
          da,
          None,
          None,
          dr,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
          None,
      )
  
file_path: triton/python/triton/ops/blocksparse/softmax.py
imports: import torch
  from ...None import jit
  from ...None import language
  from ...None import next_power_of_2
label_desc: Use image node_id 3 for calling the _softmax obj's underlying member method code with example usage: obj.backward(ctx, dout) and returns: da,  None,  None,  dr,  None,  None,  None,  None,  None,  None,  None,  None,  None,  None,  None,  None,  None,  None