Spaces:
Runtime error
Runtime error
| import numpy as np | |
| from .constants import ( | |
| QUESTION_COLUMN_NAME, | |
| CONTEXT_COLUMN_NAME, | |
| ANSWER_COLUMN_NAME, | |
| ANSWERABLE_COLUMN_NAME, | |
| ID_COLUMN_NAME, | |
| ) | |
| def get_sketch_features(tokenizer, mode, data_args): | |
| pad_on_right = tokenizer.padding_side == "right" | |
| max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) | |
| def tokenize_fn(examples): | |
| """Tokenize questions and contexts | |
| Args: | |
| examples (Dict): DatasetDict | |
| Returns: | |
| Dict: Tokenized examples | |
| """ | |
| # truncation과 padding을 통해 tokenization을 진행 | |
| # stride를 이용하여 overflow를 유지 | |
| # 각 example들은 이전의 context와 조금씩 겹침 | |
| # overflow 발생 시 지정한 batch size보다 더 많은 sample이 들어올 수 있음 -> data augmentation | |
| tokenized_examples = tokenizer( | |
| examples[QUESTION_COLUMN_NAME if pad_on_right else CONTEXT_COLUMN_NAME], | |
| examples[CONTEXT_COLUMN_NAME if pad_on_right else QUESTION_COLUMN_NAME], | |
| # 길이가 긴 context가 등장할 경우 truncation을 진행 | |
| truncation="only_second" if pad_on_right else "only_first", | |
| max_length=max_seq_length, | |
| stride=data_args.doc_stride, | |
| # overflow 발생 시 원래 인덱스를 찾을 수 있게 mapping 가능한 값이 필요 | |
| return_overflowing_tokens=True, | |
| return_offsets_mapping=False, | |
| # sentence pair가 입력으로 들어올 때 0과 1로 구분지음 | |
| return_token_type_ids=data_args.return_token_type_ids, | |
| padding="max_length" if data_args.pad_to_max_length else False, | |
| # return_tensors='pt' | |
| ) | |
| return tokenized_examples | |
| def prepare_train_features(examples): | |
| tokenized_examples = tokenize_fn(examples) | |
| sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") | |
| tokenized_examples["labels"] = [] | |
| for i in range(len(tokenized_examples["input_ids"])): | |
| # 하나의 example이 여러 개의 span을 가질 수 있음 | |
| sample_index = sample_mapping[i] | |
| # unanswerable label 생성 | |
| # answerable: 0, unanswerable: 1 | |
| is_impossible = examples[ANSWERABLE_COLUMN_NAME][sample_index] | |
| tokenized_examples["labels"].append(0 if not is_impossible else 1) | |
| return tokenized_examples | |
| def prepare_eval_features(examples): | |
| tokenized_examples = tokenize_fn(examples) | |
| sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") | |
| tokenized_examples["example_id"] = [] | |
| tokenized_examples["labels"] = [] | |
| for i in range(len(tokenized_examples["input_ids"])): | |
| # 하나의 example이 여러 개의 span을 가질 수 있음 | |
| sample_index = sample_mapping[i] | |
| id_col = examples[ID_COLUMN_NAME][sample_index] | |
| tokenized_examples["example_id"].append(id_col) | |
| # unanswerable label 생성 | |
| # answerable: 0, unanswerable: 1 | |
| is_impossible = examples[ANSWERABLE_COLUMN_NAME][sample_index] | |
| tokenized_examples["labels"].append(0 if not is_impossible else 1) | |
| return tokenized_examples | |
| def prepare_test_features(examples): | |
| tokenized_examples = tokenize_fn(examples) | |
| sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") | |
| tokenized_examples["example_id"] = [] | |
| for i in range(len(tokenized_examples["input_ids"])): | |
| # 하나의 example이 여러 개의 span을 가질 수 있음 | |
| sample_index = sample_mapping[i] | |
| id_col = examples[ID_COLUMN_NAME][sample_index] | |
| tokenized_examples["example_id"].append(id_col) | |
| return tokenized_examples | |
| if mode == "train": | |
| get_features_fn = prepare_train_features | |
| elif mode == "eval": | |
| get_features_fn = prepare_eval_features | |
| elif mode == "test": | |
| get_features_fn = prepare_test_features | |
| return get_features_fn, True | |
| def get_intensive_features(tokenizer, mode, data_args): | |
| pad_on_right = tokenizer.padding_side == "right" | |
| max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) | |
| beam_based = data_args.intensive_model_type in ["xlnet", "xlm"] | |
| def tokenize_fn(examples): | |
| """Tokenize questions and contexts | |
| Args: | |
| examples (Dict): DatasetDict | |
| Returns: | |
| Dict: Tokenized examples | |
| """ | |
| # truncation과 padding을 통해 tokenization을 진행 | |
| # stride를 이용하여 overflow를 유지 | |
| # 각 example들은 이전의 context와 조금씩 겹침 | |
| # overflow 발생 시 지정한 batch size보다 더 많은 sample이 들어올 수 있음 | |
| tokenized_examples = tokenizer( | |
| examples[QUESTION_COLUMN_NAME if pad_on_right else CONTEXT_COLUMN_NAME], | |
| examples[CONTEXT_COLUMN_NAME if pad_on_right else QUESTION_COLUMN_NAME], | |
| # 길이가 긴 context가 등장할 경우 truncation을 진행 | |
| truncation="only_second" if pad_on_right else "only_first", | |
| max_length=max_seq_length, | |
| stride=data_args.doc_stride, | |
| # overflow 발생 시 원래 인덱스를 찾을 수 있게 mapping 가능한 값이 필요 | |
| return_overflowing_tokens=True, | |
| # token의 캐릭터 단위 position을 찾을 수 있는 offset을 반환 | |
| # start position과 end position을 찾는데 도움을 줌 | |
| return_offsets_mapping=True, | |
| # sentence pair가 입력으로 들어올 때 0과 1로 구분지음 | |
| return_token_type_ids=data_args.return_token_type_ids, | |
| padding="max_length" if data_args.pad_to_max_length else False, | |
| # return_tensors='pt' | |
| ) | |
| return tokenized_examples | |
| def prepare_train_features(examples): | |
| tokenized_examples = tokenize_fn(examples) | |
| # Since one example might give us several features if it has a long context, | |
| # we need a map from a feature to its corresponding example. | |
| # This key gives us just that. | |
| sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") | |
| # The offset mappings will give us a map from token to character position in the original context | |
| # This will help us compute the start_positions and end_positions. | |
| offset_mapping = tokenized_examples.pop("offset_mapping") | |
| # Let's label those exmaples! | |
| tokenized_examples["start_positions"] = [] | |
| tokenized_examples["end_positions"] = [] | |
| tokenized_examples["is_impossibles"] = [] | |
| if beam_based: | |
| tokenized_examples["cls_index"] = [] | |
| tokenized_examples["p_mask"] = [] | |
| for i, offsets in enumerate(offset_mapping): | |
| # We will label impossible answers with the index of the CLS token. | |
| input_ids = tokenized_examples["input_ids"][i] | |
| cls_index = input_ids.index(tokenizer.cls_token_id) | |
| # Grab the sequence corresponding to that example | |
| # (to know what is the context and what is the question.) | |
| sequence_ids = tokenized_examples.sequence_ids(i) | |
| context_index = 1 if pad_on_right else 0 | |
| # `p_mask` which indicates the tokens that can't be in answers | |
| # Build the p_mask: non special tokens and context gets 0.0, the others get 1.0. | |
| # The cls token gets 0.0 too (for predictions of empty answers). | |
| # iInspired by XLNet. | |
| if beam_based: | |
| tokenized_examples["cls_index"].append(cls_index) | |
| tokenized_examples["p_mask"].append( | |
| [ | |
| 0.0 if s == context_index or k == cls_index else 1.0 | |
| for k, s in enumerate(sequence_ids) | |
| ] | |
| ) | |
| # One example can give several spans, | |
| # this is the index of the example containing this span of text. | |
| sample_index = sample_mapping[i] | |
| answers = examples[ANSWER_COLUMN_NAME][sample_index] | |
| is_impossible = examples[ANSWERABLE_COLUMN_NAME][sample_index] | |
| # If no answers are given, set the cls_index as answer. | |
| if is_impossible or len(answers["answer_start"]) == 0: | |
| tokenized_examples["start_positions"].append(cls_index) | |
| tokenized_examples["end_positions"].append(cls_index) | |
| tokenized_examples["is_impossibles"].append(1.0) # unanswerable | |
| else: | |
| # Start/end character index of the answer in the text. | |
| start_char = answers["answer_start"][0] | |
| end_char = start_char + len(answers["text"][0]) | |
| # sequence_ids는 0, 1, None의 세 값만 가짐 | |
| # None 0 0 ... 0 None 1 1 ... 1 None | |
| # Start token index of the current span in the text. | |
| token_start_index = 0 | |
| while sequence_ids[token_start_index] != context_index: | |
| token_start_index += 1 | |
| # End token index of the current span in the text. | |
| token_end_index = len(input_ids) - 1 | |
| while sequence_ids[token_end_index] != context_index: | |
| token_end_index -= 1 | |
| # Detect if the answer is out of the span | |
| # (in which case this feature is labeled with the CLS index.) | |
| if not ( | |
| offsets[token_start_index][0] <= start_char and | |
| offsets[token_end_index][1] >= end_char | |
| ): | |
| tokenized_examples["start_positions"].append(cls_index) | |
| tokenized_examples["end_positions"].append(cls_index) | |
| tokenized_examples["is_impossibles"].append(1.0) # unanswerable | |
| else: | |
| # Otherwise move the token_start_index and token_end_index to the two ends of the answer. | |
| # Note: we could go after the last offset if the answer is the last word (edge case). | |
| while ( | |
| token_start_index < len(offsets) and | |
| offsets[token_start_index][0] <= start_char | |
| ): | |
| token_start_index += 1 | |
| tokenized_examples["start_positions"].append(token_start_index - 1) | |
| while offsets[token_end_index][1] >= end_char: | |
| token_end_index -= 1 | |
| tokenized_examples["end_positions"].append(token_end_index + 1) | |
| tokenized_examples["is_impossibles"].append(0.0) # answerable | |
| return tokenized_examples | |
| def prepare_eval_features(examples): | |
| tokenized_examples = tokenize_fn(examples) | |
| # Since one example might give us several features if it has a long context, | |
| # we need a map from a feature to its corresponding example. | |
| # This key gives us just that. | |
| sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") | |
| # For evaluation, we will need to convert our predictions to substrings of the context, | |
| # so we keep the corresponding example_id and we will store the offset mappings. | |
| tokenized_examples["example_id"] = [] | |
| # We will provide the index of the CLS token ans the p_mask to the model, | |
| # but not the is_impossible label. | |
| if beam_based: | |
| tokenized_examples["cls_index"] = [] | |
| tokenized_examples["p_mask"] = [] | |
| for i, input_ids in enumerate(tokenized_examples["input_ids"]): | |
| # Find the CLS token in the input ids. | |
| cls_index = input_ids.index(tokenizer.cls_token_id) | |
| # Grab the sequence corresponding to that example | |
| # (to know what is the context and what is the question.) | |
| sequence_ids = tokenized_examples.sequence_ids(i) | |
| context_index = 1 if pad_on_right else 0 | |
| # `p_mask` which indicates the tokens that can't be in answers | |
| # Build the p_mask: non special tokens and context gets 0.0, the others get 1.0. | |
| # The cls token gets 0.0 too (for predictions of empty answers). | |
| # iInspired by XLNet. | |
| if beam_based: | |
| tokenized_examples["cls_index"].append(cls_index) | |
| tokenized_examples["p_mask"].append( | |
| [ | |
| 0.0 if s == context_index or k == cls_index else 1.0 | |
| for k, s in enumerate(sequence_ids) | |
| ] | |
| ) | |
| # One example can give several spans, | |
| # this is the index of the example containing this span of text. | |
| sample_index = sample_mapping[i] | |
| id_col = examples[ID_COLUMN_NAME][sample_index] | |
| tokenized_examples["example_id"].append(id_col) | |
| # Set to None the offset_mapping that are note part of the context | |
| # so it's easy to determine if a token position is part of the context or not. | |
| tokenized_examples["offset_mapping"][i] = [ | |
| (o if sequence_ids[k] == context_index else None) | |
| for k, o in enumerate(tokenized_examples["offset_mapping"][i]) | |
| ] | |
| return tokenized_examples | |
| if mode == "train": | |
| get_features_fn = prepare_train_features | |
| elif mode == "eval": | |
| get_features_fn = prepare_eval_features | |
| elif mode == "test": | |
| get_features_fn = prepare_eval_features | |
| return get_features_fn, True |