文章目录

  • 前言
  • 数据准备
    • 数据下载
    • 数据预处理(iwslt14_preprocess_subwordnmt_old_version)
  • 模型训练
  • 补充
    • 补充一:Key error while accessing batch_iterator.first_batch
  • 参考

前言

笔者尝试复现LaSS工作,由于该工作所做的第一步就是训练一个多语言机器翻译模型,故记录在此,本文主要内容是数据准备的步骤。

数据准备

实验使用iwslt 14中的8个以英语为中心的语言对,完成16个方向的多语言机器翻译。目前使用该数据集是因为其数据量相对较小,模型训练速度较快,笔者觉得比较适合用于机器翻译上手、比较不同模型性能的优劣。数据集的统计信息如下图所示:

下面介绍数据的下载和预处理。假设现在的所在目录为/data/syxu/data/data_store/iwslt14

数据下载

从https://wit3.fbk.eu/2014-01链接中下载得到2014-01.tgz文件夹,保存至当前目录,tar zxvf 2014-01.tgz进行文件解压缩。2014-01中的内容如下:

使用cp -r 2014-01/texts/*/en/*-en.tgz .将需要使用到的压缩文件提取到当前目录,得到:

数据预处理(iwslt14_preprocess_subwordnmt_old_version)

bash prepare-iwslt14.sh

数据预处理部分的脚本代码参照LaSS和multilingual-kd-pytorch。
具体来说,首先在当前目录下创建预处理脚本文件:prepare-iwslt14.sh和preprocess_multilingual.py,这两个文件各自的代码如下:

  • prepare-iwslt14.sh
#!/usr/bin/env bash
#
# Adapted from https://github.com/facebookresearch/MIXER/blob/master/prepareData.sh
echo 'Cloning Moses github repository (for tokenization scripts)...'
git clone https://github.com/moses-smt/mosesdecoder.gitecho 'Cloning Subword NMT repository (for BPE pre-processing)...'
git clone https://github.com/rsennrich/subword-nmt.gitSCRIPTS=mosesdecoder/scripts
TOKENIZER=$SCRIPTS/tokenizer/tokenizer.perl
LC=$SCRIPTS/tokenizer/lowercase.perl
CLEAN=$SCRIPTS/training/clean-corpus-n.perl
BPEROOT=subword-nmt
BPE_TOKENS=30000
prep=iwslt14.tokenized
tmp=$prep/tmp
orig=orig
rm -r $orig
rm -r $tmp
rm -r $prep
mkdir -p $orig $tmp $prepfor src in ar de es fa he it nl pl; dotgt=enlang=$src-enecho "pre-processing train data..."for l in $src $tgt; doif [[ ! -f $src-en.tgz ]]; thenwget https://wit3.fbk.eu/archive/2014-01//texts/$src/en/$src-en.tgzficd $origtar zxvf ../$src-en.tgzcd ..f=train.tags.$lang.$ltok=train.tags.$lang.tok.$lcat $orig/$lang/$f | \grep -v '<url>' | \grep -v '<talkid>' | \grep -v '<keywords>' | \sed -e 's/<title>//g' | \sed -e 's/<\/title>//g' | \sed -e 's/<description>//g' | \sed -e 's/<\/description>//g' | \perl $TOKENIZER -threads 8 -l $l > $tmp/$tokecho ""doneperl $CLEAN -ratio 1.5 $tmp/train.tags.$lang.tok $src $tgt $tmp/train.tags.$lang.clean 1 175for l in $src $tgt; doperl $LC < $tmp/train.tags.$lang.clean.$l > $tmp/train.tags.$lang.$ldoneecho "pre-processing valid/test data..."for l in $src $tgt; dofor o in `ls $orig/$lang/IWSLT14.TED*.$l.xml`; dofname=${o##*/}f=$tmp/${fname%.*}echo $o $fgrep '<seg id' $o | \sed -e 's/<seg id="[0-9]*">\s*//g' | \sed -e 's/\s*<\/seg>\s*//g' | \sed -e "s/\’/\'/g" | \perl $TOKENIZER -threads 8 -l $l | \perl $LC > $fecho ""donedoneecho "creating train, valid, test..."for l in $src $tgt; doawk '{if (NR%23 == 0)  print $0; }' $tmp/train.tags.$src-$tgt.$l > $tmp/valid.en-$src.$lawk '{if (NR%23 != 0)  print $0; }' $tmp/train.tags.$src-$tgt.$l > $tmp/train.en-$src.$lcat $tmp/IWSLT14.TED.dev2010.$src-$tgt.$l \$tmp/IWSLT14.TEDX.dev2012.$src-$tgt.$l \$tmp/IWSLT14.TED.tst2010.$src-$tgt.$l \$tmp/IWSLT14.TED.tst2011.$src-$tgt.$l \$tmp/IWSLT14.TED.tst2012.$src-$tgt.$l \> $tmp/test.en-$src.$ldoneTRAIN=$tmp/train.allBPE_CODE=$prep/coderm -f $TRAINfor l in $src $tgt; docat $tmp/train.en-$src.$l >> $TRAINdone
done
echo "learn_bpe.py on ${TRAIN}..."
python $BPEROOT/learn_bpe.py -s $BPE_TOKENS < $TRAIN > $BPE_CODEfor src in ar de es fa he it nl pl; dofor L in $src $tgt; dofor f in train.en-$src.$L valid.en-$src.$L test.en-$src.$L; doecho "apply_bpe.py to ${f}..."python $BPEROOT/apply_bpe.py -c $BPE_CODE < $tmp/$f > $prep/$fdonedone
donerm -r text
mkdir -p text/train_data
mkdir -p text/valid_data
mkdir -p text/test_data
cp iwslt14.tokenized/train.en-* text/train_data/
cp iwslt14.tokenized/valid.en-* text/valid_data/
cp iwslt14.tokenized/test.en-* text/test_data/
cd ..
python iwslt14/preprocess_multilingual.py --pref=iwslt14/  --joined-dictionary
  • preprocess_multilingual.py
#!/usr/bin/env python3
# Copyright (c) 2017-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the license found in the LICENSE file in
# the root directory of this source tree. An additional grant of patent rights
# can be found in the PATENTS file in the same directory.
"""
Data pre-processing: build vocabularies and binarize training data.
"""import argparse
import glob
import json
import random
from collections import Counter
from itertools import zip_longest
import os
import shutilfrom fairseq.data import indexed_dataset, dictionary
from fairseq.tokenizer import Tokenizer, tokenize_line
from multiprocessing import Pool, Manager, Processdef get_parser():parser = argparse.ArgumentParser()parser.add_argument('--pref', metavar='FP', default=None, help='data prefix')parser.add_argument('--no-dict', action='store_true', help='do not build dictionary')parser.add_argument('--nwordssrc', metavar='N', default=65536, type=int, help='number of target words to retain')parser.add_argument('--padding-factor', metavar='N', default=8, type=int,help='Pad dictionary size to be multiple of N')parser.add_argument('--joined-dictionary', action='store_true', help='Generate joined dictionary for en-xx')parser.add_argument('--expert', default='', type=str)parser.add_argument('--workers', metavar='N', default=4, type=int, help='number of parallel workers')# parser.add_argument('--workers', metavar='N', default=os.cpu_count(), type=int, help='number of parallel workers')return parserdef main(args):print(args)random.seed(1)destdir = os.path.join(args.pref, 'data-bin' + ('' if args.expert == '' else '/' + args.expert))os.makedirs(destdir, exist_ok=True)dict_path = os.path.join(destdir, 'dict.txt')textdir = os.path.join(args.pref, 'text')train_dir = os.path.join(textdir, 'train_data')test_dir = os.path.join(textdir, 'test_data')valid_dir = os.path.join(textdir, 'valid_data')# if args.expert != '':# train_files = glob.glob('{}/train.{}-en.*.e'.format(train_dir, args.expert)) + \#               glob.glob('{}/train.en-{}.*.e'.format(train_dir, args.expert))# pass# else:train_files = glob.glob('{}/train.*-*.*'.format(train_dir))train_files = [f for f in train_files if len(f.split('.')) in [3, 5]]test_files = glob.glob('{}/test.*-*.*'.format(test_dir))test_files = [f for f in test_files if len(f.split('.')) in [3, 5]]valid_files = glob.glob('{}/valid.*-*.*'.format(valid_dir))valid_files = [f for f in valid_files if len(f.split('.')) in [3, 5]]lng_pairs = set([f.split('/')[-1].split(".")[1] for f in (train_files + test_files + valid_files)])print(train_files, test_files, valid_files, lng_pairs)def build_dictionary(filenames):d = dictionary.Dictionary()for filename in filenames:Tokenizer.add_file_to_dictionary(filename, d, tokenize_line, args.workers)return dtgt_dict_path = os.path.join(destdir, 'dict.tgt.txt')if not args.no_dict:if args.joined_dictionary:src_dict = build_dictionary(train_files)src_dict.finalize(nwords=args.nwordssrc,padding_factor=args.padding_factor)dict_path = os.path.join(destdir, 'dict.txt')# create dict for every languagefor lng_pair in lng_pairs:src, tgt = lng_pair.split('-')tmp_src_dict_path = os.path.join(destdir, f'dict.{src}.txt')tmp_tgt_dict_path = os.path.join(destdir, f'dict.{tgt}.txt')if not os.path.exists(tmp_src_dict_path):src_dict.save(tmp_src_dict_path)if not os.path.exists(tmp_tgt_dict_path):src_dict.save(tmp_tgt_dict_path)src_dict.save(dict_path)print(src_dict)else:print("| build en dict.")src_dict = build_dictionary([f for f in train_files if f.replace('.tok.bpe', '').endswith('.en')])src_dict.finalize(nwords=args.nwordssrc,padding_factor=args.padding_factor)src_dict.save(dict_path)print("| build xx dict.")tgt_dict = build_dictionary([f for f in train_files if not f.replace('.tok.bpe', '').endswith('.en')])tgt_dict.finalize(nwords=args.nwordssrc,padding_factor=args.padding_factor)tgt_dict.save(tgt_dict_path)def make_binary_dataset(input_prefix, output_prefix, lng_pair, lang, num_workers):if not args.joined_dictionary and lang != 'en':dict = dictionary.Dictionary.load(tgt_dict_path)else:dict = dictionary.Dictionary.load(dict_path)print('| [{}] Dictionary: {} types'.format(lang, len(dict) - 1))n_seq_tok = [0, 0]replaced = Counter()def merge_result(worker_result):replaced.update(worker_result['replaced'])n_seq_tok[0] += worker_result['nseq']n_seq_tok[1] += worker_result['ntok']input_file = f'{input_prefix}.{lng_pair}.{lang}.tok.bpe'if not os.path.exists(input_file):input_file = f'{input_prefix}.{lng_pair}.{lang}'if not os.path.exists(input_file):print("| {} not found".format(input_file))returnif args.expert:input_file = input_file + '.e'offsets = Tokenizer.find_offsets(input_file, num_workers)pool = Noneif num_workers > 1:pool = Pool(processes=num_workers - 1)for worker_id in range(1, num_workers):fn_without_ext = f"{output_prefix}{worker_id}.{lng_pair}.{lang}"pool.apply_async(binarize, (input_file, dict, fn_without_ext,offsets[worker_id],offsets[worker_id + 1]), callback=merge_result)pool.close()ds = indexed_dataset.IndexedDatasetBuilder(f"{output_prefix}.{lng_pair}.{lang}.bin")merge_result(Tokenizer.binarize(input_file, dict, lambda t: ds.add_item(t),offset=0, end=offsets[1]))if num_workers > 1:pool.join()for worker_id in range(1, num_workers):temp_file_path = f"{output_prefix}{worker_id}.{lng_pair}.{lang}"ds.merge_file_(temp_file_path)os.remove(indexed_dataset.data_file_path(temp_file_path))os.remove(indexed_dataset.index_file_path(temp_file_path))ds.finalize(f"{output_prefix}.{lng_pair}.{lang}.idx")print('| [{}] {}: {} sents, {} tokens, {:.3}% replaced by {}'.format(lang, input_file, n_seq_tok[0], n_seq_tok[1],100 * sum(replaced.values()) / n_seq_tok[1], dict.unk_word))def make_all(lng_pair, lang):make_binary_dataset(os.path.join(train_dir, 'train'),os.path.join(destdir, 'train'),lng_pair, lang, num_workers=args.workers)make_binary_dataset(os.path.join(test_dir, 'test'),os.path.join(destdir, 'test'),lng_pair, lang, num_workers=1)make_binary_dataset(os.path.join(valid_dir, 'valid'),os.path.join(destdir, 'valid'),lng_pair, lang, num_workers=1)lngs = set()for lng_pair in lng_pairs:src_and_tgt = lng_pair.split('-')if len(src_and_tgt) != 2:continuesrc, tgt = src_and_tgtprint("| building: ", src, tgt)lngs.add(src)lngs.add(tgt)make_all(lng_pair, src)make_all(lng_pair, tgt)lngs = list(lngs)lngs.sort()json.dump(lngs, open(os.path.join(destdir, 'all_lngs.json'), 'w'))def binarize(filename, dict, fn_without_ext, offset, end):ds = indexed_dataset.IndexedDatasetBuilder(f"{fn_without_ext}.bin")def consumer(tensor):ds.add_item(tensor)res = Tokenizer.binarize(filename, dict, consumer, offset=offset, end=end)ds.finalize(f"{fn_without_ext}.idx")return resif __name__ == '__main__':parser = get_parser()args = parser.parse_args()main(args)

上述代码的大致预处理流程为:

  • 分词:perl $TOKENIZER -threads 8 -l $l > $tmp/$tok
  • 清理:perl $CLEAN -ratio 1.5 $tmp/train.tags.$lang.tok $src $tgt $tmp/train.tags.$lang.clean 1 175
  • 小写化:perl $LC < $tmp/train.tags.$lang.clean.$l > $tmp/train.tags.$lang.$l
  • 为测试数据进行同样的:分词、小写化
  • 创建训练、验证、测试集
  • 使用所有训练数据学习bpe:python $BPEROOT/learn_bpe.py -s $BPE_TOKENS < $TRAIN > $BPE_CODE
  • 对所有文件进行bpe:python $BPEROOT/apply_bpe.py -c $BPE_CODE < $tmp/$f > $prep/$f
  • 创建词典&二值化:python iwslt14/preprocess_universal.py --pref=iwslt14/ --joined-dictionary

另外需要特别说明的是,preprocess_multilingual.py需要用到fairseq库, 而如果直接在当前环境pip install fairseq,得到最新版本是跑不了这些代码的。方法有二:1. pip install fairseq==0.6.1(没有尝试);2. git clone https://github.com/RayeRen/multilingual-kd-pytorch ; cp -r multilingual-kd-pytorch/fairseq .

最终得到data-bin文件夹,用于模型的训练。
(关于以上预处理流程中涉及到的代码的大致解析,请见[机器翻译] 常见预处理代码解析)

模型训练

看LaSS。

补充

补充一:Key error while accessing batch_iterator.first_batch

如果遇到该错误,则是因为上面的preprocess_multilingual.py与你使用的fairseq版本不对应,可以尝试[机器翻译] multilingual fairseq-preprocess中的方法。

参考

https://github.com/NLP-Playground/LaSS
https://github.com/RayeRen/multilingual-kd-pytorch/blob/master/data/iwslt/raw/prepare-iwslt14.sh
https://blog.csdn.net/jokerxsy/article/details/125054739

[机器翻译] 记一次多语言机器翻译模型的训练相关推荐

  1. [深度学习] 自然语言处理 --- Huggingface-Pytorch中文语言Bert模型预训练

    Hugging face 是一家总部位于纽约的聊天机器人初创服务商,开发的应用在青少年中颇受欢迎,相比于其他公司,Hugging Face更加注重产品带来的情感以及环境因素.官网链接在此 https: ...

  2. 大语言模型的多语言机器翻译能力分析

    来自:南大NLP 进NLP群->加入NLP交流群 01 研究动机 以ChatGPT为代表的大语言模型(Large Language Models, LLM)在机器翻译(Machine Trans ...

  3. 不以英语为中心,百种语言互译,FB开源首个单一多语言MT模型

    机器之心报道 机器之心编辑部 Facebook AI 近日开源了多语言机器翻译模型 M2M-100,该模型不依赖以英语为中心的数据,可以实现 100 种语言之间的相互翻译. 机器翻译(MT)打破了人类 ...

  4. EMNLP2018论文解读 | 三种提升多语言翻译模型的高效策略

    本文(<三种提升一对多多语言翻译策略>)是搜狗和中科院自动化所合作发表在 EMNLP 2018 上的工作.搜狗翻译目前采用业界领先的神经网络机器翻译框架支持 60 种以上不同语言之间的互译 ...

  5. 融合统计机器翻译特征的蒙汉神经网络机器翻译技术

    融合统计机器翻译特征的蒙汉神经网络机器翻译技术 杜健  内蒙古大学 [摘要]:随着机器翻译的发展,统计机器翻译已经进入瓶颈期很难有所提高,因此研究人员逐步将研究目光投向神经网络机器翻译方向.神经网络机 ...

  6. 超越谷歌BERT!依图推出预训练语言理解模型ConvBERT,入选NeurIPS 2020

    机器之心发布 机器之心编辑部 在本文中,本土独角兽依图科技提出了一个小而美的方案--ConvBERT,通过全新的注意力模块,仅用 1/10 的训练时间和 1/6 的参数就获得了跟 BERT 模型一样的 ...

  7. K-BERT | 基于知识图谱的语言表示模型

    今天给大家介绍发表在AAAI 2020上的文章"K-BERT: Enabling Language Representation with Knowledge Graph",该工作 ...

  8. R语言分类模型:逻辑回归模型LR、决策树DT、推理决策树CDT、随机森林RF、支持向量机SVM、Rattle可视化界面数据挖掘、分类模型评估指标(准确度、敏感度、特异度、PPV、NPV)

    R语言分类模型:逻辑回归模型LR.决策树DT.推理决策树CDT.随机森林RF.支持向量机SVM.Rattle可视化界面数据挖掘.分类模型评估指标(准确度.敏感度.特异度.PPV.NPV) 目录

  9. R语言回归模型构建、回归模型基本假设(正态性、线性、独立性、方差齐性)、回归模型诊断、car包诊断回归模型、特殊观察样本分析、数据变换、模型比较、特征筛选、交叉验证、预测变量相对重要度

    R语言回归模型构建.回归模型基本假设(正态性.线性.独立性.方差齐性).回归模型诊断.car包诊断回归模型.特殊观察样本分析.数据变换.模型比较.特征筛选.交叉验证.预测变量相对重要度 目录

最新文章

  1. Directx11 教程(2) 基本的windows应用程序框架(2)
  2. 北大新研究用数学模型揭网红崛起奥秘!登上Nature子刊
  3. 给字符数组赋值的方法
  4. 工具栏对象GUI Status 与GUI Title
  5. Helm 从入门到实践 | 从 0 开始制作一个 Helm Charts
  6. 初识ES-安装kibana
  7. Python实现多行数据读入
  8. 我!程序猿!被银行套路了!
  9. 鸿蒙系统手机现在有什么,华为鸿蒙手机迟迟未来 手机操作系统面临的难点有哪些...
  10. python27换行_python 27 :用句点字符匹配换行
  11. 微博无限私信技术软件_用手机制作剪辑视频的教程,手机视频剪辑软件还有哪些?...
  12. FFMPEG音视频开发: 发布RTSP流(采用EasyDarwin作为流媒体服务器)
  13. PV(访问量)、UV(独立访客)、IP(独立IP) (转)
  14. Oracle 10g的闪回机制
  15. Java后端实现安卓/IOS移动端消息推送(百度云推送)
  16. 第三代电力电子半导体:SiC MOSFET学习笔记(一)SiC兴起
  17. 密码爆破工具:Medusa(美杜莎)-操作说明
  18. 美好(fanzao)的一天又开始了今天研究SpringBoot
  19. 多边形扫描转换算法中的边表(Edge Table, ET)
  20. 选一些200页左右的书,每周看一本

热门文章

  1. 【PAT乙级】 1014福尔摩斯的情书(20) [字符串处理]
  2. win8计算机修改密码,win8系统修改电脑开机密码的方法
  3. 按头安利 好看又实用的餐饮美食海外PPT模板素材看这里
  4. 推荐系统实战第02课召回算法和业界最佳实践Part1
  5. 国考省考行测:资料分析,两年复合增长率
  6. 物联网专业的大学生需要掌握哪些技术?看一看我的学习路线
  7. 音频文件c语言对比,一种音频比对算法
  8. linux的vim撤销命令,[Linux] Vim 撤销 回退 操作
  9. 蓝桥杯——ALGO-743——矮人采金子
  10. hdu2616 kill the monster 4.3.8