zoukankan      html  css  js  c++  java
  • 基于统计机器翻译的文白对译

    本文介绍利用NiuTrans工具进行文白对译的步骤,默认用户已经安装NiuTrans,安装目录为NiuTrans/,以下相对路径基于此目录。

    文白对译模型训练步骤分为语料预处理、对齐、翻译模型训练、语言模型训练、参数调整四个阶段。

    一、语料预处理

    我们拿到的原始数据格式比较杂乱,需要做预处理,最终形成规则的平行语料数据。

    语 料预处理包括统一标点符号,删除无关符号,删除段前段后,句前句后空格,分词等阶段。最终形成两个平行文件,暂称为src.txt和tgt.txt两个文 件(若是文白翻译src为文,tgt为白,反之src为白,tgt为文),这两个文件每行一句话(自然句),每句话已经分好词,词语以空格分割开,两个文 件中每行一一对应,因此行数相等。

    考虑到文白词语的异意性,句句对齐后的句子分词策略为:白话文为平常的中文分词,文言文为一元分词。

    二、对齐

    NiuTrans采用第三方工具giza++进行词汇对齐,由于giza++只能进行单向对齐,为了保证对齐结果的准确性,NiuTrans合并了两个方向上的对齐结果,生成了最终的对齐结果供后续步骤使用。

    具 体来说,若src==》tgt对齐,giza++会生成一个名为src2tgt.A3.final的结果文件;若tgt==》src对齐,giza++会 生成一个名为tgt2src.A3.final的结果文件;NiuTrans对这两个方向的A3文件进行合并,生成最终的对齐文件 alignment.txt。

    以上的对齐步骤可参看脚本代码scripts/NiuTrans-running-GIZA++.pl。

    需要特别注意的是,giza++ 进行单向对齐时,如果源/目标句对的长度(分词后词汇个数)相差太大,giza++会对长的一方进行剪切,而在另一个方向目标/源对齐时,并不一定进行剪 切。这样就造成了在两个对齐结果文件src2tgt.A3.final和tgt2src.A3.final的不一致。这个不一致将会造成NiuTrans 在合并生成alignment.txt时发生错误直接退出。这种错误只跟源/目标的长度比有关,与具体哪种语言无关。因此本文题目虽然是《文白对译步骤》,其实是所有语言通用的步骤。因此,直接运行脚本scripts/NiuTrans-running-GIZA++.pl,在第八步之后会出现错误退出,导致训练失败。

    解决方法为:在第七步之后,第八步之前,遍历src2tgt.A3.final和tgt2src.A3.final两个文件,将不一致的句对从两个A3文件中剔除,同时也从两个平行语料文件中剔除。

    遍历算法很简单,首先看下A3文件的格式:

    # Sentence pair (20) source length 11 target length 13 alignment score : 1.14927e-38
    智果 便 向 太史 请求 脱离 智族 姓氏 , 另 立 为辅 氏
    NULL ({ 2 }) 智 ({ }) 果 ({ 1 5 6 7 8 }) 别 ({ 10 }) 族 ({ }) 于 ({ 3 }) 太 ({ 4 }) 史 ({ }) , ({ 9 }) 为 ({ }) 辅 ({ 11 12 }) 氏 ({ 13 })
    

    上面摘录的是一个句子对的对齐结果。第一行为句对描述,第二行为目标句子内容,第三行为对齐结果。【Sentence pair (20)】表示为第20个句对,source length 11表示源句长度为11,target length 13表示目标句子长度为13。遍历两个A3文件中的每个pair(三行),检查若第一个文件中的source length与第二个文件中的target length相等,且第一个文件中的target length和第二个文件中的source length 相等,说明该句对是一致的,否则不一致,把该句对从两个A3文件和平行文件中剔除。

    处理代码粘贴如下:

    check.py
    # -*- coding: utf-8 -*-
    '''
    Created on 2014年8月25日
    @author: wuseguang
    '''
    import sys
    import re
    print "脚本名:", sys.argv[0]
    if(len(sys.argv)!=5):
        print "参数不对"
        sys.exit()
    src=sys.argv[1]
    tgt=sys.argv[2]
    srcs=sys.argv[3]
    tgts=sys.argv[4]
    errPairs=[]
    with open(src,'r') as srcFile,open(tgt,'r')as tgtFile,open(src+'.check','w')as srcw,open(tgt+'.check','w')as tgtw:
        index=-1
        pair=0
        flag=True
        while True:
            index+=1
            print index
            srcLine=srcFile.readline()
            tgtLine=tgtFile.readline()
            if not srcLine or not tgtLine:
                break
             
            if index%3!=0 or not srcLine.startswith("# Sentence pair"):
                if flag:
                    srcw.write(srcLine)
                    tgtw.write(tgtLine)
                continue
            srcData=re.split('D+',srcLine)
            tgtData=re.split('D+',tgtLine)
            #print srcData
            #print tgtData
            if srcData[2]!=tgtData[3] or srcData[3]!=tgtData[2]:
                errPairs.append(index/3+1)
                flag=False
                continue
            pair+=1
            flag=True
            oldtitle="# Sentence pair ("+srcData[1]+")"
            newtitle='# Sentence pair ('+str(pair)+')'
            print oldtitle
            print newtitle
            srcw.write(srcLine.replace(oldtitle,newtitle))
            tgtw.write(tgtLine.replace(oldtitle,newtitle))
             
    with open(srcs,'r') as srcsfile,open(tgts,'r') as tgtsfile,open(srcs+'.check','w')as srcw,open(tgts+'.check','w')as tgtw:
        pair=0
        errSet=set(errPairs)
        #print srcs+'
    '
        #print tgts+'
    '
        while True:
            pair+=1
            #print 'pair:',pair
            srcline=srcsfile.readline()
            tgtline=tgtsfile.readline()
            if not srcline or not tgtline:
                break
            if pair in errSet:
                continue
            srcw.write(srcline)
            tgtw.write(tgtline)
    print errPairs
    print len(errPairs)
    

    请将该文件放置于scripts目录下。后续脚本会自助调用。

    然后,注释掉scripts/NiuTrans-running-GIZA++.pl脚本中的第八步的代码。在调用scripts/NiuTrans-running-GIZA++.pl脚本之后,调用check.py进行一致性检查,最后调用NiuTrans的合并对齐命令../bin/NiuTrans.SymAlignment。

    三、翻译模型训练

    在上一步对齐的结果alignment.txt上,进行翻译模型的训练,训练命令为:

    perl NiuTrans-phrase-train-model.pl -tmdir $workDir/model.phrase/ -s $srcFile -t $tgtFile -a $aligFile

    -s指向源平行语料文件,-t指向目标平行语料文件,-a指向alignment.txt文件。

    四、语言模型训练

    语言模型检查目标语言的合法度,因此训练语料只需用目标语言语料即可,格式跟平行语料格式一样,即每行一句,没句以空格分词。训练命令如下:

    perl NiuTrans-training-ngram-LM.pl -corpus $lmodelFile -ngram 3 -vocab $workDir/lm/lm.vocab -lmbin $workDir/lm/lm.trie.data
    lmodelFile即为训练语料文件,惯例以lm.txt命名。

    五、参数调整

    参数调整阶段,对上面训练的两个模型(翻译模型和语言模型)进行权重的调整,其实质是把这两个模型作为两个feature,然后套如特征模型。

    训练命令如下:

    perl NiuTrans-phrase-generate-mert-config.pl -tmdir $workDir/model.phrase/ -lmdir $workDir/lm/ -ngram 3 -o $workDir/NiuTrans.phrase.user.config

    六、总流程小结

    为了操作方便,以上的所有流程我写成到了一个总脚本中,名为train.sh放置在script目录下。内容如下:

     1 #!/bin/sh
     2 scriptDir=$(realpath $PWD)
     3 workDir=$(realpath $1)
     4 srcFile=${workDir}/preprocessing/$2
     5 tgtFile=${workDir}/preprocessing/$3
     6 lmodelFile=${workDir}/preprocessing/$4
     7 aligFile=$workDir/wordalignment/alignment.txt
     8 src2tgtA3File=$workDir/wordalignment/src2tgt.A3.final
     9 tgt2srcA3File=$workDir/wordalignment/tgt2src.A3.final
    10 echo "script_dir is ${scriptDir}"
    11 echo "work_dir is $workDir"
    12 echo "src_file is ${srcFile}"
    13 echo "tgt_file is ${tgtFile}"
    14 echo "alignFile is $aligFile"
    15 #exit
    16 mkdir $workDir/wordalignment -p
    17 mkdir $workDir/lm -p
    18 mkdir $workDir/model.phrase -p
    19 #exit
    20 cd $scriptDir
    21 perl NiuTrans-running-GIZA++.pl -src $srcFile -tgt $tgtFile -out $aligFile -tmpdir $workDir/wordalignment/
    22 cd $scriptDir
    23 python $scriptDir/check.py $src2tgtA3File $tgt2srcA3File $srcFile $tgtFile
    24 src2tgtA3File=${src2tgtA3File}.check
    25 tgt2srcA3File=${tgt2srcA3File}.check
    26 srcFile=${srcFile}.check
    27 tgtFile=${tgtFile}.check
    28 cd $scriptDir
    29 ../bin/NiuTrans.SymAlignment  $tgt2srcA3File $src2tgtA3File $aligFile
    30 cd $scriptDir
    31 perl NiuTrans-phrase-train-model.pl -tmdir $workDir/model.phrase/ -s $srcFile -t $tgtFile -a $aligFile
    32 cd $scriptDir
    33 perl NiuTrans-training-ngram-LM.pl -corpus $lmodelFile -ngram 3 -vocab $workDir/lm/lm.vocab -lmbin $workDir/lm/lm.trie.data
    34 cd $scriptDir
    35 perl NiuTrans-phrase-generate-mert-config.pl -tmdir $workDir/model.phrase/ -lmdir $workDir/lm/ -ngram 3 -o $workDir/NiuTrans.phrase.user.config

    脚本的内容已经非常清晰,不再详述。

    运行此脚本的前提为:1、NiuTrans-running-GIZA++.pl脚本中第八步已经被注释;2、check.py已经放置在scripts文件夹下。

    运行示例:(wenyan.txt baihua.txt位于../work/preprocessing/目录)

    ./train.sh ../work/ wenyan.txt baihua.txt lm2.txt

    七、测试

    在模型训练完毕后,即可进行测试。首先需要具备测试文件test.txt,测试文件格式与平行文件格式一样,与训练语料保持无交集即可。测试命令如下:

    perl NiuTrans-phrase-decoder-model.pl -test $workDir/test/test.txt -c $workDir/NiuTrans.phrase.user.config -output $workDir/test/Xbest.out

    -test指明测试文件位置,-c指明上一步训练的模型配置文件位置,-output 指明翻译结果文件位置。

    注意,若需要指明多个翻译结果,需要修改脚本NiuTrans-phrase-decoder-model.pl第56行的-nbest参数,默认为1。

  • 相关阅读:
    【C#进阶系列】06 类型和成员基础
    纪中5日T1 1564. 旅游
    纪中17日T1 2321. 方程
    纪中17日T2 2322. capacitor
    纪中10日T1 2313. 动态仙人掌
    纪中14日听课小结 图论 最短路 二分图 差分约束
    一个抓猫的游戏 消遣GAME 持续更新中!
    洛谷P1464 Function  HDU P1579 Function Run Fun
    洛谷P1976 鸡蛋饼
    纪中12日T1 2307. 选择
  • 原文地址:https://www.cnblogs.com/wuseguang/p/3980631.html
Copyright © 2011-2022 走看看