BPE算法和ubword-nmt的使用

# 论文原文代码《Neural Machine Translation of Rare Words with Subword Units | Byte Pair Encoding》
import re, collections

def get_stats(vocab):
    pairs = collections.defaultdict(int) # defaultdict还可以被用来计数,将default_factory设为int即可
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols) - 1):
            pairs[symbols[i], symbols[i + 1]] += freq
    return pairs
def merge_vocab(pair, v_in):
    v_out = {}
    bigram = re.escape(' '.join(pair))
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)') #re.complie 生成正则表达式对象
    for word in v_in:
        w_out = p.sub(''.join(pair), word) #re.sub()实现字符串的替换。对word按照p的pattern替换成pair
        v_out[w_out] = v_in[word]
    return v_out

# vocab = {
#     'l o w </w>': 5,
#     'l o w e r </w>': 2,
#     'n e w e s t </w>': 6,
#     'w i d e s t </w>': 3
# }
vocab = {
    '网 络</w>': 5,
    '中 国 网 络</w>': 2,
    '网 络 安 全 </w>': 6,
    '中 国 安 全 </w>': 3
}
num_merges = 8
for i in range(num_merges):
    pairs = get_stats(vocab)
    if not pairs:
        break
    best = max(pairs,key=pairs.get) #max(序列,key)key可以接受1个函数,对key之前的参数进行运算.dict.get返回键值
    vocab = merge_vocab(best, vocab)
    print(best)
('安', '全')
('安全', '</w>')
('网', '络</w>')
('网', '络')
('网络', '安全</w>')
('中', '国')
('中国', '安全</w>')
('中国', '网络</w>')
# 手动实现实现BPE
import re, collections

def get_vocab(filename):
    vocab = collections.defaultdict(int)
    with open(filename,'r',encoding='utf-8') as fhand:
        for line in fhand:
            words = line.strip().split() #1行里的单词
        # #strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
        # split()通过指定分隔符(默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等)对字符串进行切片。
            for word in words:
                vocab[' '.join(list(word))+' </w>']+=1
    return vocab

def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i],symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = re.escape(' '.join(pair))
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
    for word in v_in:
        w_out = p.sub(''.join(pair), word)
        v_out[w_out] = v_in[word]
    return v_out

def get_tokens(vocab):
    '''获取原始token'''
    tokens = collections.defaultdict(int)
    for word, freq in vocab.items():
        word_tokens = word.split()
        for token in word_tokens:
            tokens[token] += freq
    return tokens

vocab = get_vocab('pg16457.txt')
# vocab = {'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3}
# vocab = {
#     '网 络</w>': 5,
#     '中 国 网 络</w>': 2,
#     '网 络 安 全 </w>': 6,
#     '中 国 安 全 </w>': 3
# }
print('==========')
print('Tokens Before BPE')
tokens = get_tokens(vocab)
print('Tokens: {}'.format(tokens))
print('Number of tokens: {}'.format(len(tokens)))
print('==========')

num_merges = 10
for i in range(num_merges):
    pairs = get_stats(vocab)
    if not pairs:
        break
    best = max(pairs, key=pairs.get)
    vocab = merge_vocab(best, vocab)
    print('Iter: {}'.format(i))
    print('Best pair: {}'.format(best))
    tokens = get_tokens(vocab)
    print('Tokens: {}'.format(tokens))
    print('Number of tokens: {}'.format(len(tokens)))
    print('==========')
==========
Tokens Before BPE
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 15, 'e': 59, '</w>': 267, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'c': 7, 't': 35, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 27, 'w': 9, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的': 12, '新': 2, '协': 1, '议': 1, '。': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 161
==========
Iter: 0
Best pair: ('e', '</w>')
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 15, 'e</w>': 21, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'e': 38, 'c': 7, 't': 35, '</w>': 246, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 27, 'w': 9, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的': 12, '新': 2, '协': 1, '议': 1, '。': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 162
==========
Iter: 1
Best pair: ('的', '</w>')
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 15, 'e</w>': 21, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'e': 38, 'c': 7, 't': 35, '</w>': 234, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 27, 'w': 9, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的</w>': 12, '新': 2, '协': 1, '议': 1, '。': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 162
==========
Iter: 2
Best pair: ('。', '</w>')
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 15, 'e</w>': 21, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'e': 38, 'c': 7, 't': 35, '</w>': 222, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 27, 'w': 9, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的</w>': 12, '新': 2, '协': 1, '议': 1, '。</w>': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 162
==========
Iter: 3
Best pair: ('t', 'h')
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 5, 'e</w>': 21, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'e': 38, 'c': 7, 't': 25, '</w>': 222, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'th': 10, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 27, 'w': 9, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的</w>': 12, '新': 2, '协': 1, '议': 1, '。</w>': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 163
==========
Iter: 4
Best pair: ('a', 't')
Tokens: defaultdict(<class 'int'>, {'\ufeff': 1, 'T': 4, 'h': 5, 'e</w>': 21, 'P': 2, 'r': 24, 'o': 36, 'j': 2, 'e': 38, 'c': 7, 't': 15, '</w>': 222, 'G': 2, 'u': 16, 'n': 29, 'b': 4, 'g': 15, 'E': 4, 'B': 4, 'k': 9, 'f': 4, 'A': 6, 'l': 23, 'd': 8, 'th': 10, 'M': 2, ',': 3, 'y': 6, 'J': 2, 's': 23, 'V': 2, 'i': 26, 'a': 17, 'w': 9, 'at': 10, 'm': 3, 'v': 2, '.': 3, 'Y': 1, 'p': 11, '-': 1, 'L': 2, ':': 5, 'R': 2, 'D': 1, '6': 2, '2': 3, '0': 6, '5': 2, '[': 1, '#': 1, '1': 5, '4': 1, '7': 1, ']': 1, 'I': 5, '!': 5, '预': 2, '计': 2, '菲': 2, '利': 6, '佩': 1, '·': 4, '库': 4, '蒂': 4, '尼': 4, '奥': 4, '将': 5, '签': 2, '署': 2, '一': 6, '份': 2, '为': 3, '期': 4, '四': 4, '年': 4, '半': 2, '的</w>': 12, '新': 2, '协': 1, '议': 1, '。</w>': 12, '普': 1, '合': 3, '同': 3, '物': 2, '浦': 2, '中': 4, '场': 2, '核': 1, '心': 1, '目': 1, '前': 1, '于': 2, '8': 2, '到': 4, '这': 1, '位': 1, '球': 1, '员': 1, '布': 2, '伦': 1, '丹': 1, '罗': 2, '杰': 2, '斯': 2, '对': 6, '阵': 2, '切': 2, '尔': 2, '西': 2, '表': 2, '现': 2, '感': 2, '高': 2, '兴': 2, '兰': 1, '登': 1, '德': 6, '国': 4, '人': 3, '在': 2, '加': 3, '时': 2, '赛': 6, '以': 2, '比': 2, '击': 4, '败': 4, '阿': 2, '根': 2, '廷': 2, ',': 4, '第': 4, '次': 6, '举': 2, '起': 2, '奖': 2, '杯': 8, '队': 1, '他': 2, '是': 2, '个': 6, '全': 2, '职': 2, '安': 2, '慰': 2, '被': 2, '手': 2, '七': 4, '甲': 2, '冠': 4, '军': 4, '、': 2, '两': 2, '联': 4, '和': 2, '增': 2, '添': 1, '了': 1, '世': 2, '界': 2, '胜': 2, '至': 1})
Number of tokens: 164
==========

。。。。。。。

# BPE编码  没有保留初始的vovab,当num_merges过大时,初始的token将都会消失,英文中文都得用词. 输入时,每个单词后面都要加</w>
'''
在之前的算法中,我们已经得到了 subword 的词表,对该词表按照字符个数由多到少排序。
编码时,对于每个单词,遍历排好序的子词词表寻找是否有 token 是当前单词的子字符串,如果有,则该 token 是表示单词的 tokens 之一
我们从最长的 token 迭代到最短的 token,尝试将每个单词中的子字符串替换为 token。 
最终,我们将迭代所有 tokens,并将所有子字符串替换为 tokens。 
如果仍然有子字符串没被替换但所有 token 都已迭代完毕,则将剩余的子词替换为特殊 token,如 <unk>
'''
import re, collections
def get_vocab(filename):
    vocab = collections.defaultdict(int)
    with open(filename, 'r', encoding='utf-8') as fhand:
        for line in fhand:
            words = line.strip().split()
            for word in words:
                vocab[' '.join(list(word)) + ' </w>'] += 1

    return vocab

def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i],symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, v_in):
    v_out = {}
    bigram = re.escape(' '.join(pair))
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
    for word in v_in:
        w_out = p.sub(''.join(pair), word)
        v_out[w_out] = v_in[word]
    return v_out

def get_tokens_from_vocab(vocab):
    tokens_frequencies = collections.defaultdict(int)
    vocab_tokenization = {}
    for word, freq in vocab.items():
        word_tokens = word.split()
        for token in word_tokens:
            tokens_frequencies[token] += freq
        vocab_tokenization[''.join(word_tokens)] = word_tokens
    return tokens_frequencies, vocab_tokenization

def measure_token_length(token):
    if token[-4:] == '</w>':  #取倒数4个,即判断token是否以</w>结尾,</w>算1个长度
        return len(token[:-4]) + 1
    else:  #不以token结尾的token
        return len(token)

def tokenize_word(string, sorted_tokens, unknown_token='</u>'):    
    if string == '':
        return []
    if sorted_tokens == []:
        return [unknown_token]
    string_tokens = []
    for i in range(len(sorted_tokens)):
        token = sorted_tokens[i]
        token_reg = re.escape(token.replace('.', '[.]'))

        matched_positions = [(m.start(0), m.end(0)) for m in re.finditer(token_reg, string)]
        if len(matched_positions) == 0:
            continue
        substring_end_positions = [matched_position[0] for matched_position in matched_positions]

        substring_start_position = 0
        for substring_end_position in substring_end_positions:
            substring = string[substring_start_position:substring_end_position]
            string_tokens += tokenize_word(string=substring, sorted_tokens=sorted_tokens[i+1:], unknown_token=unknown_token)
            string_tokens += [token]
            substring_start_position = substring_end_position + len(token)
        remaining_substring = string[substring_start_position:]
        string_tokens += tokenize_word(string=remaining_substring, sorted_tokens=sorted_tokens[i+1:], unknown_token=unknown_token)
        break
    return string_tokens

vocab1 = get_vocab('pg16457.txt')
print('==========')
print('Tokens Before BPE')
tokens_frequencies, vocab_tokenization = get_tokens_from_vocab(vocab)
print('All tokens: {}'.format(tokens_frequencies.keys()))
print('Number of tokens: {}'.format(len(tokens_frequencies.keys())))
print('==========')

#### 编码
num_merges = 600
vocab=vocab1
for i in range(num_merges):
    pairs = get_stats(vocab)
    if not pairs:
        break
    best = max(pairs,key=pairs.get)
    vocab = merge_vocab(best,vocab)
    print('Iter: {}'.format(i))
    print('Best pair: {}'.format(best))
    tokens_frequencies,vocab_tokenization = get_tokens_from_vocab(vocab)
    print('Number of tokens:{}'.format(len(tokens_frequencies.keys())))   
    print('==========')
    
    
def mer_ini_vovab(v_init,v_aft):
    '''加上最初的vocab'''
    v_out= {}
    for word in v_init:
        v_out[word] = v_init[word]
    for word in v_aft:
        v_out[word] = v_aft[word]
    return v_out
vocab2 = mer_ini_vovab(vocab1,vocab)
tokens_frequencies,vocab_tokenization = get_tokens_from_vocab(vocab2)
print('Number of tokens:{}'.format(len(tokens_frequencies.keys())))
==========
Tokens Before BPE
All tokens: dict_keys(['\ufeff', 'T', 'h', 'e</w>', 'P', 'r', 'o', 'j', 'e', 'c', 't</w>', 'G', 'u', 't', 'n', 'b', 'er', 'g</w>', 'E', 'B', 'k', '</w>', 'f', 'A', 'l', 'd', 'th', 'M', ',', 'y', 'J', 'le', 's', 'V', 'i', 'a', 'w', 'at', 'm', 'v', '.', 'Y', 'p', 'g', '-', 'L', ':', 'R', 'D', '6', '2', '0', '5', '[', '#', '1', '4', '7', ']', 'I', '!', '预', '计', '菲', '利', '佩', '·', '库', '蒂', '尼', '奥', '将', '签', '署', '一', '份', '为', '期', '四', '年', '半', '的</w>', '新', '协', '议', '。</w>', '普', '合', '同', '物', '浦', '中', '场', '核', '心', '目', '前', '于', '8', '到', '这', '位', '球', '员', '布', '伦', '丹', '罗', '杰', '斯', '对', '阵', '切', '尔', '西', '表', '现', '感', '高', '兴', '兰', '登', '德', '国', '人', '在', '加', '时', '赛', '以', '比', '击', '败', '阿', '根', '廷', ',', '第', '次', '举', '起', '奖', '杯</w>', '队', '他', '是', '个', '全', '职', '安', '慰', '被', '手', '七', '甲', '冠', '军', '、', '两', '联', '和', '增', '添', '了', '世', '界', '胜', '至'])
Number of tokens: 168
==========
Iter: 0
Best pair: ('e', '</w>')
Number of tokens:162
==========
Iter: 1
Best pair: ('的', '</w>')
Number of tokens:162
==========
Iter: 2
Best pair: ('。', '</w>')
Number of tokens:162
==========
Iter: 3
Best pair: ('t', 'h')
Number of tokens:163
==========
Iter: 4
Best pair: ('a', 't')
Number of tokens:164
==========
Iter: 323
Best pair: ('核心', '</w>')
Number of tokens:151
==========
Iter: 324
Best pair: ('目', '前')
Number of tokens:150
==========
Iter: 325
Best pair: ('目前', '</w>')
Number of tokens:150
==========
Iter: 326
Best pair: ('这', '位')
Number of tokens:149
==========
Iter: 327
Best pair: ('这位', '</w>')
Number of tokens:149
==========
Iter: 328
Best pair: ('球', '员')
Number of tokens:148
==========
Iter: 329
Best pair: ('球员', '</w>')
Number of tokens:148
==========
Iter: 330
Best pair: ('布', '伦')
Number of tokens:148
==========
Iter: 331
Best pair: ('布伦', '丹')
Number of tokens:147
==========
Iter: 332
Best pair: ('布伦丹', '</w>')
Number of tokens:147
==========
Iter: 333
Best pair: ('布', '兰')
Number of tokens:146
==========
Iter: 334
Best pair: ('布兰', '登')
Number of tokens:145
==========
Iter: 335
Best pair: ('布兰登', '</w>')
Number of tokens:145
==========
Iter: 336
Best pair: ('德国', '人</w>')
Number of tokens:146
==========
Iter: 337
Best pair: ('德国', '队')
Number of tokens:145
==========
Iter: 338
Best pair: ('德国队', '</w>')
Number of tokens:145
==========
Iter: 339
Best pair: ('为', '</w>')
Number of tokens:145
==========
Iter: 340
Best pair: ('两', '个</w>')
Number of tokens:145
==========
Iter: 341
Best pair: ('增', '添')
Number of tokens:145
==========
Iter: 342
Best pair: ('增添', '</w>')
Number of tokens:145
==========
Iter: 343
Best pair: ('了', '</w>')
Number of tokens:145
==========
Iter: 344
Best pair: ('增', '加')
Number of tokens:144
==========
Iter: 345
Best pair: ('增加', '</w>')
Number of tokens:144
==========
Iter: 346
Best pair: ('至', '</w>')
Number of tokens:143
==========
Iter: 347
Best pair: ('两', '次</w>')
Number of tokens:143
==========
Iter: 348
Best pair: ('一', '次</w>')
Number of tokens:142
==========
Number of tokens:303
# Let's check how tokenization will be for a known word

word_given_known = 'Scientists</w>have</w>known</w>for</w>years</w>that animals</w>'
word_given_unknown = '在</w>一篇</w>新</w>的</w>《</w>跟单</w>汇票</w>·</w>热诺</w>维斯</w>》</w>中 '
# 按token长度排序
sorted_tokens_tuple = sorted(tokens_frequencies.items(), key=lambda item: (measure_token_length(item[0]), item[1]), reverse=True)
sorted_tokens = [token for (token, freq) in sorted_tokens_tuple]

def tokenize_unkown_word(word_given):
    print('Tokenizing word: {}...'.format(word_given))
    if word_given in vocab_tokenization:
        print('Tokenization is of the known word:')
        print(vocab_tokenization[word_given])
        print('Tokenization treating the known word as unknown:')
        print(tokenize_word(string=word_given, sorted_tokens=sorted_tokens, unknown_token='</u>'))
    else:
        print('Tokenizating of the unknown word:')
        print(tokenize_word(string=word_given, sorted_tokens=sorted_tokens, unknown_token='</u>'))
    print('==========')

tokenize_unkown_word(word_given_known)
tokenize_unkown_word(word_given_unknown)
Tokenizing word: Scientists</w>have</w>known</w>for</w>years</w>that animals</w>...
Tokenizating of the unknown word:
['c', 'i', 'e', 'n', 't', 'i', 's', 't', 's', '</w>', 'h', 'a', 'v', 'e', '</w>', 'k', 'n', 'o', 'w', 'n', '</w>', 'for</w>', 'y', 'e', 'a', 'r', 's', '</w>', 't', 'h', 'a', 't', 'a', 'n', 'i', 'm', 'a', 'l', 's', '</w>']
==========
Tokenizing word: defaultdict(<class 'int'>, {'艺 术 总 监 </w>': 2, '托 马 斯 </w>': 40, '· </w>': 7206, '朱 连 恩 </w>': 1, '“ </w>': 1788, '从 </w>': 645, '混 乱 </w>': 22, '中 </w>': 1525, '创 造 </w>': 30, '结 构 </w>': 8, '” </w>': 1777, ', <三 届 </w>': 4, '科 斯 蒂 </w>': 4, '根 </w>': 4, 'D V O </w>': 4, '斧 子 </w>': 4, '亨 内 格 </w>': 2, '希 思 </w>': 6, '罗 宾 逊 </w>': 18, '阿 德 莱 </w>': 2, '山 区 </w>': 4, '雄 性 </w>': 8, '考 拉 </w>': 6, '冲 向 </w>': 6, '雌 性 </w>': 4, '扭 打 </w>': 4, '哺 乳 动 物 </w>': 12, '交 配 季 节 </w>': 2, '素 养 </w>': 2, '深 爱 </w>': 2, '悼 念 </w>': 4, '奥 克 兰 </w>': 6, '看 人 </w>': 2, '阿 多 </w>': 2, '韦 厄 </w>': 2, '沃 拉 </w>': 2, '遗 书 </w>': 4, '火 山 口 </w>': 8, '小 径 </w>': 2, '费 拉 </w>': 2, '信 该 </w>': 2, '跌 倒 </w>': 4, '四 十 五 分 钟 </w>': 1, '奶 </w>': 3, '奶 瓶 </w>': 2, '马 德 里 队 </w>': 2, '淘 汰 赛 </w>': 4, '帕 梅 拉 </w>': 4, '柯 兰 </w>': 2, '柯 林 斯 </w>': 4, '县 法 院 </w>': 2, '财 产 法 </w>': 2, '卡 梅 伦 想 </w>': 2, '同 僚 </w>': 2, '达 考 </w>': 2, '拉 普 </w>': 4, '翅 膀 </w>': 6, '迅 猛 </w>': 2, '敏 捷 </w>': 2, '凶 残 </w>': 2, '南 达 科 他 州 </w>': 4, '地 狱 </w>': 2, '溪 组 </w>': 2, '达 科 </w>': 2, '电 子 设 备 </w>': 2, '滤 网 </w>': 2, '西 莉 亚 </w>': 2, '光 线 </w>': 2, '八 小 时 </w>': 2, '于 海 军 </w>': 2, '这 么 久 </w>': 2, '奥 尔 登 </w>': 2, 'M a t t h e w </w>': 2, 'B r a y </w>': 2, '嗑 </w>': 2, '药 </w>': 6, '人 行 道 </w>': 6, '碳 纤 维 </w>': 2, '小 休 </w>': 2, '弗 洛 伦 斯 </w>': 4, '吉 朗 </w>': 2, '抱 负 </w>': 2, '持 球 </w>': 2, '洞 穴 </w>': 12, '约 翰 斯 顿 </w>': 4, '人 质 危 机 </w>': 2, '东 北 部 </w>': 2, '巴 达 赫 尚 </w>': 2, '长 征 </w>': 2, '山 洞 </w>': 6, '............... '德 利 布 </w>': 2, 'C M </w>': 2, '朋 克 </w>': 2, '真 名 </w>': 2, '不 利 </w>': 2, '成 龙 </w>': 2, '梅 楚 忠 </w>': 2, '玛 丽 安 </w>': 2, '王 和 钟 </w>': 2, '担 当 </w>': 2, '客 座 </w>': 2, '投 </w>': 2, '做 爱 时 </w>': 2, '更 改 </w>': 2, '柯 利 </w>': 2, '你 们 </w>': 2, '0 4 6 </w>': 2, '赠 款 </w>': 2, '1 9 7 9 </w>': 2, '科 波 </w>': 2, '拉 未 </w>': 2, '启 示 录 </w>': 2, '坎 皮 恩 </w>': 2, '钢 琴 </w>': 2, '金 棕 榈 奖 </w>': 2, '低 俗 小 说 </w>': 2, '塔 伦 </w>': 2, '萨 芬 娜 </w>': 2, '可 悲 </w>': 2, '奖 池 </w>': 2, '挣 得 </w>': 2, '人 患 </w>': 2, '4 4 % </w>': 2, '贫 困 县 </w>': 1, '发 病 率 </w>': 2, '贫 困 地 区 </w>': 1, '普 赖 尔 </w>': 2, '拆 毁 </w>': 2, '吹 </w>': 2, '情 绪 反 应 </w>': 2})...

ubword-nmt的使用

英文预处理要将所有大写字母改为小写字母 ;将英文句尾结束符与句尾最后一个单词用空格分开

  • 获取corpus.bpe这个子词词表和 vocab.en,vocab.de的双语词典(里面是这两种语言的子词及其出现的频率)
    word-nmt learn-joint-bpe-and-vocab --input source.txt target.txt -s 32000 -o corpus.bpe --write-vocabulary vocab.en vocab.de

  • 接下来我们使用以下命令来对双语的语料进行subword切分处理,EN2CHtest.bpr.txt 是bep分词后的,‘@@ ’作为subwords内部的分隔符
    subword-nmt apply-bpe -c corpus.bpe --vocabulary vocab.en --vocabulary-threshold 50 <EN2CHtest.txt> EN2CHtest.bpr.txt

  • 解码,在linux服务器上 。 sed's/旧字符串/新字符串/g' 文件名
    sed -r 's/(@@ )|(@@ ?$)//g' EN2CHtest.bpr.txt > 1.txt

collections----容器数据类型介绍 &re

# collections----容器数据类型介绍
import collections
## collections模块包含了除list、dict、和tuple之外的容器数据类型,如counter、defaultdict、deque、namedtuple、orderdict。

def use_counter():
    '''Counter : 一个简单的计数器,字典形式{‘key’:key出现的次数,...},统计字符出现的个数.'''
    s = 'abbcccdddd'
    c = collections.Counter(s)
    print('Counter:',s)
    c.update('kkkkhhhhaaaa')
    print('Counter_update:',c)
    print ('Counter_elements:',list(c.elements())) # elements()方法可以返回一个包含所有Counter数据的迭代器
    for letter, count in c.most_common(2): # most_common()返回前n个最多的数据,
        print ('Counter.most_common(2) %s: %d' % (letter, count))
use_counter()
    
def use_defaultdict():
    '''
    defaultdict: 使用dict字典类型时,如果引用的key不存在,就会抛出KeyError。如果希望Key不存在时,返回一个默认值,就可以用defaultdict。
    其余操作与dict相同,其第一个参数为default_factory属性提供初始值,默认为None;
    defaultdict还可以被用来计数,将default_factory设为int即可
    '''
    s=[('yellow',1),('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
    d = collections.defaultdict(lambda: 'defaultvalue',s) # 这里的lambda argument_list: expression表示的是一个函数。这个函数叫做lambda函数。
    print('defaultdict:',d.items())
    print(max(d,key=d.get))
use_defaultdict()


Counter: abbcccdddd
Counter_update: Counter({'a': 5, 'd': 4, 'k': 4, 'h': 4, 'c': 3, 'b': 2})
Counter_elements: ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd', 'k', 'k', 'k', 'k', 'h', 'h', 'h', 'h']
Counter.most_common(2) a: 5
Counter.most_common(2) d: 4
defaultdict: dict_items([('yellow', 3), ('blue', 4), ('red', 1)])
blue
# re 正则表达式
import re

## re.complie compile 函数用于编译正则表达式。
pattern = re.compile(r'\w+')  #匹配字母数字及下划线

## re.sub是re模块重要的组成部分,并且功能也非常强大,主要功能实现正则的替换。 
## 定义sub(pattern, repl, string, count=0, flags=0), 对字符串string按照正则表达式pattern,将string的匹配项替换成字符串repl。 
result = pattern.sub('**',"(ji) (4) (af),(g^q)")
print('sub_result:',result)

## re.escape() 对特殊字符进行转义
re.escape('www.python.org')
sub_result: (**) (**) (**),(**^**)





'www\\.python\\.org'
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容