본문 바로가기
Python

추상 메서드 (Abstract Method)

by arirang_ 2024. 12. 10.

허깅페이스의 transformers 코드를 보다가 추상메서드에 대해 정리해보려고 한다.

 

📌 추상 메서드란?

구체적인 구현없이 선언만 된 메서드.

추상 메서드는 상위 클래스에서 정의되지만, 하위 클래스에서 반드시 구현되어야 한다. 

 

📌 사용 목적

특정 클래스가 가져야 할 공통 인터페이스를 정의하기 위해 사용된다.

 

📌 특징

본체(구현)가 없으며, 보통 pass 또는 raise NotImplementedError로 처리된다.

 

📌 구현 예시

transformers/src/tranformers/tokenization_utils_base.py

_encode_plus는 tokenization_utils_base에 정의된 추상 메서드이다. 

_encode_plus는 PreTrainedTokenizerBase 클래스에서 선언만 되어 있고, 실제 구현은 상속받은 클래스(transformers/src/tranformers/tokenization_utils.py의 PreTrainedTokenizer )에서 이루어진다.

@add_end_docstrings(INIT_TOKENIZER_DOCSTRING)
class PreTrainedTokenizerBase(SpecialTokensMixin, PushToHubMixin):
    ...
    def _encode_plus(
            self,
            text: Union[TextInput, PreTokenizedInput, EncodedInput],
            text_pair: Optional[Union[TextInput, PreTokenizedInput, EncodedInput]] = None,
            add_special_tokens: bool = True,
            padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
            truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
            max_length: Optional[int] = None,
            stride: int = 0,
            is_split_into_words: bool = False,
            pad_to_multiple_of: Optional[int] = None,
            padding_side: Optional[bool] = None,
            return_tensors: Optional[Union[str, TensorType]] = None,
            return_token_type_ids: Optional[bool] = None,
            return_attention_mask: Optional[bool] = None,
            return_overflowing_tokens: bool = False,
            return_special_tokens_mask: bool = False,
            return_offsets_mapping: bool = False,
            return_length: bool = False,
            verbose: bool = True,
            split_special_tokens: bool = False,
            **kwargs,
        ) -> BatchEncoding:
            raise NotImplementedError
        
        ...

 

 

transformers/src/tranformers/tokenization_utils.py

from .tokenization_utils_base import (
    ...
    PreTrainedTokenizerBase,
    ...
)
@add_end_docstrings(INIT_TOKENIZER_DOCSTRING)
class PreTrainedTokenizer(PreTrainedTokenizerBase):
	...

    def _encode_plus(
        self,
        text: Union[TextInput, PreTokenizedInput, EncodedInput],
        text_pair: Optional[Union[TextInput, PreTokenizedInput, EncodedInput]] = None,
        add_special_tokens: bool = True,
        padding_strategy: PaddingStrategy = PaddingStrategy.DO_NOT_PAD,
        truncation_strategy: TruncationStrategy = TruncationStrategy.DO_NOT_TRUNCATE,
        max_length: Optional[int] = None,
        stride: int = 0,
        is_split_into_words: bool = False,
        pad_to_multiple_of: Optional[int] = None,
        padding_side: Optional[bool] = None,
        return_tensors: Optional[Union[str, TensorType]] = None,
        return_token_type_ids: Optional[bool] = None,
        return_attention_mask: Optional[bool] = None,
        return_overflowing_tokens: bool = False,
        return_special_tokens_mask: bool = False,
        return_offsets_mapping: bool = False,
        return_length: bool = False,
        verbose: bool = True,
        **kwargs,
    ) -> BatchEncoding:
        def get_input_ids(text):
            if isinstance(text, str):
                tokens = self.tokenize(text, **kwargs)
                return self.convert_tokens_to_ids(tokens)
            elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], str):
                if is_split_into_words:
                    tokens = list(
                        itertools.chain(*(self.tokenize(t, is_split_into_words=True, **kwargs) for t in text))
                    )
                    return self.convert_tokens_to_ids(tokens)
                else:
                    return self.convert_tokens_to_ids(text)
            elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
                return text
            else:
                if is_split_into_words:
                    raise ValueError(
                        f"Input {text} is not valid. Should be a string or a list/tuple of strings when"
                        " `is_split_into_words=True`."
                    )
                else:
                    raise ValueError(
                        f"Input {text} is not valid. Should be a string, a list/tuple of strings or a list/tuple of"
                        " integers."
                    )

        if return_offsets_mapping:
            raise NotImplementedError(
                "return_offset_mapping is not available when using Python tokenizers. "
                "To use this feature, change your tokenizer to one deriving from "
                "transformers.PreTrainedTokenizerFast. "
                "More information on available tokenizers at "
                "https://github.com/huggingface/transformers/pull/2674"
            )

        first_ids = get_input_ids(text)
        second_ids = get_input_ids(text_pair) if text_pair is not None else None

        return self.prepare_for_model(
            first_ids,
            pair_ids=second_ids,
            add_special_tokens=add_special_tokens,
            padding=padding_strategy.value,
            truncation=truncation_strategy.value,
            max_length=max_length,
            stride=stride,
            pad_to_multiple_of=pad_to_multiple_of,
            padding_side=padding_side,
            return_tensors=return_tensors,
            prepend_batch_axis=True,
            return_attention_mask=return_attention_mask,
            return_token_type_ids=return_token_type_ids,
            return_overflowing_tokens=return_overflowing_tokens,
            return_special_tokens_mask=return_special_tokens_mask,
            return_length=return_length,
            verbose=verbose,
        )

	...

_encode_plus는 텍스트를 토큰화하고 정수 ID로 변환 하며, 특수 토큰과 데이터를 추가하는 메서드로, PreTrainedTokenizerBase에서 추상 메서드로 정의된다. 

이후 이 메서드는 PreTrainedTokenizer에서 구체적으로 구현되며, BERT나 GPT와 같은 모델별 토크나이저에서 필요에 따라 모델 특징에 맞게 확장된다.

추상 메서드는 공통 인터페이스를 제공하면서도 각 모델의 특화된 동작을 가능하게 한다.

 

📌 정리

PreTrainedTokenizerBase는 여러 모델에서 공통적으로 사용할 수 있는 인터페이스를 제공한다.

_encode_plus는 텍스트를 입력 받아 토큰화, 정수 변환, 특수 토큰 추가, 결과 반환 과정을 정의해야 하지만, 이 과정은 모델 별로 다를 수 있다. 

추상 메서드를 사용하면서 각 모델에 특화된 방식으로 _encode_plus를 구현할 수 있다. 

우리는 일관된 인터페이스 tokenizer(prompt)를 사용하면서도 모델별 최적화된 동작을 활용할 수 있다.

 

 

📌 출처 코드

https://github.com/huggingface/transformers/blob/main/src/transformers/tokenization_utils_base.py#L2788

 

transformers/src/transformers/tokenization_utils_base.py at main · huggingface/transformers

🤗 Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX. - huggingface/transformers

github.com

https://github.com/huggingface/transformers/blob/main/src/transformers/tokenization_utils.py

 

transformers/src/transformers/tokenization_utils.py at main · huggingface/transformers

🤗 Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX. - huggingface/transformers

github.com

 

'Python' 카테고리의 다른 글

[Python] type hinting  (2) 2024.12.09