Spaces:
Runtime error
Runtime error
| # Copyright 2022 The OFA-Sys Team. | |
| # All rights reserved. | |
| # This source code is licensed under the Apache 2.0 license | |
| # found in the LICENSE file in the root directory. | |
| from io import BytesIO | |
| import math | |
| import logging | |
| import random | |
| import warnings | |
| import numpy as np | |
| import torch | |
| import base64 | |
| from torchvision import transforms | |
| from PIL import Image, ImageFile | |
| from data import data_utils | |
| from data.ofa_dataset import OFADataset | |
| from utils.vision_helper import RandomAugment | |
| import utils.transforms as T | |
| ImageFile.LOAD_TRUNCATED_IMAGES = True | |
| ImageFile.MAX_IMAGE_PIXELS = None | |
| Image.MAX_IMAGE_PIXELS = None | |
| logger = logging.getLogger(__name__) | |
| warnings.filterwarnings("ignore", "(Possibly )?corrupt EXIF data", UserWarning) | |
| def get_whole_word_mask(bpe, dictionary): | |
| if bpe is not None: | |
| def is_beginning_of_word(i): | |
| if i < dictionary.nspecial: | |
| # special elements are always considered beginnings | |
| return True | |
| tok = dictionary[i] | |
| if tok.startswith("madeupword"): | |
| return True | |
| try: | |
| return bpe.is_beginning_of_word(tok) | |
| except ValueError: | |
| return True | |
| mask_whole_words = torch.ByteTensor( | |
| list(map(is_beginning_of_word, range(len(dictionary)))) | |
| ) | |
| return mask_whole_words | |
| return None | |
| def collate(samples, pad_idx, eos_idx): | |
| if len(samples) == 0: | |
| return {} | |
| def merge(key): | |
| return data_utils.collate_tokens( | |
| [s[key] for s in samples], | |
| pad_idx, | |
| eos_idx=eos_idx, | |
| ) | |
| id = np.array([s["id"] for s in samples]) | |
| src_tokens = merge("source") | |
| src_lengths = torch.LongTensor([s["source"].ne(pad_idx).long().sum() for s in samples]) | |
| patch_images = torch.stack([sample['patch_image'] for sample in samples], dim=0) | |
| patch_masks = torch.cat([sample['patch_mask'] for sample in samples]) | |
| code_masks = None | |
| if samples[0].get("code_mask", None) is not None: | |
| code_masks = torch.cat([sample['code_mask'] for sample in samples]) | |
| conf = torch.cat([s['conf'] for s in samples], dim=0) | |
| prev_output_tokens = None | |
| target = None | |
| if samples[0].get("target", None) is not None: | |
| target = merge("target") | |
| tgt_lengths = torch.LongTensor([s["target"].ne(pad_idx).long().sum() for s in samples]) | |
| ntokens = tgt_lengths.sum().item() | |
| if samples[0].get("prev_output_tokens", None) is not None: | |
| prev_output_tokens = merge("prev_output_tokens") | |
| else: | |
| ntokens = src_lengths.sum().item() | |
| batch = { | |
| "id": id, | |
| "nsentences": len(samples), | |
| "ntokens": ntokens, | |
| "net_input": { | |
| "src_tokens": src_tokens, | |
| "src_lengths": src_lengths, | |
| "patch_images": patch_images, | |
| "patch_masks": patch_masks, | |
| "code_masks": code_masks, | |
| "prev_output_tokens": prev_output_tokens | |
| }, | |
| "target": target, | |
| "conf": conf | |
| } | |
| return batch | |
| class UnifyDataset(OFADataset): | |
| def __init__( | |
| self, | |
| split, | |
| dataset, | |
| bpe, | |
| src_dict, | |
| tgt_dict=None, | |
| max_src_length=128, | |
| max_tgt_length=30, | |
| seed=7, | |
| code_dict_size=8192, | |
| num_bins=1000, | |
| patch_image_size=384, | |
| code_image_size=128, | |
| pure_text_dataset=None, | |
| pure_image_dataset=None, | |
| detection_dataset=None, | |
| all_object_list=None, | |
| all_caption_list=None, | |
| type2ans_dict=None, | |
| ans2type_dict=None, | |
| max_image_size=512, | |
| mask_ratio=0.3, | |
| random_ratio=0.0, | |
| keep_ratio=0.0, | |
| mask_length="span-poisson", | |
| poisson_lambda=3.0, | |
| replace_length=1 | |
| ): | |
| super().__init__(split, dataset, bpe, src_dict, tgt_dict) | |
| self.max_src_length = max_src_length | |
| self.max_tgt_length = max_tgt_length | |
| self.seed = seed | |
| self.code_dict_size = code_dict_size | |
| self.num_bins = num_bins | |
| self.patch_image_size = patch_image_size | |
| self.code_image_size = code_image_size | |
| self.pure_text_dataset = pure_text_dataset | |
| self.pure_image_dataset = pure_image_dataset | |
| self.detection_dataset = detection_dataset | |
| self.epoch = 0 | |
| self.all_object_list = all_object_list | |
| self.all_caption_list = all_caption_list | |
| self.type2ans_dict = type2ans_dict | |
| self.ans2type_dict = ans2type_dict | |
| self.mask_ratio = mask_ratio | |
| self.random_ratio = random_ratio | |
| self.keep_ratio = keep_ratio | |
| self.mask_length = mask_length | |
| self.poisson_lambda = poisson_lambda | |
| self.replace_length = replace_length | |
| if self.replace_length not in [-1, 0, 1]: | |
| raise ValueError(f"invalid arg: replace_length={self.replace_length}") | |
| if self.mask_length not in ["subword", "word", "span-poisson"]: | |
| raise ValueError(f"invalid arg: mask-length={self.mask_length}") | |
| if self.mask_length == "subword" and self.replace_length not in [0, 1]: | |
| raise ValueError(f"if using subwords, use replace-length=1 or 0") | |
| self.mask_idx = src_dict.index("<mask>") | |
| self.mask_whole_word = ( | |
| get_whole_word_mask(self.bpe, self.src_dict) | |
| if self.mask_length != "subword" | |
| else None | |
| ) | |
| self.mask_span_distribution = None | |
| if self.mask_length == "span-poisson": | |
| _lambda = self.poisson_lambda | |
| lambda_to_the_k = 1 | |
| e_to_the_minus_lambda = math.exp(-_lambda) | |
| k_factorial = 1 | |
| ps = [] | |
| for k in range(0, 128): | |
| ps.append(e_to_the_minus_lambda * lambda_to_the_k / k_factorial) | |
| lambda_to_the_k *= _lambda | |
| k_factorial *= k + 1 | |
| if ps[-1] < 0.0000001: | |
| break | |
| ps = torch.FloatTensor(ps) | |
| self.mask_span_distribution = torch.distributions.Categorical(ps) | |
| self.pos_tgt_item = self.encode_text(" yes") | |
| self.neg_tgt_item = self.encode_text(" no") | |
| self.mask_left = self.mask_top = int(0.5 * self.code_image_size) | |
| self.mask_right = self.mask_bottom = int(1.5 * self.code_image_size) | |
| self.mask_ids = [ | |
| i*self.code_image_size*2+j | |
| for i in range(self.code_image_size*2) for j in range(self.code_image_size*2) | |
| if not (self.mask_left <= i < self.mask_right and self.mask_top <= j < self.mask_bottom) | |
| ] | |
| scales = np.arange(patch_image_size, 481).tolist() | |
| # for image-text pair | |
| self.patch_resize_transform = transforms.Compose([ | |
| T.RandomResize(scales, max_size=672), | |
| transforms.CenterCrop(patch_image_size), | |
| RandomAugment(2, 7, isPIL=True, augs=['Identity', 'AutoContrast', 'Equalize', 'Brightness', 'Sharpness', | |
| 'ShearX', 'ShearY', 'TranslateX', 'TranslateY', 'Rotate']), | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]), | |
| ]) | |
| # for pure image | |
| self.patch_crop_transform = transforms.Compose([ | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]), | |
| ]) | |
| # for detection | |
| self.detection_transform = T.Compose([ | |
| T.RandomHorizontalFlip(), | |
| T.LargeScaleJitter(output_size=self.code_image_size*2, aug_scale_min=1.0, aug_scale_max=1.5), | |
| T.ToTensor(), | |
| T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], max_image_size=max_image_size) | |
| ]) | |
| # for visual grounding | |
| self.visual_grounding_transform = T.Compose([ | |
| T.RandomResize(scales, max_size=672), | |
| T.ObjectCenterCrop((patch_image_size, patch_image_size)), | |
| T.ToTensor(), | |
| T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], max_image_size=max_image_size) | |
| ]) | |
| def set_epoch(self, epoch, **unused): | |
| self.epoch = epoch | |
| def get_negative_caption(self, caption, gt_objects): | |
| prob = random.random() | |
| if gt_objects is not None and gt_objects != '' and prob > 0.6: | |
| gt_object = random.choice(gt_objects.strip().split('&&')) | |
| negative_object = random.choice(self.all_object_list[:-1]) | |
| negative_object = self.all_object_list[-1] if negative_object == gt_object else negative_object | |
| negative_caption = caption.replace(gt_object, negative_object) | |
| else: | |
| negative_caption = random.choice(self.all_caption_list) | |
| return negative_caption | |
| def get_negative_answer(self, answer, conf): | |
| prob = random.random() | |
| if conf > (prob + 0.1) and answer in self.ans2type_dict: | |
| negative_answer_type = self.ans2type_dict[answer] | |
| if negative_answer_type == 'how many' and answer.isdigit() and prob > 0.5: | |
| negative_answer = int(answer) + random.choice([-1, 1]) if answer != 0 else 1 | |
| else: | |
| negative_answer_list = self.type2ans_dict[negative_answer_type] | |
| negative_answer = random.choice(negative_answer_list[:-1]) | |
| negative_answer = negative_answer_list[-1] if negative_answer == answer else negative_answer | |
| return negative_answer | |
| negative_answer_list = self.type2ans_dict['other'] | |
| negative_answer = random.choice(negative_answer_list[:-1]) | |
| negative_answer = negative_answer_list[-1] if negative_answer == answer else negative_answer | |
| return negative_answer | |
| def process_image_text_pair(self, index): | |
| uniq_id, image, caption, question, refs, gt_objects, dataset_name, type = self.dataset[index] | |
| image = Image.open(BytesIO(base64.urlsafe_b64decode(image))).convert("RGB") | |
| patch_image = self.patch_resize_transform(image) if type != 'visual_grounding' else None | |
| patch_mask = torch.tensor([True]) | |
| conf = torch.tensor([1.0]) | |
| if type == 'caption': | |
| tgt_caption = self.pre_caption(caption, self.max_tgt_length) | |
| pos_src_caption = self.pre_caption(caption, self.max_src_length) | |
| neg_src_caption = self.pre_caption(self.get_negative_caption(caption, gt_objects), self.max_src_length) | |
| src_item = self.encode_text(" what does the image describe?") | |
| tgt_item = self.encode_text(" {}".format(tgt_caption)) | |
| pos_src_item = self.encode_text(' does the image describe " {} "?'.format(pos_src_caption)) | |
| neg_src_item = self.encode_text(' does the image describe " {} "?'.format(neg_src_caption)) | |
| elif type == 'qa': | |
| question = self.pre_question(question, self.max_src_length) | |
| ref_dict = {item.split('|!+')[1]: float(item.split('|!+')[0]) for item in refs.split('&&')} | |
| answer = max(ref_dict, key=ref_dict.get) | |
| conf = ref_dict[answer] | |
| src_item = self.encode_text(" {}".format(question)) | |
| tgt_item = self.encode_text(" {}".format(answer)) | |
| conf = torch.tensor([conf]) | |
| pos_src_item = self.encode_text(' what is the answer to question " {} ". is " {} "?'.format(question, answer)) | |
| neg_src_item = self.encode_text( | |
| ' what is the answer to question " {} ". is " {} "?'.format(question, self.get_negative_answer(answer, conf)) | |
| ) | |
| elif type == 'visual_grounding': | |
| conf = torch.tensor([1.0]) | |
| w, h = image.size | |
| boxes_target = {"boxes": [], "labels": [], "area": [], "size": torch.tensor([h, w])} | |
| x0, y0, x1, y1 = refs.strip().split(',') | |
| boxes_target["boxes"] = torch.tensor([[float(x0), float(y0), float(x1), float(y1)]]) | |
| boxes_target["labels"] = np.array([0]) | |
| boxes_target["area"] = torch.tensor([(float(x1) - float(x0)) * (float(y1) - float(y0))]) | |
| patch_image, boxes_target = self.visual_grounding_transform(image, boxes_target) | |
| quant_x0 = "<bin_{}>".format(int((boxes_target["boxes"][0][0] * (self.num_bins - 1)).round())) | |
| quant_y0 = "<bin_{}>".format(int((boxes_target["boxes"][0][1] * (self.num_bins - 1)).round())) | |
| quant_x1 = "<bin_{}>".format(int((boxes_target["boxes"][0][2] * (self.num_bins - 1)).round())) | |
| quant_y1 = "<bin_{}>".format(int((boxes_target["boxes"][0][3] * (self.num_bins - 1)).round())) | |
| region_coord = "{} {} {} {}".format(quant_x0, quant_y0, quant_x1, quant_y1) | |
| src_caption = self.pre_caption(caption, self.max_src_length) | |
| src_item = self.encode_text(' which region does the text " {} " describe?'.format(src_caption)) | |
| tgt_item = self.encode_text(region_coord, use_bpe=False) | |
| else: | |
| logger.info('type {} is not implemented'.format(type)) | |
| raise NotImplementedError | |
| src_item = torch.cat([self.bos_item, src_item, self.eos_item]) | |
| target_item = torch.cat([tgt_item, self.eos_item]) | |
| prev_output_item = torch.cat([self.bos_item, tgt_item]) | |
| pos_src_item = torch.cat([self.bos_item, pos_src_item, self.eos_item]) if type != 'visual_grounding' else None | |
| neg_src_item = torch.cat([self.bos_item, neg_src_item, self.eos_item]) if type != 'visual_grounding' else None | |
| if type == 'caption' and dataset_name == 'cc12m': | |
| target_item[:2] = self.src_dict.pad() | |
| target_item[-1] = self.eos_item | |
| example = { | |
| "id": uniq_id, | |
| "source": src_item, | |
| "patch_image": patch_image, | |
| "patch_mask": patch_mask, | |
| "target": target_item, | |
| "prev_output_tokens": prev_output_item, | |
| "conf": conf, | |
| } | |
| examples = [example] | |
| prob = random.random() | |
| if type == 'visual_grounding': | |
| region_example = example.copy() | |
| region_prefix_item = self.encode_text(' what does the region describe? region:') | |
| region_coord_item = self.encode_text('{}'.format(region_coord), use_bpe=False) | |
| region_src_item = torch.cat([region_prefix_item, region_coord_item]) | |
| region_tgt_item = self.encode_text(' {}'.format(self.pre_caption(caption, self.max_tgt_length))) | |
| region_example["source"] = torch.cat([self.bos_item, region_src_item, self.eos_item]) | |
| region_example["target"] = torch.cat([region_tgt_item, self.eos_item]) | |
| region_example["prev_output_tokens"] = torch.cat([self.bos_item, region_tgt_item]) | |
| region_example["conf"] = torch.tensor([1.0]) | |
| examples.append(region_example) | |
| elif prob >= 0.5 and self.split == 'train': | |
| pos_example = example.copy() | |
| pos_example["source"] = pos_src_item | |
| pos_example["target"] = torch.cat([self.pos_tgt_item, self.eos_item]) | |
| pos_example["prev_output_tokens"] = torch.cat([self.bos_item, self.pos_tgt_item]) | |
| examples.append(pos_example) | |
| elif self.split == 'train': | |
| neg_example = example.copy() | |
| neg_example["source"] = neg_src_item | |
| neg_example["target"] = torch.cat([self.neg_tgt_item, self.eos_item]) | |
| neg_example["prev_output_tokens"] = torch.cat([self.bos_item, self.neg_tgt_item]) | |
| examples.append(neg_example) | |
| return examples | |
| def process_pure_text(self, index): | |
| patch_image = torch.zeros((3, self.code_image_size*2, self.code_image_size*2)) | |
| patch_mask = torch.tensor([False]) | |
| code_mask = torch.tensor([False]) | |
| conf = torch.tensor([2.0]) | |
| examples = [] | |
| for _ in range(2): | |
| uniq_id, text = self.pure_text_dataset[index] | |
| text = text.strip().lower() | |
| text_item = self.encode_text(" {}".format(text), length=512) | |
| text_item = text_item[-256:] | |
| text_item = torch.cat([self.bos_item, text_item, self.eos_item]) | |
| mask_text_item = self.add_whole_word_mask(text_item.clone(), self.mask_ratio) | |
| prefix_item = self.encode_text(' what is the complete text of " "?') | |
| src_item = torch.cat([prefix_item[:-2], mask_text_item[1:-1], prefix_item[-2:]]) | |
| tgt_item = text_item[1:-1] | |
| src_item = torch.cat([self.bos_item, src_item, self.eos_item]) | |
| target_item = torch.cat([tgt_item, self.eos_item]) | |
| prev_output_item = torch.cat([self.bos_item, tgt_item]) | |
| example = { | |
| "id": uniq_id, | |
| "source": src_item, | |
| "patch_image": patch_image, | |
| "patch_mask": patch_mask, | |
| "code_mask": code_mask, | |
| "target": target_item, | |
| "prev_output_tokens": prev_output_item, | |
| "conf": conf, | |
| } | |
| examples.append(example) | |
| return examples | |
| def process_pure_image(self, index): | |
| image_id, image, code = self.pure_image_dataset[index] | |
| image = Image.open(BytesIO(base64.urlsafe_b64decode(image))).convert("RGB") | |
| patch_image = self.patch_crop_transform(image) | |
| patch_image[:, self.mask_top:self.mask_bottom, self.mask_left:self.mask_right] = 0 | |
| patch_mask = torch.tensor([True]) | |
| src_item = self.encode_text(" what is the image in the middle part?") | |
| image_code = torch.LongTensor([int(num) for num in code.strip().split()]) | |
| tgt_item = image_code + len(self.src_dict) - self.code_dict_size - self.num_bins | |
| code_mask = torch.tensor([True]) | |
| conf = torch.tensor([2.0]) | |
| src_item = torch.cat([self.bos_item, src_item, self.eos_item]) | |
| target_item = torch.cat([tgt_item, self.eos_item]) | |
| prev_output_item = torch.cat([self.bos_item, tgt_item]) | |
| example = { | |
| "id": image_id, | |
| "source": src_item, | |
| "patch_image": patch_image, | |
| "patch_mask": patch_mask, | |
| "code_mask": code_mask, | |
| "target": target_item, | |
| "prev_output_tokens": prev_output_item, | |
| "conf": conf, | |
| } | |
| return [example] | |
| def process_detection(self, index): | |
| image_id, image, label = self.detection_dataset[index] | |
| image = Image.open(BytesIO(base64.urlsafe_b64decode(image))).convert("RGB") | |
| w, h = image.size | |
| boxes_target = {"boxes": [], "labels": [], "area": [], "size": torch.tensor([h, w])} | |
| label_list = label.strip().split('&&') | |
| for label in label_list: | |
| x0, y0, x1, y1, cat_id, cat = label.strip().split(',', 5) | |
| boxes_target["boxes"].append([float(x0), float(y0), float(x1), float(y1)]) | |
| boxes_target["labels"].append(cat) | |
| boxes_target["area"].append((float(x1) - float(x0)) * (float(y1) - float(y0))) | |
| boxes_target["boxes"] = torch.tensor(boxes_target["boxes"]) | |
| boxes_target["labels"] = np.array(boxes_target["labels"]) | |
| boxes_target["area"] = torch.tensor(boxes_target["area"]) | |
| patch_image, boxes_target = self.detection_transform(image, boxes_target) | |
| patch_mask = torch.tensor([True]) | |
| code_mask = torch.tensor([False]) | |
| conf = torch.tensor([2.0]) | |
| quant_boxes = [] | |
| for i, box in enumerate(boxes_target["boxes"]): | |
| quant_boxes.extend(["<bin_{}>".format(int((pos * (self.num_bins - 1)).round())) for pos in box[:4]]) | |
| quant_boxes.append(self.bpe.encode(' {}'.format(boxes_target["labels"][i]))) | |
| src_item = self.encode_text(' what are the objects in the image?') | |
| tgt_item = self.encode_text(' '.join(quant_boxes), use_bpe=False) | |
| src_item = torch.cat([self.bos_item, src_item, self.eos_item]) | |
| target_item = torch.cat([tgt_item, self.eos_item]) | |
| prev_output_item = torch.cat([self.bos_item, tgt_item]) | |
| example = { | |
| "id": image_id, | |
| "source": src_item, | |
| "patch_image": patch_image, | |
| "patch_mask": patch_mask, | |
| "code_mask": code_mask, | |
| "target": target_item, | |
| "prev_output_tokens": prev_output_item, | |
| "conf": conf, | |
| } | |
| return [example] | |
| def __getitem__(self, index): | |
| with data_utils.numpy_seed(self.seed, self.epoch): | |
| pair_samples = self.process_image_text_pair(index) | |
| extra_samples = [] | |
| if self.split == 'train' and self.dataset.data_cnt % 8 == 0: | |
| extra_samples += self.process_pure_text(0) if self.pure_text_dataset else [] | |
| extra_samples += self.process_pure_image(0) if self.pure_image_dataset else [] | |
| extra_samples += self.process_detection(0) if self.detection_dataset else [] | |
| return pair_samples, extra_samples | |
| def word_starts(self, source): | |
| if self.mask_whole_word is not None: | |
| is_word_start = self.mask_whole_word.gather(0, source) | |
| else: | |
| is_word_start = torch.ones(source.size()) | |
| is_word_start[0] = 0 | |
| is_word_start[-1] = 0 | |
| return is_word_start | |
| def add_whole_word_mask(self, source, p): | |
| is_word_start = self.word_starts(source) | |
| num_to_mask = int(math.ceil(is_word_start.float().sum() * p)) | |
| num_inserts = 0 | |
| if num_to_mask == 0: | |
| return source | |
| if self.mask_span_distribution is not None: | |
| lengths = self.mask_span_distribution.sample(sample_shape=(num_to_mask,)) | |
| # Make sure we have enough to mask | |
| cum_length = torch.cumsum(lengths, 0) | |
| while cum_length[-1] < num_to_mask: | |
| lengths = torch.cat( | |
| [ | |
| lengths, | |
| self.mask_span_distribution.sample(sample_shape=(num_to_mask,)), | |
| ], | |
| dim=0, | |
| ) | |
| cum_length = torch.cumsum(lengths, 0) | |
| # Trim to masking budget | |
| i = 0 | |
| while cum_length[i] < num_to_mask: | |
| i += 1 | |
| lengths[i] = num_to_mask - (0 if i == 0 else cum_length[i - 1]) | |
| num_to_mask = i + 1 | |
| lengths = lengths[:num_to_mask] | |
| # Handle 0-length mask (inserts) separately | |
| lengths = lengths[lengths > 0] | |
| num_inserts = num_to_mask - lengths.size(0) | |
| num_to_mask -= num_inserts | |
| if num_to_mask == 0: | |
| return self.add_insertion_noise(source, num_inserts / source.size(0)) | |
| assert (lengths > 0).all() | |
| else: | |
| lengths = torch.ones((num_to_mask,)).long() | |
| assert is_word_start[-1] == 0 | |
| word_starts = is_word_start.nonzero(as_tuple=False) | |
| indices = word_starts[ | |
| torch.randperm(word_starts.size(0))[:num_to_mask] | |
| ].squeeze(1) | |
| mask_random = torch.FloatTensor(num_to_mask).uniform_() < self.random_ratio | |
| source_length = source.size(0) | |
| assert source_length - 1 not in indices | |
| to_keep = torch.ones(source_length, dtype=torch.bool) | |
| is_word_start[ | |
| -1 | |
| ] = 255 # acts as a long length, so spans don't go over the end of doc | |
| if self.replace_length == 0: | |
| to_keep[indices] = 0 | |
| else: | |
| # keep index, but replace it with [MASK] | |
| source[indices] = self.mask_idx | |
| source[indices[mask_random]] = torch.randint( | |
| 4, len(self.tgt_dict) - self.code_dict_size - self.num_bins, size=(mask_random.sum(),) | |
| ) | |
| if self.mask_span_distribution is not None: | |
| assert len(lengths.size()) == 1 | |
| assert lengths.size() == indices.size() | |
| lengths -= 1 | |
| while indices.size(0) > 0: | |
| assert lengths.size() == indices.size() | |
| lengths -= is_word_start[indices + 1].long() | |
| uncompleted = lengths >= 0 | |
| indices = indices[uncompleted] + 1 | |
| mask_random = mask_random[uncompleted] | |
| lengths = lengths[uncompleted] | |
| if self.replace_length != -1: | |
| # delete token | |
| to_keep[indices] = 0 | |
| else: | |
| # keep index, but replace it with [MASK] | |
| source[indices] = self.mask_idx | |
| source[indices[mask_random]] = torch.randint( | |
| 4, len(self.tgt_dict) - self.code_dict_size - self.num_bins, size=(mask_random.sum(),) | |
| ) | |
| else: | |
| # A bit faster when all lengths are 1 | |
| while indices.size(0) > 0: | |
| uncompleted = is_word_start[indices + 1] == 0 | |
| indices = indices[uncompleted] + 1 | |
| mask_random = mask_random[uncompleted] | |
| if self.replace_length != -1: | |
| # delete token | |
| to_keep[indices] = 0 | |
| else: | |
| # keep index, but replace it with [MASK] | |
| source[indices] = self.mask_idx | |
| source[indices[mask_random]] = torch.randint( | |
| 4, len(self.tgt_dict) - self.code_dict_size - self.num_bins, size=(mask_random.sum(),) | |
| ) | |
| assert source_length - 1 not in indices | |
| source = source[to_keep] | |
| if num_inserts > 0: | |
| source = self.add_insertion_noise(source, num_inserts / source.size(0)) | |
| return source | |
| def add_insertion_noise(self, tokens, p): | |
| if p == 0.0: | |
| return tokens | |
| num_tokens = len(tokens) | |
| n = int(math.ceil(num_tokens * p)) | |
| noise_indices = torch.randperm(num_tokens + n - 2)[:n] + 1 | |
| noise_mask = torch.zeros(size=(num_tokens + n,), dtype=torch.bool) | |
| noise_mask[noise_indices] = 1 | |
| result = torch.LongTensor(n + len(tokens)).fill_(-1) | |
| num_random = int(math.ceil(n * self.random_ratio)) | |
| result[noise_indices[num_random:]] = self.mask_idx | |
| result[noise_indices[:num_random]] = torch.randint( | |
| low=4, high=len(self.tgt_dict)-self.code_dict_size-self.num_bins, size=(num_random,) | |
| ) | |
| result[~noise_mask] = tokens | |
| assert (result >= 0).all() | |
| return result | |
| def collater(self, samples, pad_to_length=None): | |
| """Merge samples of different tasks to form two mini-batches. | |
| Args: | |
| samples (List[Tuple]): samples to collate | |
| Returns: | |
| Tuple[dict]: two mini-batch containing the data of different tasks | |
| """ | |
| samples_v1 = [] # containing image-text pairs | |
| samples_v2 = [] # containing detection data, text data and image data | |
| for sample_tuple in samples: | |
| samples_v1 += sample_tuple[0] | |
| samples_v2 += sample_tuple[1] | |
| if samples_v2 != []: | |
| res_v1 = collate(samples_v1, pad_idx=self.src_dict.pad(), eos_idx=self.eos) | |
| res_v2 = collate(samples_v2, pad_idx=self.src_dict.pad(), eos_idx=self.eos) | |
| return res_v1, res_v2 | |
| else: | |
| res_v1 = collate(samples_v1, pad_idx=self.src_dict.pad(), eos_idx=self.eos) | |
| return res_v1 | |