实体识别-0

实体识别的领域是建筑领域,处理的文本是《地铁设计规范》,2014 年 3 月 1 日开始施行的。
参考的基准代码是https://github.com/Determined22/zh-NER-TF,该源码设计的模型,参考的论文是这两篇,Bidirectional LSTM-CRF Models for Sequence Tagging
和Neural Architectures for Named Entity Recognition
(注:但是目前写这一篇时,尚未将代码和论文模型进行比对)
现将所更改的一些内容,进行记录。
1.因为我的实体类别粗粒度分为6类,细粒度分为18类,因此默认写死的tag2lable显得不太灵活

tag2label.png

并且对应于字编号,我将这一变量更名为tag2id,同时因为字编号的使用方式是写入文件,由使用方进行读取使用,所以tag2id也写入文件,分开两个文件写(TODO:可以写入同一个文件,参考ChineseNER这个代码的写法)
代码位置:data.py/vocab_build

def vocab_build(vocab_dir, corpus_path, min_count):
    """

    :param vocab_dir:
    :param corpus_path:
    :param min_count:
    :return:
    """
    data = read_corpus(corpus_path)
    # word2id筛选掉不满足字频的字,将其他字进行编号,并把英文用,数字用,然后再给未来没有在字典中的字留一个
    # 用来代替,把不满足统一句子长度的句子用进行填充,形成这样子的一个字典;其中编号为0,为最大编号
    # word2id = {'': 0, '': , '': , .. '': , '': , ..  '': , '': , ..  '': }
    word2id = {}
    tag2id = {}
    tag_id = 0
    for sent_, tag_ in data:
        for word in sent_:
            if word.isdigit():
                word = ''
            # A-Z, a-z
            elif ('\u0041' <= word <='\u005a') or ('\u0061' <= word <='\u007a'):
                word = ''
            if word not in word2id:
                word2id[word] = [len(word2id)+1, 1]
            else:
                word2id[word][1] += 1

        for tag in tag_:
            if tag not in tag2id:
                tag2id[tag] = tag_id
                tag_id += 1
    low_freq_words = []
    for word, [word_id, word_freq] in word2id.items(): # 其实这个word_id真的没用到,表示字加入字典时的序号
        if word_freq < min_count and word != '' and word != '':
            low_freq_words.append(word)
    for word in low_freq_words:
        del word2id[word]

    # 后面修改一下按照字频去编号,这个也是参考https://github.com/zjy-ucas/ChineseNER
    new_id = 1
    for word in word2id.keys():
        word2id[word] = new_id
        new_id += 1
    word2id[''] = new_id # 查找表中没有对应的自嵌入,被替换成UNK,使用UNK对应的嵌入
    word2id[''] = 0 # 为了保证每个batch句子长度一致,用PAD对应嵌入填充句子

    # print(len(word2id))
    word_vocab_path = os.path.join(vocab_dir, 'word2id.pkl')
    with open(word_vocab_path, 'wb') as fw:
        pickle.dump(word2id, fw) # 将对象写入打开的文件中,二进制;反序列化load()

    tag_vocab_path = os.path.join(vocab_dir, 'tag2id.pkl')
    with open(tag_vocab_path, 'wb') as fw:
        pickle.dump(tag2id, fw)

2.适应tag2id和word2id的使用方式
原有main.py中,只读取word2id,因为tag2id是写死的,如下图


读取word2id.png

改为


i读取word2id和tag2id.png

对应这个参数是文件夹,因此,将data.py/read_dictionary修改如下
def read_dictionary(vocab_dir):
    """
    读取字典文件
    :param vocab_path:
    :return:
    """
    word_vocab_path = os.path.join(vocab_dir, 'word2id.pkl')
    with open(word_vocab_path, 'rb') as fr:
        word2id = pickle.load(fr)
    print('vocab_size:', len(word2id))
    tag_vocab_path = os.path.join(vocab_dir, 'tag2id.pkl')
    with open(tag_vocab_path, 'rb') as fr:
        tag2id = pickle.load(fr)
    print('vocab_size:', len(tag2id))
    return word2id, tag2id

3.在这个预处理得到字编号的过程中,将不满足字频的字进行了删除,具体逻辑在data.py/vocab_build,字频限制使用min_count这个变量,对了,在开始训练前,需要先得到字编号和标签编号,因此首先需要在data.py中,我首先设置的词频是3,这个后面也可以作为要调的一个参数

if __name__ == '__main__':
    '''
    vocab_dir = 'data_path/rail_data18'
    corpus_path = 'data_path/rail_data18/train_data'
    '''
    vocab_dir = 'data_path/rail_data6'
    corpus_path = 'data_path/rail_data6/train_data'
    min_count = 3
    vocab_build(vocab_dir, corpus_path, min_count)
    word2id, tag2id = read_dictionary(vocab_dir)
    print(word2id)
    print(tag2id)

4.将结果写入部分,进行了改动,源码中是unicode了,改为不进行编码

not encode.png

5.main.py中将训练数据的默认路径进行修改,如图
数据文件默认位置.png

源代码中是将测试数据用作验证用,但我有构造出验证数据,因此使用验证数据进行验证
dev_test1.png

dev_test2.png

6.添加perl语言的解析环境
windows
activeperl官网下载安装,命令行perl -v检查安装成功,但是需要重启电脑才能被识别到
linux
检查是否已经安装:perl -v,没有直接用rpm安装就可以了
7.将数据集放入相应的位置,就可以跑起来代码了
训练命令:python main.py --mode=train
测试命令:python main.py --mode=test --demo_model=1608281271(后面那个数字为训练的模型)

你可能感兴趣的:(实体识别-0)