| |
| |
| |
| |
| |
| |
|
|
| from logging import getLogger |
| import os |
| import numpy as np |
| import torch |
|
|
| from .dataset import StreamDataset, Dataset, ParallelDataset |
| from .dictionary import BOS_WORD, EOS_WORD, PAD_WORD, UNK_WORD, MASK_WORD |
|
|
|
|
| logger = getLogger() |
|
|
|
|
| def process_binarized(data, params): |
| """ |
| Process a binarized dataset and log main statistics. |
| """ |
| dico = data['dico'] |
| assert ((data['sentences'].dtype == np.uint16) and (len(dico) < 1 << 16) or |
| (data['sentences'].dtype == np.int32) and (1 << 16 <= len(dico) < 1 << 31)) |
| logger.info("%i words (%i unique) in %i sentences. %i unknown words (%i unique) covering %.2f%% of the data." % ( |
| len(data['sentences']) - len(data['positions']), |
| len(dico), len(data['positions']), |
| sum(data['unk_words'].values()), len(data['unk_words']), |
| 100. * sum(data['unk_words'].values()) / (len(data['sentences']) - len(data['positions'])) |
| )) |
| if params.max_vocab != -1: |
| assert params.max_vocab > 0 |
| logger.info("Selecting %i most frequent words ..." % params.max_vocab) |
| dico.max_vocab(params.max_vocab) |
| data['sentences'][data['sentences'] >= params.max_vocab] = dico.index(UNK_WORD) |
| unk_count = (data['sentences'] == dico.index(UNK_WORD)).sum() |
| logger.info("Now %i unknown words covering %.2f%% of the data." |
| % (unk_count, 100. * unk_count / (len(data['sentences']) - len(data['positions'])))) |
| if params.min_count > 0: |
| logger.info("Selecting words with >= %i occurrences ..." % params.min_count) |
| dico.min_count(params.min_count) |
| data['sentences'][data['sentences'] >= len(dico)] = dico.index(UNK_WORD) |
| unk_count = (data['sentences'] == dico.index(UNK_WORD)).sum() |
| logger.info("Now %i unknown words covering %.2f%% of the data." |
| % (unk_count, 100. * unk_count / (len(data['sentences']) - len(data['positions'])))) |
| if (data['sentences'].dtype == np.int32) and (len(dico) < 1 << 16): |
| logger.info("Less than 65536 words. Moving data from int32 to uint16 ...") |
| data['sentences'] = data['sentences'].astype(np.uint16) |
| return data |
|
|
|
|
| def load_binarized(path, params): |
| """ |
| Load a binarized dataset. |
| """ |
| assert path.endswith('.pth') |
| if params.debug_train: |
| path = path.replace('train', 'valid') |
| if getattr(params, 'multi_gpu', False): |
| split_path = '%s.%i.pth' % (path[:-4], params.local_rank) |
| if os.path.isfile(split_path): |
| assert params.split_data is False |
| path = split_path |
| assert os.path.isfile(path), path |
| logger.info("Loading data from %s ..." % path) |
| data = torch.load(path) |
| data = process_binarized(data, params) |
| return data |
|
|
|
|
| def set_dico_parameters(params, data, dico): |
| """ |
| Update dictionary parameters. |
| """ |
| if 'dico' in data: |
| assert data['dico'] == dico |
| else: |
| data['dico'] = dico |
|
|
| n_words = len(dico) |
| bos_index = dico.index(BOS_WORD) |
| eos_index = dico.index(EOS_WORD) |
| pad_index = dico.index(PAD_WORD) |
| unk_index = dico.index(UNK_WORD) |
| mask_index = dico.index(MASK_WORD) |
| if hasattr(params, 'bos_index'): |
| assert params.n_words == n_words |
| assert params.bos_index == bos_index |
| assert params.eos_index == eos_index |
| assert params.pad_index == pad_index |
| assert params.unk_index == unk_index |
| assert params.mask_index == mask_index |
| else: |
| params.n_words = n_words |
| params.bos_index = bos_index |
| params.eos_index = eos_index |
| params.pad_index = pad_index |
| params.unk_index = unk_index |
| params.mask_index = mask_index |
|
|
|
|
| def load_mono_data(params, data): |
| """ |
| Load monolingual data. |
| """ |
| data['mono'] = {} |
| data['mono_stream'] = {} |
|
|
| for lang in params.mono_dataset.keys(): |
|
|
| logger.info('============ Monolingual data (%s)' % lang) |
|
|
| assert lang in params.langs and lang not in data['mono'] |
| data['mono'][lang] = {} |
| data['mono_stream'][lang] = {} |
|
|
| for splt in ['train', 'valid', 'test']: |
|
|
| |
| if splt == 'train' and params.eval_only: |
| continue |
|
|
| |
| mono_data = load_binarized(params.mono_dataset[lang][splt], params) |
| set_dico_parameters(params, data, mono_data['dico']) |
|
|
| |
| bs = params.batch_size if splt == 'train' else 1 |
| data['mono_stream'][lang][splt] = StreamDataset(mono_data['sentences'], mono_data['positions'], bs, params) |
|
|
| |
| if splt == 'train' and params.split_data and 1 < params.n_gpu_per_node <= data['mono_stream'][lang][splt].n_batches: |
| n_batches = data['mono_stream'][lang][splt].n_batches // params.n_gpu_per_node |
| a = n_batches * params.local_rank |
| b = n_batches * params.local_rank + n_batches |
| data['mono_stream'][lang][splt].select_data(a, b) |
|
|
| |
| if lang in params.ae_steps or lang in params.bt_src_langs: |
|
|
| |
| dataset = Dataset(mono_data['sentences'], mono_data['positions'], params) |
|
|
| |
| if splt == 'train': |
| dataset.remove_empty_sentences() |
| dataset.remove_long_sentences(params.max_len) |
|
|
| |
| if splt == 'train' and params.n_gpu_per_node > 1 and params.split_data: |
| n_sent = len(dataset) // params.n_gpu_per_node |
| a = n_sent * params.local_rank |
| b = n_sent * params.local_rank + n_sent |
| dataset.select_data(a, b) |
|
|
| data['mono'][lang][splt] = dataset |
|
|
| logger.info("") |
|
|
| logger.info("") |
|
|
|
|
| def load_para_data(params, data): |
| """ |
| Load parallel data. |
| """ |
| data['para'] = {} |
|
|
| required_para_train = set(params.clm_steps + params.mlm_steps + params.pc_steps + params.mt_steps) |
|
|
| for src, tgt in params.para_dataset.keys(): |
|
|
| logger.info('============ Parallel data (%s-%s)' % (src, tgt)) |
|
|
| assert (src, tgt) not in data['para'] |
| data['para'][(src, tgt)] = {} |
|
|
| for splt in ['train', 'valid', 'test']: |
|
|
| |
| if splt == 'train' and params.eval_only: |
| continue |
|
|
| |
| if splt == 'train' and (src, tgt) not in required_para_train and (tgt, src) not in required_para_train: |
| continue |
|
|
| |
| src_path, tgt_path = params.para_dataset[(src, tgt)][splt] |
| src_data = load_binarized(src_path, params) |
| tgt_data = load_binarized(tgt_path, params) |
|
|
| |
| set_dico_parameters(params, data, src_data['dico']) |
| set_dico_parameters(params, data, tgt_data['dico']) |
|
|
| |
| dataset = ParallelDataset( |
| src_data['sentences'], src_data['positions'], |
| tgt_data['sentences'], tgt_data['positions'], |
| params |
| ) |
|
|
| |
| if splt == 'train': |
| dataset.remove_empty_sentences() |
| dataset.remove_long_sentences(params.max_len) |
|
|
| |
| if splt != 'train': |
| dataset.tokens_per_batch = -1 |
|
|
| |
| if splt == 'train' and params.n_gpu_per_node > 1 and params.split_data: |
| n_sent = len(dataset) // params.n_gpu_per_node |
| a = n_sent * params.local_rank |
| b = n_sent * params.local_rank + n_sent |
| dataset.select_data(a, b) |
|
|
| data['para'][(src, tgt)][splt] = dataset |
| logger.info("") |
|
|
| logger.info("") |
|
|
|
|
| def check_data_params(params): |
| """ |
| Check datasets parameters. |
| """ |
| |
| assert os.path.isdir(params.data_path), params.data_path |
|
|
| |
| params.langs = params.lgs.split('-') if params.lgs != 'debug' else ['en'] |
| assert len(params.langs) == len(set(params.langs)) >= 1 |
| |
| params.id2lang = {k: v for k, v in enumerate(sorted(params.langs))} |
| params.lang2id = {k: v for v, k in params.id2lang.items()} |
| params.n_langs = len(params.langs) |
|
|
| |
| clm_steps = [s.split('-') for s in params.clm_steps.split(',') if len(s) > 0] |
| params.clm_steps = [(s[0], None) if len(s) == 1 else tuple(s) for s in clm_steps] |
| assert all([(l1 in params.langs) and (l2 in params.langs or l2 is None) for l1, l2 in params.clm_steps]) |
| assert len(params.clm_steps) == len(set(params.clm_steps)) |
|
|
| |
| mlm_steps = [s.split('-') for s in params.mlm_steps.split(',') if len(s) > 0] |
| params.mlm_steps = [(s[0], None) if len(s) == 1 else tuple(s) for s in mlm_steps] |
| assert all([(l1 in params.langs) and (l2 in params.langs or l2 is None) for l1, l2 in params.mlm_steps]) |
| assert len(params.mlm_steps) == len(set(params.mlm_steps)) |
|
|
| |
| params.pc_steps = [tuple(s.split('-')) for s in params.pc_steps.split(',') if len(s) > 0] |
| assert all([len(x) == 2 for x in params.pc_steps]) |
| assert all([l1 in params.langs and l2 in params.langs for l1, l2 in params.pc_steps]) |
| assert all([l1 != l2 for l1, l2 in params.pc_steps]) |
| assert len(params.pc_steps) == len(set(params.pc_steps)) |
|
|
| |
| params.mt_steps = [tuple(s.split('-')) for s in params.mt_steps.split(',') if len(s) > 0] |
| assert all([len(x) == 2 for x in params.mt_steps]) |
| assert all([l1 in params.langs and l2 in params.langs for l1, l2 in params.mt_steps]) |
| assert all([l1 != l2 for l1, l2 in params.mt_steps]) |
| assert len(params.mt_steps) == len(set(params.mt_steps)) |
| assert len(params.mt_steps) == 0 or not params.encoder_only |
|
|
| |
| params.ae_steps = [s for s in params.ae_steps.split(',') if len(s) > 0] |
| assert all([lang in params.langs for lang in params.ae_steps]) |
| assert len(params.ae_steps) == len(set(params.ae_steps)) |
| assert len(params.ae_steps) == 0 or not params.encoder_only |
|
|
| |
| params.bt_steps = [tuple(s.split('-')) for s in params.bt_steps.split(',') if len(s) > 0] |
| assert all([len(x) == 3 for x in params.bt_steps]) |
| assert all([l1 in params.langs and l2 in params.langs and l3 in params.langs for l1, l2, l3 in params.bt_steps]) |
| assert all([l1 == l3 and l1 != l2 for l1, l2, l3 in params.bt_steps]) |
| assert len(params.bt_steps) == len(set(params.bt_steps)) |
| assert len(params.bt_steps) == 0 or not params.encoder_only |
| params.bt_src_langs = [l1 for l1, _, _ in params.bt_steps] |
|
|
| |
| required_mono = set([l1 for l1, l2 in (params.mlm_steps + params.clm_steps) if l2 is None] + params.ae_steps + params.bt_src_langs) |
| params.mono_dataset = { |
| lang: { |
| splt: os.path.join(params.data_path, '%s.%s.pth' % (splt, lang)) |
| for splt in ['train', 'valid', 'test'] |
| } for lang in params.langs if lang in required_mono |
| } |
| for paths in params.mono_dataset.values(): |
| for p in paths.values(): |
| if not os.path.isfile(p): |
| logger.error(f"{p} not found") |
| assert all([all([os.path.isfile(p) for p in paths.values()]) for paths in params.mono_dataset.values()]) |
|
|
| |
| required_para_train = set(params.clm_steps + params.mlm_steps + params.pc_steps + params.mt_steps) |
| required_para = required_para_train | set([(l2, l3) for _, l2, l3 in params.bt_steps]) |
| params.para_dataset = { |
| (src, tgt): { |
| splt: (os.path.join(params.data_path, '%s.%s-%s.%s.pth' % (splt, src, tgt, src)), |
| os.path.join(params.data_path, '%s.%s-%s.%s.pth' % (splt, src, tgt, tgt))) |
| for splt in ['train', 'valid', 'test'] |
| if splt != 'train' or (src, tgt) in required_para_train or (tgt, src) in required_para_train |
| } for src in params.langs for tgt in params.langs |
| if src < tgt and ((src, tgt) in required_para or (tgt, src) in required_para) |
| } |
| for paths in params.para_dataset.values(): |
| for p1, p2 in paths.values(): |
| if not os.path.isfile(p1): |
| logger.error(f"{p1} not found") |
| if not os.path.isfile(p2): |
| logger.error(f"{p2} not found") |
| assert all([all([os.path.isfile(p1) and os.path.isfile(p2) for p1, p2 in paths.values()]) for paths in params.para_dataset.values()]) |
|
|
| |
| assert params.eval_bleu is False or len(params.mt_steps + params.bt_steps) > 0 |
|
|
|
|
| def load_data(params): |
| """ |
| Load monolingual data. |
| The returned dictionary contains: |
| - dico (dictionary) |
| - vocab (FloatTensor) |
| - train / valid / test (monolingual datasets) |
| """ |
| data = {} |
|
|
| |
| load_mono_data(params, data) |
|
|
| |
| load_para_data(params, data) |
|
|
| |
| logger.info('============ Data summary') |
| for lang, v in data['mono_stream'].items(): |
| for data_set in v.keys(): |
| logger.info('{: <18} - {: >5} - {: >12}:{: >10}'.format('Monolingual data', data_set, lang, len(v[data_set]))) |
|
|
| |
| for (src, tgt), v in data['para'].items(): |
| for data_set in v.keys(): |
| logger.info('{: <18} - {: >5} - {: >12}:{: >10}'.format('Parallel data', data_set, '%s-%s' % (src, tgt), len(v[data_set]))) |
|
|
| logger.info("") |
| return data |
|
|