def forward(self, x: np.ndarray) -> "torch.Tensor":
        """
        Performs the neural network forward pass, either using abstract operations or concrete ones
        depending on the value of self.forward_mode

        :param x: input data, either regular data if running in concrete mode, or in an interval form with shape:
        x[batch_size, 2, feature_1, feature_2, ...] where axis=1 corresponds to the [lower, upper] bounds.
        :return: regular model predictions if in concrete mode, or interval predictions if running in abstract mode
        """

        if self.forward_mode in ["concrete", "attack"]:
            return self.concrete_forward(x)
        if self.forward_mode == "abstract":
            if x.shape[1] == 2:
                return self.abstract_forward(x)
            raise ValueError("axis=1 for the input must be of size 2 representing lower and upper bounds")
        raise ValueError("forward_mode must be set to abstract or concrete")

        Performs the neural network forward pass, either using abstract operations or concrete ones
        depending on the value of self.forward_mode

        :param x: input data, either regular data if running in concrete mode, or in an interval form with shape:
        x[batch_size, 2, feature_1, feature_2, ...] where axis=1 corresponds to the [lower, upper] bounds.
        :return: regular model predictions if in concrete mode, or interval predictions if running in abstract mode
        
art/estimators/certification/interval/pytorch.py