def get_scope_info(self) -> Tuple[List[str], List[str]]:
        """
        Get the scope information (``scope_name``, ``scope_type``) of a TorchScript node.
        In a TorchScript node, a model hierarchy is represented in a string of format:
            ``scope_name_1(scope_type_1).scope_name_2(scope_type_1).<...>.scope_name_n(scope_type_n)``
        For instance, given a torch model:

            class SubModule(torch.nn.Module):
                def __init__(self):
                    super().__init__()
                    self.linear_1 = torch.nn.Linear(2, 3)

                def forward(self, x):
                    x_1 = self.linear(x)
                    x_2 = torch.relu(x_1)
                    return x_2

            class Model(torch.nn.Module):
                def __init__(self):
                    super().__init__()
                    self.submodule_1 = SubModule()

                def forward(self, x):
                    return self.submodule_1(x)

        The model hierarchy of ``x_1`` is ``submodule_1(SubModule).linear_1(Linear)``,
        and ``x_2`` has ``submodule_1(SubModule)``.

        We consider the ``node.name`` as the most inner ``scope_name``, and
        ``node.kind`` (aten op type) as the most inner ``scope_type``.

        ``x_1`` results in:
            {
                "scope_name": ["submodule_1", "linear_1", "x_1"],
                "scope_type": ["SubModule", "Linear", "linear"],
            },
        and ``x_2`` gets:
            {
                "scope_name": ["submodule_1", "x_2"],
                "scope_type": ["SubModule", "relu"],
            }.

        Note that, for the model weight const ops, the names are in the following format:
        "submodule_1.linear_1.weight", which would result in a long ``scope_name``:
        ``["submodule_1", "linear_1", "submodule_1.linear_1.weight"]``.
        This function does a special handling to trim it to:
        ``["submodule_1", "linear_1", "weight"]``
        """

        def _trim_scopename_for_weight(scope_names: List[str]) -> List[str]:
            weight_name = scope_names[-1]
            if scope_names[:-1] != weight_name.split(".")[:-1]:
                return scope_names
            scope_names[-1] = weight_name.split(".")[-1]
            return scope_names

        if self.model_hierarchy == "" or self.model_hierarchy is None:
            scopes = []
        else:
            scopes = self.model_hierarchy.split(".")
        scope_names, scope_types = [], []
        for val in scopes:
            if val == "":
                scope_names.append("UNKNOWN_SCOPE_NAME")
                scope_types.append("UNKNOWN_SCOPE_TYPE")
                continue
            if val.count("(") != 1 or val.count(")") != 1:
                raise ValueError(f"{val} is not a valid model hierarchy string.")
            lower_idx, upper_idx = val.index("("), val.index(")")
            scope_names.append(val[:lower_idx])
            scope_types.append(val[lower_idx + 1 : upper_idx])
        scope_names.append(self.name)
        scope_types.append(self.kind)
        if self.kind == "getattr":
            scope_names = _trim_scopename_for_weight(scope_names)
        return scope_names, scope_types

        Get the scope information (``scope_name``, ``scope_type``) of a TorchScript node.
        In a TorchScript node, a model hierarchy is represented in a string of format:
            ``scope_name_1(scope_type_1).scope_name_2(scope_type_1).<...>.scope_name_n(scope_type_n)``
        For instance, given a torch model:

            class SubModule(torch.nn.Module):
                def __init__(self):
                    super().__init__()
                    self.linear_1 = torch.nn.Linear(2, 3)

                def forward(self, x):
                    x_1 = self.linear(x)
                    x_2 = torch.relu(x_1)
                    return x_2

            class Model(torch.nn.Module):
                def __init__(self):
                    super().__init__()
                    self.submodule_1 = SubModule()

                def forward(self, x):
                    return self.submodule_1(x)

        The model hierarchy of ``x_1`` is ``submodule_1(SubModule).linear_1(Linear)``,
        and ``x_2`` has ``submodule_1(SubModule)``.

        We consider the ``node.name`` as the most inner ``scope_name``, and
        ``node.kind`` (aten op type) as the most inner ``scope_type``.

        ``x_1`` results in:
            {
                "scope_name": ["submodule_1", "linear_1", "x_1"],
                "scope_type": ["SubModule", "Linear", "linear"],
            },
        and ``x_2`` gets:
            {
                "scope_name": ["submodule_1", "x_2"],
                "scope_type": ["SubModule", "relu"],
            }.

        Note that, for the model weight const ops, the names are in the following format:
        "submodule_1.linear_1.weight", which would result in a long ``scope_name``:
        ``["submodule_1", "linear_1", "submodule_1.linear_1.weight"]``.
        This function does a special handling to trim it to:
        ``["submodule_1", "linear_1", "weight"]``
        
coremltools/converters/mil/frontend/torch/internal_graph.py