Advertisement

Python 人工智能实战:机器翻译

阅读量:

1.背景介绍

机器翻译技术属于自然语言处理领域的重要组成部分。在机器翻译过程中,输入是一段待译文文本内容,在输出端则会得到另一种语言表达形式的文本结果(如英文字体转中文字体),涵盖多种语言间的互译转换工作(如英文到中文、中文到英文等)。当前应用最为广泛的机器翻译模型主要包括基于统计概率理论的方法(统计翻译模型SMT)以及基于神经网络算法的方法(神经网络翻译模型NMT)。本文将详细阐述Python编程环境下基于统计概率方法实现的机器翻译技术——IBM-1模型的具体工作原理及其实现机制。 IBM-1 由IBM公司在1957年首次提出设计与开发的一种统计机器翻译方法论体系,在当时的背景下被认为是较为先进的机器翻译技术之一。相较于前代几种基本型式的传统机器翻译方法论体系而言,在保证较高译码准确性的同时,在复杂语句句式的转换效果上却表现得并不理想,并且仅支持单向的语言互译功能(即仅能实现英文字体到其他语言字体的自动转码转换)。 IBM-1 系统的整体工作流程可通过下图来进行直观展示: IBM-1 系统采用基于概率统计理论的语言互译规律构建机制,在源语言文本与目标语言文本之间的语义对应关系学习过程中完成对双语语料库数据特征信息的有效提取与建模工作。具体而言,在实际运行过程中系统首先会对大规模双语对照语料库数据进行收集与整理归纳分析,并在此基础上建立一系列的概率条件分布模型;随后系统将根据预设的概率条件分布模型框架自动完成新输入待译文文本数据至目标语言文字段的数据映射与编码转换过程;最后系统会在生成的目标语言文字段数据基础上再结合预设的上下文信息进行必要的校正优化处理以实现最终高质量的目标译文输出结果生成过程

2.核心概念与联系

概率模型

IBM-1的概率模型基于两个词袋模型构建,并且每个词袋模型分别对应一种特定的语言。这些词袋模型本质上即构成了一个用于描述词语频率分布的矩阵结构,在这种矩阵中n表示词汇表的大小而m则表示不同语言的数量。每一列具体地代表了某一种特定语言中的词语频率分布情况;而第i个词语在第j种语言中的出现次数则可表示为f(i,j)的形式。 IBM-1的方法通过使用两个独立建立的这种矩阵来分别描述源语和目标语的语言统计特征

词典

IBM-1 模型不仅依赖于以词频向量表征语言间的共生关系这一手段,在语言模型构建中还必须依赖于一个专门设计的字典来存储必要的统计规律。该字典不仅记录了所有可能出现的词汇及其相关属性信息(如前缀、语义类别和上下文关系等),而且在估算语言模型参数时会基于所包含的信息进行处理。例如,在某些特定情况下这些词汇会包含丰富信息——代表其重要性较高或者受到特别关注——从而有助于模型更好地学习出更加精确的词汇表示方法。

转移概率

IBM/PC模型同样采用转移概率这一概念来衡量源语言连续k个词序列与目标语言连续k个词序列之间的关系强度。具体来说,则通过条件概率公式P(t_k | t_{k−1}, t_{k−2}, ..., t_{k−n+1}) 来计算该种关系的概率值。其中n代表上下文窗口的大小,则该条件概率公式即为一维滑动窗口模型的基础框架。进而可被视为一个n×m×m维的概率张量结构,在这种情况下则能够更加清晰地反映出不同位置上的条件关系和它们之间的相互影响机制。

发射概率

IBM-1 发射概率衡量了源语言连续词序列的发生可能性。该模型采用条件概率 e(w|θ) 表示模型参数 θ 和词 w 之间的关系。由于 IBM-1 模型的词汇表大小可变,在实际应用中我们需要利用发射概率来推断所有潜在词汇的概率分布。值得注意的是,在训练数据中未曾遇到的一些词汇仍然会被考虑进去。因此,在实际应用中我们需要利用发射概率来推断所有潜在词汇的概率分布。

IBM-1 参数估计

IBM-1 需要用语料数据来估计模型参数。具体的做法是:

  1. 确定目标语言V;
  2. 对所有出现过的源语言w与目标语言v进行编号;
  3. 准备训练数据集D;
  4. 每一条数据包括源语言句子、对应的目标语言句子以及其概率p;
  5. 通过词典查找相关上下文c以及中间结果m;
  6. 针对每个样本数据,利用c与m更新词典中的词汇频率信息;
  7. 基于词典中的频率信息及平行语料的概率计算转移与发射几率,并更新模型参数θ;
  8. 循环上述过程直至收敛或达到设定的最大迭代次数。

3.核心算法原理和具体操作步骤以及数学模型公式详细讲解

IBM-1 模型的核心理念就是通过统计数据构建词袋模型来推导出不同语言之间的转换规则。然而,在实际应用中如何利用数据合理估计模型参数仍然面临诸多挑战。在这里我们将通过以下Python代码示例的形式向大家展示基于 IBM-1 模型开发出的自动机翻译器的具体实现流程

数据准备

首先,需要准备三个文件:原始数据、训练数据、词典。

原始数据

原始数据被用来创建平行语料集。通常情况下,在构建这种资料集时会需要人工参与操作。由于涉及不同语言间的差异性,在展示自动机翻译器的工作原理时,默认将英语设为目标语言,并将中文作为源语言进行处理。研究中所采用的原始数据形式较为简单:每一行仅包含一个词。

复制代码
    Original Sentence in English: I like playing soccer on my computer.

    Translated Sentence in Chinese: 我喜欢在电脑上打球。
    
         
    代码解读

训练数据

用于训练自动机翻译器的是训练数据。这些数据主要包括两类:一种是具有标记者号的数据(即标注_data),另一种是没有标记者号的数据(即unannotated_data)。在annotated_data中包含了两种不同语言的对译句子;每一条这样的记录都对应一个单独的句子;而unannotated_data则可以视为语料库里尚未标记的部分;为了使其成为annotated_data的形式,这一过程需要人工干预来完成规则转换;并将其转换为标准标记的形式

复制代码
    Source language sentence A

    Target language sentence B with probability of translation PA
    Source language sentence C
    Target language sentence D with probability of translation PD
    ... and so on...
    
         
         
         
         
    代码解读

其中,A、B、C、D 代表源语言、目标语言、翻译后的语言、翻译概率,P 是一个小数。比如:

其中A代表源语言,B代表目标语言,C代表翻译后的语言,D代表翻译概率,P 为一个小数值。

其中,A,B,C,D分别表示源语言,目标语言,翻译后的语言,以及翻译的概率,P是一个介于0和1之间的数值。

复制代码
    The cat is sleeping.    猫正在睡觉。  0.8984375

    I was taken by the police to prison.    我因受贿被警察带走审查。   0.0625
    What a beautiful day!    天真可爱!    0.125
    She needs new shoes.    她需要新的鞋子。     0.6875
    
         
         
         
    代码解读

词典

该词典分别收录了源语言与目标语言各自的语言词汇。它主要收集并记录了词汇的使用频率、各种前缀后缀、语法结构以及语境信息。我们构建的这个语料库主要依赖于统计分析的方法,并通过建立相应的统计模型来估算目标语言的概率分布参数。

训练模型

接下来, 我们可以利用 IBM-1 模型进行训练. 该模型需基于语料数据估计其参数, 因此必须首先加载并准备训练数据集.

复制代码
    import os

    
    
         
    代码解读

def prepare_data(): # 从文件根目录加载原始数据
data_dir = 'data'
src_content = os.path.join(data_dir, 'en.txt')
tgt_content = os.path.join(data_dir, 'zh.txt')

复制代码
    source_lines = []
    target_lines = []
    
    with open(source_file, encoding='utf-8') as f:
    for line in f:
        if not line.strip():
            continue
        source_lines.append(line.strip())
    
    with open(target_file, encoding='utf-8') as f:
    for line in f:
        if not line.strip():
            continue
        target_lines.append(line.strip())
    
    return source_lines, target_lines
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

if name == 'main ': train_data = load_data()

复制代码
    ## 创建词袋模型
    IBM-1 模型由两个词袋模型组成,每个词袋模型对应一个语言。其中,词袋模型是一个 n*m 的矩阵,其中 n 表示词汇表的大小,m 表示语言数量。每一列代表一个语言中的词频分布情况。第 i 个词汇在第 j 个语言中的出现次数可以表示为:f(i,j)。
    ```python
    from collections import defaultdict
    
    class LanguageModel:
    def __init__(self):
        self.word_count = defaultdict(lambda: [defaultdict(int), defaultdict(float)])
    
    def count_words(self, sentences, lang=None):
        """Count words in the given sentences."""
        for sentence in sentences:
            words = sentence.split(' ')
            counts = {}
    
            for word in words:
                if lang is None or (lang=='en' and len(word)<5) or (lang=='zh' and len(word)>1):
                    if word[-1] in ['.', ',', ';']:
                        word = word[:-1].lower()
    
                    elif word[0] in ['"', "'", '(']:
                        word = word[1:]
    
                    else:
                        word = word.lower()
    
                if lang is None or (lang=='en'):
                    if word in counts:
                        counts[word][0]['en'] += 1
    
                    else:
                        counts[word] = [[], {'en': 1}]
    
                    if word+'s' in counts:
                        counts[word+'s'][0]['en'] += 1
    
                    else:
                        counts[word+'s'] = [[], {'en': 1}]
    
                    if word[:len(word)-1]+'ly' in counts:
                        counts[word[:len(word)-1]+'ly'][0]['en'] += 1
    
                    else:
                        counts[word[:len(word)-1]+'ly'] = [[], {'en': 1}]
    
                if lang is None or (lang=='zh'):
                    if word in counts:
                        counts[word][0]['zh'] += 1
    
                    else:
                        counts[word] = [[], {'zh': 1}]
    
                    if word+'es' in counts:
                        counts[word+'es'][0]['zh'] += 1
    
                    else:
                        counts[word+'es'] = [[], {'zh': 1}]
    
                    if word[:-1]+'er' in counts:
                        counts[word[:-1]+'er'][0]['zh'] += 1
    
                    else:
                        counts[word[:-1]+'er'] = [[], {'zh': 1}]
    
            for key, value in counts.items():
                if lang is None or (lang=='en'):
                    self.word_count[key][0]['en'] = max(value[0]['en'], self.word_count[key][0]['en'])
                    self.word_count[key][1]['en'] = sum([p**2 for p in list(value[1].values())])**(0.5)
    
                if lang is None or (lang=='zh'):
                    self.word_count[key][0]['zh'] = max(value[0]['zh'], self.word_count[key][0]['zh'])
                    self.word_count[key][1]['zh'] = sum([p**2 for p in list(value[1].values())])**(0.5)
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

计算转移概率

源语言和目标语言之间的转移概率衡量了不同词语组合的可能性,并且可以用条件概率 P(t_k | t_{k−1}, t_{k−2}, …, t_{k−n+1}) 来表示。其中 t_k 表示长度为 k 的词语序列;n 代表上下文窗口的大小;转移概率可以视为一个 n×m×m 的三维矩阵结构;IBM-1 模型通过词典收集并分析了大量上下文信息,并因此能够估计任意两个词语之间的相互依赖关系,并将其影响融入转移概率矩阵中。

复制代码
    from math import log
    
    class IBM1:
    def __init__(self):
        pass
    
    def compute_transition_probabilities(self, model):
        ngram_counts = defaultdict(lambda: [defaultdict(float), defaultdict(float), defaultdict(float)])
    
        all_sentences = [(x, y) for x, y in zip(*train_data)]
    
        for prev, curr in zip(['<s>'] + all_sentences[:-1], all_sentences):
            self._compute_trigrams(prev[0], curr[0], ngram_counts)
    
        for n in range(1, 4):
            for trigram in ngram_counts[n][:,:,:] - ngram_counts[n-1][:,:,:]:
                total = float(sum(list(trigram.flatten())))
    
                for a in range(model['vocab_size']):
                    for b in range(model['vocab_size']):
                        prob = trigram[(a,b)]/total
    
                        if prob > 0.:
                            model['trans_probs'][n][a][b] = min(log(prob/(model['alpha']/model['beta']), 2)) 
    
                        else:
                            model['trans_probs'][n][a][b] = -1e10
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

计算发射概率

发射概率代表源语言连续词序列发生的可能性水平。IBM-1模型采用符号e(w|θ)表示条件概率,在此定义中θ代表模型参数而w代表具体某个词语符号。由于该模型允许具有不同长度和内容的语言表达形式,在实际应用中我们无法穷举所有可能存在的词语符号;因此必须借助发射概率去估算各种可能出现的词语符号的概率分布情况。然而,在现实训练数据集中并未包含的所有词语符号仍然会被系统纳入其考虑范围之内;最终这使得发射概率形成了一个动态变化的矩阵结构。

复制代码
    class IBM1:
    def __init__(self):
        pass
    
    def compute_emission_probabilities(self, model):
        ngram_counts = defaultdict(lambda: [defaultdict(int), defaultdict(int)])
    
        for src_sent, trg_sent in zip(*train_data):
            self._compute_bigrams(src_sent, trg_sent, ngram_counts)
    
        vocab_count = defaultdict(int)
    
        for bi_grams, freq in ngram_counts[2]:
            if bi_grams[0]!= '<unk>' and bi_grams[1]!= '<unk>':
                vocab_count[bi_grams[0]] += freq
    
        vocab_freq = {k:v/sum(list(vocab_count.values())) for k, v in vocab_count.items()}
    
        for bi_grams, freq in ngram_counts[2]:
            if bi_grams[0]!= '<unk>' and bi_grams[1]!= '<unk>':
                model['emit_probs'][2][bi_grams[0]][bi_grams[1]] = min(-1.*log(vocab_freq[bi_grams[0]]))
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

模型参数估计

IBM-1 需要用语料数据来估计模型参数。具体的做法是:

  1. 确定目标语言 V,即所有需要翻译的目标语言;

  2. 将所有出现过的源语言 w 和目标语言 v 分别赋予索引;

构建训练数据集 D ,其中每条样本包含源语言的一个句子 、其对应的翻译目标语言的句子以及相对应的概率值 p 。训练集通常由一对接的源语言与目标语言的语料构成 ,即所谓的双语平行语料库

  1. 在词典中查找所有的上下文 c 和中间结果 m;

  2. 对每个数据样本,用 c 和 m 更新词典中的词频信息;

基于词汇库中的频率数据以及平行对照的数据集,在统计语言模型中评估转移概率与发射概率,并将模型参数θ设定为当前最优值。

  1. 重复以上步骤直至收敛或达到最大迭代次数;

  2. 生成目标语言的翻译结果。

复制代码
    class IBM1:

     def __init__(self):
     self.model = {'vocab_size': 5000,
                   'alpha': 0.1,
                   'beta': 0.1,
                   'trans_probs': [],
                   'emit_probs': []}
    
     self.max_iter = 100
    
     self.create_models()
    
    
    
         
         
         
         
         
         
         
         
         
         
         
         
    代码解读
复制代码
    def create_models(self):
    self.model['trans_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    self.model['emit_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    
    self.model['trans_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    self.model['emit_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    
    self.model['trans_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    self.model['emit_probs'].append([[0.] * self.model['vocab_size']] * self.model['vocab_size'])
    
    
    def train(self):
    current_loss = 1e10
    num_iters = 0
    
    while abs(current_loss) > 1e-4 and num_iters < self.max_iter:
        print("Iteration:", num_iters)
        loss = self._iterate()
        print("Loss:", loss)
    
        current_loss = loss
    
        num_iters += 1
    
    
    def _iterate(self):
    lm = LanguageModel()
    model = deepcopy(self.model)
    
    # Estimate transition probabilities using bigram counts
    self.compute_transition_probabilities(model)
    
    # Estimate emission probabilities using unigram counts
    self.compute_emission_probabilities(model)
    
    return 0.
    
    
    def translate(self, text):
    pass
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
复制代码
    ## 测试模型
    最后,测试模型的准确性,同时可视化模型的性能。
    ```python
    if __name__ == '__main__':
    # Test the model accuracy
    test_set = [('the quick brown fox jumps over the lazy dog'.split(), '那是一只快速跑的棕色狐狸。'.split()), 
                ('apple pie apple juice'.split(), '苹果派西瓜露。'.split()),
                ('The movie was cool.'.split(), '这部电影很酷。'.split())]
    
    correct = 0
    
    for src_sent, trg_sent in test_set:
        pred_trg_sent = translator.translate(src_sent)
        if pred_trg_sent == trg_sent:
            correct += 1
    
    print("Accuracy:", correct / len(test_set))
    
    # Visualize performance
    translator.visualize()
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

全部评论 (0)

还没有任何评论哟~