美文网首页Machine Learning & Recommendation & NLP & DL
自然语言处理N天-实现一个Transformer数据预处理

自然语言处理N天-实现一个Transformer数据预处理

作者: 我的昵称违规了 | 来源:发表于2019-03-02 00:24 被阅读6次
新建 Microsoft PowerPoint 演示文稿 (2).jpg

这个算是在课程学习之外的探索,不过希望能尽快用到项目实践中。在文章里会引用较多的博客,文末会进行reference。
搜索Transformer机制,会发现高分结果基本上都源于一篇论文Jay Alammar的《The Illustrated Transformer》(图解Transformer),提到最多的Attention是Google的《Attention Is All You Need》。

  • 对于Transformer的运行机制了解即可,所以会基于这篇论文来学习Transformer,结合《Sklearn+Tensorflow》中Attention注意力机制一章完成基本的概念学习;
  • 找一个基于Transformer的项目练手

5.代码实现

数据获取

源代码使用的是MAC和linux的操作,使用bash download.sh,调用download.sh即可。
我的因为是win系统,就直接从网址上下载压缩包。

https://wit3.fbk.eu/archive/2016-01//texts/de/en/de-en.tgz
在源文件中解压后,会发现这个语料库是以XML格式保存的,内容应该是TED的文本。

对数据进行预处理

数据预处理,是在prepro.py文件中,可以来看看是怎么处理的。这部分主要是完成对英德语料库xml文件的读取和分词,并存储到相应的文件夹中。

准备引入的库
import os
import errno
import sentencepiece as spm
import re
from hyperparams import Hparams
import logging

logging.basicConfig(level=logging.INFO)
读取文件夹中的数据
def prepro(hp):
    
    # 加载原始数据->预处理->使用sentencepiece进行分词
    # 注意,这里使用的分词库是sentencepiece
    # :param hp: hyperparams. argparse.
    # :return: 
    
    # 获取数据,因为是对齐后的英德语料库,所以训练、评价、测试都是双份的。
    logging.info("# Check if raw files exist")
    train1 = "./de-en/train.tags.de-en.de"
    train2 = "./de-en/train.tags.de-en.en"
    eval1 = "./de-en/IWSLT16.TED.tst2013.de-en.de.xml"
    eval2 = "./de-en/IWSLT16.TED.tst2013.de-en.en.xml"
    test1 = "./de-en/IWSLT16.TED.tst2014.de-en.de.xml"
    test2 = "./de-en/IWSLT16.TED.tst2014.de-en.en.xml"
逐条处理

做一个for循环,对读取的数据进行逐条处理

    for f in (train1, train2, eval1, eval2, test1, test2):
        if not os.path.isfile(f):
            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), f)

        logging.info("# Preprocessing")
        ......
分割每一句

数据处理。

  • 使用正则对xml文件进行划分
  • 断言,由于是对齐后的语料库,所以在划分之后需要确定prepro_train1和prepro_train2每一行的单词是一致的
  • 下面的eval和test部分同样
        train部分的数据处理
        _prepro = lambda x: [line.strip() for line in open(x, 'r', encoding='utf-8').read().split("\n") if
                             not line.startswith("<")]
        prepro_train1, prepro_train2 = _prepro(train1), _prepro(train2)
        assert len(prepro_train1) == len(prepro_train2), "Check if train source and target files match."

        # eval部分的数据处理
        _prepro = lambda x: [re.sub("<[^>]+>", "", line).strip() for line in
                             open(x, 'r', encoding='utf-8').read().split("\n") if line.startswith("<seg id")]
        prepro_eval1, prepro_eval2 = _prepro(eval1), _prepro(eval2)
        assert len(prepro_eval1) == len(prepro_eval2), "Check if eval source and target files match."

        # test部分的数据处理
        prepro_test1, prepro_test2 = _prepro(test1), _prepro(test2)
        assert len(prepro_test1) == len(prepro_test2), "Check if test source and target files match."
输出数据进行检测

这部分我在运行的时候报错了……

        # 输出第一行的数据
        logging.info("Let's see how preprocessed data look like")
        logging.info("prepro_train1:", prepro_train1[0])
        logging.info("prepro_train2:", prepro_train2[0])
        logging.info("prepro_eval1:", prepro_eval1[0])
        logging.info("prepro_eval2:", prepro_eval2[0])
        logging.info("prepro_test1:", prepro_test1[0])
        logging.info("prepro_test2:", prepro_test2[0])
写入数据
  • 构造文件夹
  • 将读取并处理好的数据写入文件中
        logging.info("# write preprocessed files to disk")
        os.makedirs("iwslt2016/prepro", exist_ok=True)

        def _write(sents, fname):
            with open(fname, 'w', encoding='utf-8') as fout:
                fout.write("\n".join(sents))

        _write(prepro_train1, "iwslt2016/prepro/train.de")
        _write(prepro_train2, "iwslt2016/prepro/train.en")
        _write(prepro_train1 + prepro_train2, "iwslt2016/prepro/train")
        _write(prepro_eval1, "iwslt2016/prepro/eval.de")
        _write(prepro_eval2, "iwslt2016/prepro/eval.en")
        _write(prepro_test1, "iwslt2016/prepro/test.de")
        _write(prepro_test2, "iwslt2016/prepro/test.en")
构建BPE模型

采用Byte pair encoding (BPE) 算法来进行分割。
BPE通过一个固定大小的词汇表来表示开放词汇,这个词汇表里面的是变长的字符串序列。这是一种对于神经网络模型非常合适的词分割策略。

        logging.info("# Train a joint BPE model with sentencepiece")
        os.makedirs("iwslt2016/segmented", exist_ok=True)
        train = '--input=iwslt2016/prepro/train --pad_id=0 --unk_id=1 
                     --bos_id=2 --eos_id=3 --model_prefix=iwslt2016/segmented/bpe --vocab_size={} --model_type=bpe'.format(hp.vocab_size)
        spm.SentencePieceTrainer.Train(train)

        logging.info("# Load trained bpe model")
        sp = spm.SentencePieceProcessor()
        sp.Load("iwslt2016/segmented/bpe.model")
分词处理

对前面读取的数据进行分词处理。并打印出来。

        logging.info("# Segment")

        def _segment_and_write(sents, fname):
            with open(fname, "w", encoding='utf-8') as fout:
                for sent in sents:
                    pieces = sp.EncodeAsPieces(sent)
                    fout.write(" ".join(pieces) + "\n")

        _segment_and_write(prepro_train1, "iwslt2016/segmented/train.de.bpe")
        _segment_and_write(prepro_train2, "iwslt2016/segmented/train.en.bpe")
        _segment_and_write(prepro_eval1, "iwslt2016/segmented/eval.de.bpe")
        _segment_and_write(prepro_eval2, "iwslt2016/segmented/eval.en.bpe")
        _segment_and_write(prepro_test1, "iwslt2016/segmented/test.de.bpe")

        logging.info("Let's see how segmented data look like")
        print("train1:", open("iwslt2016/segmented/train.de.bpe", 'r', encoding='utf-8').readline())
        print("train2:", open("iwslt2016/segmented/train.en.bpe", 'r', encoding='utf-8').readline())
        print("eval1:", open("iwslt2016/segmented/eval.de.bpe", 'r', encoding='utf-8').readline())
        print("eval2:", open("iwslt2016/segmented/eval.en.bpe", 'r', encoding='utf-8').readline())
        print("test1:", open("iwslt2016/segmented/test.de.bpe", 'r', encoding='utf-8').readline())
运行一哈
if __name__ == '__main__':
    hparams = Hparams()
    parser = hparams.parser
    hp = parser.parse_args()
    prepro(hp)
    logging.info("Done")

最后会生成两个文件夹,如图所示,运行的时间比较长


image.png

相关文章

网友评论

    本文标题:自然语言处理N天-实现一个Transformer数据预处理

    本文链接:https://www.haomeiwen.com/subject/zhusuqtx.html