Ah! You are correct: contrary to my initial impression, the gradients are not all null. The portion of the gradient tensor returned by print() was filled with zeros – unsurprisingly, since the elements of the mini-batch are sparse matrices – but there are indeed some non-zero elements buried in the middle of it. The first non-zero gradient turns out to be weight.gradient[71]. Thanks for the sanity check!
(I confess this is a bit mysterious to me: the first non-zero element of the mini-batch is xb[0,152]. I could not reproduce, with pen and paper, why the corresponding gradient appears to be weights.grad[97]. But this is technically a separate question).