def _loss_gradient_per_batch(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
        """
        Compute the gradient of the loss function w.r.t. `x` per batch.
        """
        assert x.shape[0] == y.shape[0], "Number of samples in x and y differ."

        # pad input
        x_padded, mask, mask_frequency = self._pad_audio_input(x)

        # get loss gradients
        feed_dict = {
            self._x_padded: x_padded,
            self._y_target: y,
            self._mask_frequency: mask_frequency,
        }
        gradients_padded = self.sess.run(self._loss_gradient_op, feed_dict)

        # undo padding, i.e. change gradients shape from (nb_samples, max_length) to (nb_samples)
        lengths = mask.sum(axis=1)
        gradients = []
        for gradient_padded, length in zip(gradients_padded, lengths):
            gradient = gradient_padded[:length]
            gradients.append(gradient)

        # for ragged input, use object dtype
        dtype = np.float32 if x.ndim != 1 else object
        return np.array(gradients, dtype=dtype)

        Compute the gradient of the loss function w.r.t. `x` per batch.
        
art/estimators/speech_recognition/tensorflow_lingvo.py