BERT - BERT tokenizer

SeongGyun Hong·2024년 10월 1일

NLP

목록 보기
2/5

1. BERT tokenizer에서 자주 보는 하이퍼 파라미터

1.1 max_seq_length

정의: 질문, 문맥, 그리고 특별 토큰([CLS], [SEP] 등)을 모두 합한 문자열의 최대 길이이다.

역할: BERT 모델은 입력 시퀀스의 길이가 고정되어 있어야 하기에, max_seq_length는 이 고정된 길이를 설정하는 데 사용된다.

예를 들어, max_seq_length가 384로 설정되어 있다면, 입력 시퀀스는 최대 384개의 토큰으로 제한된다.
만약 입력 시퀀스가 이보다 길다면, 잘라내거나 패딩을 추가하여 길이를 맞춘다.

1.2 doc_stride

정의: 문맥이 너무 길어서 여러 개의 시퀀스로 나눠야 할 때, 각 시퀀스가 겹치는 부분의 길이이다.

역할: 문맥이 max_seq_length보다 길 경우, 문맥을 여러 조각으로 나눠야 한다.

이때, doc_stride는 각 조각이 얼마나 겹칠지를 결정하는데, 예를 들어, doc_stride가 128로 설정되어 있다면, 첫 번째 조각의 끝부분 128 토큰과 두 번째 조각의 시작부분 128 토큰이 겹치게 된다.
이렇게 하면 중요한 정보가 조각 사이에서 손실되지 않도록 보장할 수 있다.

1.3 예시

max_seq_length = 384:
입력 시퀀스는 최대 384개의 토큰으로 제한된다.

doc_stride = 128:
문맥이 너무 길어서 나눠야 할 때, 각 조각이 128개의 토큰만큼 겹치게 된다.


2. BERT tokenizer 예시

model_checkpoint = "bert-base-multilingual-cased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)


tokenized_examples = tokenizer(
        examples["question"],
        examples["context"],
        truncation="only_second",  # Truncate to max_length. This will only truncate the second sequence of a pair.
        max_length=max_seq_length,
        stride=doc_stride,
        return_overflowing_tokens=True, # Whether or not to return overflowing token sequences.
        return_offsets_mapping=True,  # Whether or not to return (char_start, char_end) for each token.
        padding="max_length",
    )

위와 같은 경우에서 코드를 살펴보면

  1. tokenizer
    tokenizer는 텍스트를 토큰으로 변환하는 도구로, 여기서는 질문과 문맥을 받아 토큰화한다.

  2. examples["question"]와 examples["context"]
    각각 질문과 문맥을 나타냄.

  3. truncation="only_second"
    이 옵션은 입력 시퀀스가 max_length를 초과할 경우, 두 번째 시퀀스(즉, 문맥)만 잘라내도록 설정한다.
    즉, 질문은 그대로 유지하고, 문맥만 잘라낸다.

  4. max_length=max_seq_length
    입력 시퀀스의 최대 길이를 max_seq_length로 설정한다. 즉, 모델이 처리할 수 있는 최대 길이를 정하는 것.

  5. stride=doc_stride
    문맥이 너무 길어서 여러 조각으로 나눠야 할 때, 각 조각이 겹치는 부분의 길이를 설정한다.
    예를 들어, doc_stride가 128로 설정되어 있다면, 각 조각이 128개의 토큰만큼 겹치게 된다.

  6. return_overflowing_tokens=True
    이 옵션은 토큰화된 시퀀스가 max_length를 초과할 경우, 초과된 토큰 시퀀스를 반환할지 여부를 설정한다.
    즉, True이면 초과된 토큰 시퀀스도 반환된다.

    예시 상황
    문맥 (Context)
    “서울은 대한민국의 수도입니다. 서울은 한강이 흐르고, 많은 사람들이 살고 있습니다. 서울은 역사적으로 중요한 도시입니다.”

    질문 (Question)
    “대한민국의 수도는 어디인가요?”

    설정
    max_length = 10:
    입력 시퀀스의 최대 길이

    doc_stride = 5:
    문맥이 너무 길어서 나눌 때, 각 시퀀스가 겹치는 부분의 길이

    return_overflowing_tokens = True:
    초과된 토큰 시퀀스를 반환

    토큰화 과정은 이하와 같다

    첫 번째 시퀀스
    입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 서울은 대한민국의 수도입니다. 서울은 [SEP]
    길이: 10 (최대 길이)
    초과된 부분: “한강이 흐르고, 많은 사람들이 살고 있습니다. 서울은 역사적으로 중요한 도시입니다.”

    두 번째 시퀀스
    입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 서울은 한강이 흐르고, 많은 사람들이 [SEP]
    길이: 10 (최대 길이)
    초과된 부분: “살고 있습니다. 서울은 역사적으로 중요한 도시입니다.”

    세 번째 시퀀스
    입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 많은 사람들이 살고 있습니다. 서울은 역사적으로 [SEP]
    길이: 10 (최대 길이)
    초과된 부분: “중요한 도시입니다.”

    네 번째 시퀀스
    입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 서울은 역사적으로 중요한 도시입니다. [SEP]
    길이: 10 (최대 길이)
    초과된 부분: 없음

    결과
    return_overflowing_tokens=True로 설정했기 때문에, 초과된 토큰 시퀀스도 반환되고. 각 시퀀스는 다음과 같이 나눠진다.

    첫 번째 시퀀스: “서울은 대한민국의 수도입니다. 서울은”

    두 번째 시퀀스: “서울은 한강이 흐르고, 많은 사람들이”

    세 번째 시퀀스: “많은 사람들이 살고 있습니다. 서울은”

    네 번째 시퀀스: “서울은 역사적으로 중요한 도시입니다.”

    이렇게 하면 긴 문맥을 여러 조각으로 나눠서 처리할 수 있게 되며, 실질적으로 원래 question과 context로 하나의 시퀀스로 들어갔을 문장이 max_lenght를 초과했기 때문에 해당 초과부분이 잘리는 것이 아니라
    return_overflowing_tokens=True 하이퍼 파라미터에 의해 doc_stride를 고려하여 각 시퀀스가 겹치도록 설정한 채 중요부분에 대한 손실이 없도록 question은 그대로 유지한채 context를 max_legnth와 doc_stride에 맞춰 잘라서 여러개의 입력시퀀스로 만들어 준다.

    앞선 예시의 경우 question-context 쌍 하나로 들어갔지만 실질적으로 총 4쌍이 된 것.

    그래서 실제로 이하와 같은 코드를 실행했을 때

    len(tokenized_examples['input_ids'])
    출력 : 10

    위와 같이 총 10개가 출력될 때가 있는데 만약 내가 입력한 question-context 쌍이 10개 보다 작은데 이렇게 출력된거면 이건 바로 return_overflowing_tokens 옵션이 반영된 결과임.

  7. return_offsets_mapping=True
    이 옵션은 각 토큰의 시작과 끝 위치를 반환할지 여부를 설정한다.
    True로 설정하면, 각 토큰의 문자 단위 시작과 끝 위치를 반환

    예시를 통한 설명
    문맥 (Context)
    “서울은 대한민국의 수도입니다.”

    토큰화 과정
    문맥을 토큰화하면 다음과 같이 된다.:

    토큰: [서울, 은, 대한민국, 의, 수도, 입니다, .]

    여기서 Offset Mapping을 True로 하면 각 토큰의 시작과 끝 위치가 함께 반환 됨.

    예를 들어:

    “서울”: (0, 2)
    “은”: (2, 3)
    “대한민국”: (4, 8)
    “의”: (8, 9)
    “수도”: (10, 12)
    “입니다”: (12, 15)
    “.”: (15, 16)

    위와 같은 형식으로 반환이 됨.

  8. padding="max_length"
    이 옵션은 입력 시퀀스의 길이가 max_length보다 짧을 경우, 패딩을 추가하여 길이를 맞춘다. max_length로 설정하면, 항상 최대 길이로 패딩


tokenized_examples['overflow_to_sample_mapping']
>>> [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]

위와 같은 코드는 tokenizer가 토크나이징한 후 나온 sequence의 출처가 각각 몇번 샘플이 출처인지 밝히는 것.

예시
문맥 (Context)
“서울은 대한민국의 수도입니다. 서울은 한강이 흐르고, 많은 사람들이 살고 있습니다. 서울은 역사적으로 중요한 도시입니다. 서울은 또한 경제적으로도 중요한 역할을 하고 있습니다. 서울의 인구는 약 천만 명에 달합니다. 서울은 다양한 문화와 역사를 가지고 있습니다.”

질문 (Question)
“대한민국의 수도는 어디인가요?”

토큰화 과정
문맥이 max_seq_length를 초과하는 경우를 가정해보면, 이 경우 문맥을 여러 조각으로 나눠야 함.

첫 번째 시퀀스
입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 서울은 대한민국의 수도입니다. 서울은 한강이 흐르고, 많은 사람들이 살고 있습니다. 서울은 역사적으로 중요한 도시입니다. 서울은 또한 경제적으로도 중요한 역할을 하고 있습니다. [SEP]
초과된 부분: “서울의 인구는 약 천만 명에 달합니다. 서울은 다양한 문화와 역사를 가지고 있습니다.”
overflow_to_sample_mapping: 0
두 번째 시퀀스
입력: [CLS] 대한민국의 수도는 어디인가요? [SEP] 서울은 또한 경제적으로도 중요한 역할을 하고 있습니다. 서울의 인구는 약 천만 명에 달합니다. 서울은 다양한 문화와 역사를 가지고 있습니다. [SEP]
초과된 부분: 없음
overflow_to_sample_mapping: 0

정리

위 코드는 질문과 문맥을 토큰화하고, 필요한 경우 잘라내거나 패딩을 추가하여 입력 시퀀스를 max_length로 맞춰준다.
또한, 초과된 토큰 시퀀스를 반환하고, 각 토큰의 시작과 끝 위치를 반환하도록 설정해준다.

profile
헤매는 만큼 자기 땅이다.

0개의 댓글