def get_layer_activations(  # type: ignore
        p_classifier: PyTorchClassifier,
        x: "torch.Tensor",
        layers: list[int | str],
    ) -> tuple[dict[str, "torch.Tensor"], list[str]]:
        """
        Return the output of the specified layers for input `x`. `layers` is a list of either layer indices (between 0
        and `nb_layers - 1`) or layers' name. The number of layers can be determined by counting the results returned by
        calling `layer_names`.

        :param p_classifier: model for adversarial training protocol.
        :param x: Input for computing the activations.
        :param layers: Layers for computing the activations
        :return: Tuple containing the output dict and a list of layers' names. In dictionary each element is a
                 layer's output where the first dimension is the batch size corresponding to `x`.
        """

        p_classifier.model.train(mode=False)

        list_layer_names = []
        for layer in layers:
            if isinstance(layer, six.string_types):
                if layer not in p_classifier._layer_names:
                    raise ValueError(f"Layer name {layer} not supported")
                layer_name = layer
                list_layer_names.append(layer_name)

            elif isinstance(layer, int):
                layer_index = layer
                layer_name = p_classifier._layer_names[layer_index]
                list_layer_names.append(layer_name)

            else:
                raise TypeError("Layer must be of type str or int")

        def get_feature(name):
            # the hook signature
            def hook(model, input, output):  # pylint: disable=redefined-builtin,unused-argument
                p_classifier._features[name] = output

            return hook

        if not hasattr(p_classifier, "_features"):
            p_classifier._features = {}
            # register forward hooks on the layers of choice

        for layer_name in list_layer_names:
            if layer_name not in p_classifier._features:
                interim_layer = dict([*p_classifier._model._model.named_modules()])[layer_name]
                interim_layer.register_forward_hook(get_feature(layer_name))

        p_classifier.model(x)
        return p_classifier._features, list_layer_names

        Return the output of the specified layers for input `x`. `layers` is a list of either layer indices (between 0
        and `nb_layers - 1`) or layers' name. The number of layers can be determined by counting the results returned by
        calling `layer_names`.

        :param p_classifier: model for adversarial training protocol.
        :param x: Input for computing the activations.
        :param layers: Layers for computing the activations
        :return: Tuple containing the output dict and a list of layers' names. In dictionary each element is a
                 layer's output where the first dimension is the batch size corresponding to `x`.
        
art/defences/trainer/adversarial_trainer_oaat_pytorch.py