[MRC] 전처리 코드 분석

hyunsooo·2022년 12월 19일
0
def prepare_train_features(examples):
    # 주어진 텍스트를 토크나이징 한다. 이 때 텍스트의 길이가 max_seq_length를 넘으면 stride만큼 슬라이딩하며 여러 개로 쪼갬.
    # 즉, 하나의 example에서 일부분이 겹치는 여러 sequence(feature)가 생길 수 있음.
    tokenized_examples = tokenizer(
        examples["question"],
        examples["context"],
        truncation="only_second",  # max_seq_length까지 truncate한다. pair의 두번째 파트(context)만 잘라냄.
        max_length=max_seq_length,
        stride=doc_stride,
        return_overflowing_tokens=True, # 길이를 넘어가는 토큰들을 반환할 것인지
        return_offsets_mapping=True,  # 각 토큰에 대해 (char_start, char_end) 정보를 반환한 것인지
        padding="max_length",
    )
    
    # example 하나가 여러 sequence에 대응하는 경우를 위해 매핑이 필요함.
    overflow_to_sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping")
    # offset_mappings으로 토큰이 원본 context 내 몇번째 글자부터 몇번째 글자까지 해당하는지 알 수 있음.
    offset_mapping = tokenized_examples.pop("offset_mapping")

    # 정답지를 만들기 위한 리스트
    tokenized_examples["start_positions"] = []
    tokenized_examples["end_positions"] = []

    for i, offsets in enumerate(offset_mapping):
        input_ids = tokenized_examples["input_ids"][i]
        cls_index = input_ids.index(tokenizer.cls_token_id)
        
        # 해당 example에 해당하는 sequence를 찾음.
        sequence_ids = tokenized_examples.sequence_ids(i)
        
        # sequence가 속하는 example을 찾는다.
        example_index = overflow_to_sample_mapping[i]
        answers = examples["answers"][example_index]
        
        # 텍스트에서 answer의 시작점, 끝점
        answer_start_offset = answers["answer_start"][0]
        answer_end_offset = answer_start_offset + len(answers["text"][0])

        # 텍스트에서 현재 span의 시작 토큰 인덱스
        token_start_index = 0
        while sequence_ids[token_start_index] != 1:
            token_start_index += 1
        
        # 텍스트에서 현재 span 끝 토큰 인덱스
        token_end_index = len(input_ids) - 1
        while sequence_ids[token_end_index] != 1:
            token_end_index -= 1

        # answer가 현재 span을 벗어났는지 체크
        if not (offsets[token_start_index][0] <= answer_start_offset and offsets[token_end_index][1] >= answer_end_offset):
            tokenized_examples["start_positions"].append(cls_index)
            tokenized_examples["end_positions"].append(cls_index)
        else:
            # token_start_index와 token_end_index를 answer의 시작점과 끝점으로 옮김
            while token_start_index < len(offsets) and offsets[token_start_index][0] <= answer_start_offset:
                token_start_index += 1
            tokenized_examples["start_positions"].append(token_start_index - 1)
            while offsets[token_end_index][1] >= answer_end_offset:
                token_end_index -= 1
            tokenized_examples["end_positions"].append(token_end_index + 1)

    return tokenized_examples

tokenizer

truncation

  • True : 긴 시퀀스에서 적절한 길이까지 자른다.

  • "only_first" : 시퀀스 쌍 중 앞의 시퀀스에서 자른다.

  • "only_second" : 시퀀스 쌍 중 뒤의 시퀀스에서 자른다.

stride

MRC task 특성상 질문과 본문 쌍을 사용하게 되는데 두 시퀀스의 쌍이 max length를 넘어갈 경우 데이터를 나눠서 사용하게 된다. 이때 단순히 잘라 사용하게 되면 모델이 문맥의 이해를 못할 수 있기 때문에 적절하게 오버랩하여 데이터를 제공하게 되는데 이때 오버랩 되는 숫자를 제공한다.

Example

"안녕하세요 오늘도 우리는 머신러닝과 딥러닝에 대해서 공부합니다."

  • "안녕하세요 오늘도 우리는 머신러닝과"
  • "우리는 머신러닝과 딥러닝에 대해서 공부합니다."

return_overflowing_tokens

위와 같이 하나의 데이터가 나눠졌을 경우 적절한 매핑을 해주기 위한 인덱스 정보를 반환한다.

offset_mapping

토큰이 원본 context 내 시작 인덱스와 끝 인덱스를 반환한다.

sequence_ids

각 토큰이 question에 속하는지 context에 속하는지 나타낸다. CLS와 PAD는 None값으로 출력된다.

profile
지식 공유

0개의 댓글