def estimate_gradient(self, x: np.ndarray, grad: np.ndarray) -> np.ndarray:
        """
        Provide an estimate of the gradients of the defence for the backward pass. For thermometer encoding,
        the gradient estimate is the one used in https://arxiv.org/abs/1802.00420, where the thermometer encoding
        is replaced with a differentiable approximation:
        `g(x_{i,j,c})_k = min(max(x_{i,j,c} - k / self.num_space, 0), 1)`.

        :param x: Input data for which the gradient is estimated. First dimension is the batch size.
        :param grad: Gradient value so far.
        :return: The gradient (estimate) of the defence.
        """
        if self.channels_first:
            x = np.transpose(x, (0,) + tuple(range(2, len(x.shape))) + (1,))
            grad = np.transpose(grad, (0,) + tuple(range(2, len(x.shape))) + (1,))

        thermometer_grad = np.zeros(x.shape[:-1] + (x.shape[-1] * self.num_space,))
        mask = np.array([x > k / self.num_space for k in range(self.num_space)])
        mask = np.moveaxis(mask, 0, -1)
        mask = mask.reshape(thermometer_grad.shape)
        thermometer_grad[mask] = 1

        grad = grad * thermometer_grad
        grad = np.reshape(grad, grad.shape[:-1] + (grad.shape[-1] // self.num_space, self.num_space))
        grad = np.sum(grad, -1)

        if self.channels_first:
            x = np.transpose(x, (0,) + (len(x.shape) - 1,) + tuple(range(1, len(x.shape) - 1)))
            grad = np.transpose(grad, (0,) + (len(x.shape) - 1,) + tuple(range(1, len(x.shape) - 1)))

        return grad / (self.clip_values[1] - self.clip_values[0])

        Provide an estimate of the gradients of the defence for the backward pass. For thermometer encoding,
        the gradient estimate is the one used in https://arxiv.org/abs/1802.00420, where the thermometer encoding
        is replaced with a differentiable approximation:
        `g(x_{i,j,c})_k = min(max(x_{i,j,c} - k / self.num_space, 0), 1)`.

        :param x: Input data for which the gradient is estimated. First dimension is the batch size.
        :param grad: Gradient value so far.
        :return: The gradient (estimate) of the defence.
        
art/defences/preprocessor/thermometer_encoding.py