FLAT代码解读(1)-输入

论文 FLAT: Chinese NER Using Flat-Lattice Transformer(ACL 2020)

首先介绍一下命名实体识别任务数据集的常见标注格式:

  • BIO: B(Begin)-X 实体X的开头;I(Inside)-X 实体X的内部;O(Outside) 不属于实体
  • BIOES: B(Begin)-X 实体X的开头;I(Inside)-X 实体X的中间;O(Outside) 不属于实体;E(End)-X 实体X的结尾;S(Singleton)-the single word是实体
  • BMES:B(Begin)-X 实体X的开头;M(Middle)-X 实体X的中间;E(End)-X 实体X的结尾;S(Singleton)-the single word是实体

比如:

Michael Jeffrey Jordan was born in Brooklyn , New   York   .
B-PER   I-PER   E-PER   O   O   O  S-LOC    O B-LOC E-LOC  O

FALT整体框架图

词典信息加入模型被证明对中文NER任务很有效,但是结合词典的方法通常会使输入变成一个动态的结构,导致无法有效利用GPU的并行计算。FLAT模型通过采用一个特殊的位置编码表征输入结构,从而不需要在运行时动态改变结构来表征输入。这里推荐去看作者的讲解视频 结合词典的中文命名实体识别

FLAT

数据处理

  1. 读取数据集
from fastNLP.io.loader import ConllLoader

def get_bigrams(words):
    result = []
    for i, w in enumerate(words):
        if i != len(words)-1:
            result.append(words[i]+words[i+1])
        else:
            result.append(words[i]+'')

    return result

train_path = os.path.join('/input/resume-ner', 'train.char.bmes')

loader = ConllLoader(['chars', 'target']) # header
train_bundle = loader.load(train_path)
datasets = dict()
datasets['train'] = train_bundle.datasets['train']
# 添加列 bigrams
datasets['train'].apply_field(get_bigrams, field_name='chars', new_field_name='bigrams')
# 添加列 seq_len
datasets['train'].add_seq_len('chars')

print(datasets['train'])

得到的输出格式为:

train examples

chars列为样本中的字符
target列为标签
bigrams列为两两相邻字符组成的双字
seq_len为chars列中字符的个数

  1. 提取vocab
from fastNLP import Vocabulary

char_vocab = Vocabulary()
bigram_vocab = Vocabulary()
label_vocab = Vocabulary()
# 根据列 field_name中的词构建词典
char_vocab.from_dataset(datasets['train'], field_name='chars') #  id:0,  id:1, 公 id:3 ...
bigram_vocab.from_dataset(datasets['train'], field_name='bigrams') #  id:0,  id:1, 公司 id:2 ...                
label_vocab.from_dataset(datasets['train'], field_name='target') #  id:0,  id:1, O id:2, M-ORG id:3 ...

根据数据集字段中的字符构建对应的词典vocab。

  1. 加载预训练embedding
embeddings = {}
    if char_embedding_path is not None:
        char_embedding = StaticEmbedding(char_vocab, char_embedding_path, word_dropout=0.01,
                                         min_freq=char_min_freq, only_train_min_freq=only_train_min_freq)
        embeddings['char'] = char_embedding

    if bigram_embedding_path is not None:
        bigram_embedding = StaticEmbedding(bigram_vocab, bigram_embedding_path, word_dropout=0.01,
                                           min_freq=bigram_min_freq, only_train_min_freq=only_train_min_freq)
        embeddings['bigram'] = bigram_embedding

    return datasets, vocabs, embeddings
  • char_embedding_path为预训练的单个字符的embedding向量。
  • bigram_embedding_path为预训练的双个字符的embedding向量。

给定预训练embedding的路径,StaticEmbdding函数根据vocab从embedding中抽取相应的数据(只会将出现在vocab中的词抽取出来,如果没有找到,则会随机初始化一个值(但如果该word是被标记为no_create_entry的话,则不会单独创建一个值,而是会被指向unk的index))。

  1. 融入词汇信息
w_list = load_yangjie_rich_pretrain_word_list(yangjie_rich_pretrain_word_path,
                                              _refresh=refresh_data,
                                              _cache_fp='cache/{}'.format(args.lexicon_name))

datasets,vocabs,embeddings = equip_chinese_ner_with_lexicon(datasets,vocabs,embeddings,
                                                            w_list,yangjie_rich_pretrain_word_path,
                                                            _refresh=refresh_data,_cache_fp=cache_name,
                                                            only_lexicon_in_train=args.only_lexicon_in_train,
                                                            word_char_mix_embedding_path=output_char_and_word_path,
                                                            number_normalized=args.number_normalized,
                                                            lattice_min_freq=args.lattice_min_freq,
                                                            only_train_min_freq=args.only_train_min_freq)

加载词典数据,得到w_list,词典中的词汇可包含两个,三个等多个字符。
equip_chinese_ner_with_lexicon函数用来将词汇信息lexicon写入样本中。

  • 得到词汇相关字段
    for k, v in datasets.items():
        # partial函数将一个函数的某些参数固定住,返回一个新函数
        v.apply_field(partial(get_skip_path, w_trie=w_trie), 'chars', 'lexicons')
        v.apply_field(copy.copy, 'chars', 'raw_chars')
        v.add_seq_len('lexicons', 'lex_num')
        v.apply_field(lambda x: list(map(lambda y: y[0], x)), 'lexicons', 'lex_s')
        v.apply_field(lambda x: list(map(lambda y: y[1], x)), 'lexicons', 'lex_e')

lexicons列为样本中匹配到的词汇信息,如[[0, 1, '中国'],[3, 5, '天安门']]
lex_num列为样本匹配到的词汇的个数
lex_s列为各个匹配词的起始索引列表,如[0, 3]
lex_e列为各个匹配词的终止索引列表,如[1, 5]

  1. 拼接原始字符串和词汇
    def concat(ins):
        chars = ins['chars']
        lexicons = ins['lexicons']
        result = chars + list(map(lambda x: x[2], lexicons))
        return result

    def get_pos_s(ins):
        lex_s = ins['lex_s']
        seq_len = ins['seq_len']
        pos_s = list(range(seq_len)) + lex_s
        return pos_s

    def get_pos_e(ins):
        lex_e = ins['lex_e']
        seq_len = ins['seq_len']
        pos_e = list(range(seq_len)) + lex_e
        return pos_e

    for k, v in datasets.items():
        v.apply(concat, new_field_name='lattice')
        v.set_input('lattice')
        v.apply(get_pos_s, new_field_name='pos_s')
        v.apply(get_pos_e, new_field_name='pos_e')
        v.set_input('pos_s', 'pos_e')

concat函数将词典lexicon中匹配到的词汇拼接到样本末尾,得到lattice
pos_s列记为论文中的Head
pos_e列即为论文中的Tail
这三列均被设置为Input

  1. 字符转成整数id
vocabs['char'].index_dataset(* (datasets.values()),
                                 field_name='chars', new_field_name='chars')
vocabs['bigram'].index_dataset(* (datasets.values()),
                                   field_name='bigrams', new_field_name='bigrams')
vocabs['label'].index_dataset(* (datasets.values()),
                                  field_name='target', new_field_name='target')
vocabs['lattice'].index_dataset(* (datasets.values()),
                                    field_name='lattice', new_field_name='lattice')

return datasets, vocabs, embeddings

最后通过各个vocab将datasets中的对应字符字段转成数字(vocab中的id)。Vocabulary类的主要作用就是实现字符和对应id之间的互相转换。

最终即得到了FLAT整体框架图中所需要的输入数据。

参考:
FLAT: Chinese NER Using Flat-Lattice Transformer (github.com)
论文阅读《FLAT:Chinese NER Using Flat-Lattice Transformer》
Flat-Lattice-Transformer模型源码测试

你可能感兴趣的:(FLAT代码解读(1)-输入)