TASK05-机器翻译

@[TOC](机器相关及相关技术)
机器翻译(MT):将一段文本从一种语言自动翻译为另一种语言,用神经网络解决这个问题通常称为神经机器翻译(NMT)。主要特征为:输出是单词序列而不是单个单词。输出序列的长度可能与源序列的长度不同。

BPE(byte pair encoding ):词表压缩

  1. NMT 系统为了能够控制计算的复杂度,有 着一个固定大小的词汇表,通常会将词汇表限制在 30k 到 80k 之间,这就导致了其在翻译未登录词时有着严重的不足。由于限定词汇表的大小,对于未出现在该词汇表中的词,NMT 系统用 UNK 标记来替代。结果,NMT 系统不仅无法将它们翻译准确,而且破坏了句子的 结构特征。为了解决 NMT 系统中存在的这一问题, Sennrich 和 Haddow(2016)提出了 一种 BPE 编码的解决方法。该方法将训练语料中单词拆分成更为常见的小部分,这里把 它叫做子字单元。通过这种方法,我们假设在同样将词汇表设置成 30k 的情况下,由于很多单词拆解的子字部分是相同的,所以 30k 的子字单元实际上可以表示出远远超出 30k 的以单 词为基础的词汇表。这样,对于绝大多数未登录词,就可以通过子字单元的组合表示出翻译 的结果。

思想

BPE 的思想是将单词拆解为更小更常见的子字单元。对于原本不在词表中的单词,NMT 系统一般会用 UNK 标示符替代。BPE 方法将其拆解为常见的子字,通过翻译子字部分将原有的 UNK 单词进行了翻译,从而极大地保存了句子的结构特征和流畅性。

算法步骤

算法步骤如下:

初始化符号词表。将所有的字符加入到符号词表中。对所有单词的末尾加入特殊标记,如-。翻译后恢复原始的标记。
迭代对所有符号进行计数,找出次数最多的(A, B),用AB代替。
每次合并,会产生一个新的符号,代表着n-gram字符
常见的n-grams字符(或者whole words),最终会被合并到一个符号

代码实现

    '''把单词分割成最小的符号,并且加上结尾符号'''
    vocabs = {}
    for word, count in words.items():
        # 在正则式自身内,加上空格,abc——>a b c
        word = re.sub(r'([a-zA-Z])', r' \1', word)
        word += ' ' + endtag
        vocabs[word] = count
    return vocabs

def get_symbol_pairs(vocabs):
    ''' 获得词汇中所有的字符pair,连续长度为2,并统计出现次数
    Args:
        vocabs: 单词dict,(word, count)单词的出现次数。单词已经分割为最小的字符
    Returns:
        pairs: ((符号1, 符号2), count)
    '''
    pairs = dict()
    for word, freq in vocabs.items():
        # 单词里的符号
        symbols = word.split()
        for i in range(len(symbols) - 1):
            p = (symbols[i], symbols[i + 1])
            pairs[p] = pairs.get(p, 0) + freq
    return pairs

def merge_symbols(symbol_pair, vocabs):
    '''把vocabs中的所有单词中的'a b'字符串用'ab'替换
    Args:
        symbol_pair: (a, b) 两个符号
        vocabs: 用subword(symbol)表示的单词,(word, count)。其中word使用subword空格分割
    Returns:
        vocabs_new: 替换'a b'为'ab'的新词汇表
    '''
    vocabs_new = {}
    raw = ' '.join(symbol_pair)
    merged = ''.join(symbol_pair)
    # 非字母和数字字符做转义
    bigram =  re.escape(raw)
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
    for word, count in vocabs.items():
        word_new = p.sub(merged, word)
        vocabs_new[word_new] = count
    return vocabs_new

raw_words = {"low":5, "lower":2, "newest":6, "widest":3}
vocabs = process_raw_words(raw_words)

num_merges = 10
print (vocabs)
for i in range(num_merges):
    pairs = get_symbol_pairs(vocabs)
    # 选择出现频率最高的pair
    symbol_pair = max(pairs, key=pairs.get)
    vocabs = merge_symbols(symbol_pair, vocabs)
print (vocabs)

操作次数是算法唯一的超参数。

发布了26 篇原创文章 · 获赞 2 · 访问量 791

猜你喜欢

转载自blog.csdn.net/li_kin/article/details/104365610