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。

  • 相关阅读:
    转傻逼是傻逼的通行证,苦逼是苦逼的墓志铭 简单
    css 表格底边框在ie6下不显示 简单
    cookie设置、读取,domain、path、expires 简单
    js事件作用域问题 简单
    js鼠标事件定位 简单
    报到证的作用 简单
    转白领一族预防空调病全攻略 简单
    The "External World" is Inside the Brain
    [转]DllMain详解
    Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects
  • 原文地址:https://www.cnblogs.com/wuseguang/p/3980631.html
Copyright © 2011-2022 走看看