ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

BISTML-CRF项目源码

2021-04-25 19:59:03  阅读:224  来源: 互联网

标签:name tags train len 源码 CRF time pickle BISTML


BILSTM-CRF项目源码

结构

data

boson数据集分析

oragindata

{{product_name:浙江在线杭州}}{{time:4月25日}}讯(记者{{person_name: 施宇翔}} 通讯员 {{person_name:方英}})毒贩很“时髦”,用{{product_name:微信}}交易毒品。没料想警方也很“潮”,将计就计,一举将其擒获。记者从{{org_name:杭州江干区公安分局}}了解到,经过一个多月的侦查工作,{{org_name:江干区禁毒专案组}}抓获吸贩毒人员5名,缴获“冰毒”400余克,毒资30000余元,扣押汽车一辆。{{location:黑龙江}}籍男子{{person_name:钱某}}长期落脚于宾馆、单身公寓,经常变换住址。他有一辆车,经常半夜驾车来往于{{location:杭州主城区}}的各大宾馆和单身公寓,并且常要活动到{{time:凌晨6、7点钟}},{{time:白天}}则在家里呼呼大睡。{{person_name:钱某}}不寻常的特征,引起了警方注意。禁毒大队通过侦查,发现{{person_name:钱某}}实际上是在向落脚于宾馆和单身公寓的吸毒人员贩送“冰毒”。

第一层处理:实现对单个字打标签,具体实现:按照括号配对," : "左边的是tag,右边的是word。再将标签分为开始,中间,结束,分别给word中的每个字打tag。给没有“{{ }}”的每个字打上/o。将处理后的文件输入wordtag中。

def origin2tag():
    input_data = codecs.open('./origindata.txt','r','utf-8')
    output_data = codecs.open('./wordtag.txt','w','utf-8')
    # 一个line是一个待分析的实例
    for line in input_data.readlines():
        # 将line中的词组分出来
        line=line.strip()
        i=0 #读取词的时候计数
        while i <len(line):
            if line[i] == '{':
                i+=2
                temp=""
                while line[i]!='}':
                    temp+=line[i]
                    i+=1
                i+=2
                # ":"左边是标签,右边是实体
                word=temp.split(':')
                sen = word[1]
                # 给词组打开始,中间和结束
                output_data.write(sen[0]+"/B_"+word[0]+" ")
                for j in sen[1:len(sen)-1]:
                    output_data.write(j+"/M_"+word[0]+" ")
                output_data.write(sen[-1]+"/E_"+word[0]+" ")
            else:
                output_data.write(line[i]+"/O ")
                i+=1
        output_data.write('\n')
    input_data.close()
    output_data.close()

wordtag

浙/B_product_name 江/M_product_name 在/M_product_name 线/M_product_name 杭/M_product_name 州/E_product_name 4/B_time 月/M_time 2/M_time 5/M_time 日/E_time 讯/O (/O 记/O 者/O  /B_person_name 施/M_person_name 宇/M_person_name 翔/E_person_name  /O 通/O 讯/O 员/O  /O 方/B_person_name 英/E_person_name )/O 毒/O 贩/O 很/O “/O 时/O 髦/O ”/O ,/O 用/O 微/B_product_name 信/E_product_name 交/O 易/O 毒/O 品/O 。/O 没/O 料/O 想/O 警/O 方/O 也/O 很/O “/O 潮/O ”/O ,/O 将/O 计/O 就/O 计/O ,/O 一/O 举/O 将/O 其/O 擒/O 获/O 。/O 记/O 者/O 从/O 杭/B_org_name 州/M_org_name 江/M_org_name 干/M_org_name 区/M_org_name 公/M_org_name 安/M_org_name 分/M_org_name 局/E_org_name 了/O 解/O 到/O ,/O 经/O 过/O 一/O 个/O 多/O 月/O 的/O 侦/O 查/O 工/O 作/O ,/O 江/B_org_name 干/M_org_name 区/M_org_name 禁/M_org_name 毒/M_org_name 专/M_org_name 案/M_org_name 组/E_org_name 抓/O 获/O 吸/O 贩/O 毒/O 人/O 员/O 5/O 名/O ,/O 缴/O 获/O “/O 冰/O 毒/O ”/O 4/O 0/O 0/O 余/O 克/O ,/O 毒/O 资/O 3/O 0/O 0/O 0/O 0/O 余/O 元/O ,/O 扣/O 押/O 汽/O 车/O 一/O 辆/O 。/O 黑/B_location 龙/M_location 江/E_location 籍/O 男/O 子/O 钱/B_person_name 某/E_person_name 长/O 期/O 落/O 脚/O 于/O 宾/O 馆/O 、/O 单/O 身/O 公/O 寓/O ,/O 经/O 常/O 变/O 换/O 住/O 址/O 。/O 他/O 有/O 一/O 辆/O 车/O ,/O 经/O 常/O 半/O 夜/O 驾/O 车/O 来/O 往/O 于/O 杭/B_location 州/M_location 主/M_location 城/M_location 区/E_location 的/O 各/O 大/O 宾/O 馆/O 和/O 单/O 身/O 公/O 寓/O ,/O 并/O 且/O 常/O 要/O 活/O 动/O 到/O 凌/B_time 晨/M_time 6/M_time 、/M_time 7/M_time 点/M_time 钟/E_time ,/O 白/B_time 天/E_time 则/O 在/O 家/O 里/O 呼/O 呼/O 大/O 睡/O 。/O 钱/B_person_name 某/E_person_name 不/O 寻/O 常/O 的/O 特/O 征/O ,/O 引/O 起/O 了/O 警/O 方/O 注/O 意/O 。/O 禁/O 毒/O 大/O 队/O 通/O 过/O 侦/O 查/O ,/O 发/O 现/O 钱/B_person_name 某/E_person_name 实/O 际/O 上/O 是/O 在/O 向/O 落/O 脚/O 于/O 宾/O 馆/O 和/O 单/O 身/O 公/O 寓/O 的/O 吸/O 毒/O 人/O 员/O 贩/O 送/O “/O 冰/O 毒/O ”/O 。/O 

第二层处理:# 按照标点符号进行分段

# 文本处理阶段二
# 逻辑分段(标点符号)
def tagsplit():
    with open('./wordtag.txt','rb') as inp:
        texts = inp.read().decode('utf-8')
    sentences = re.split('[,。!?、‘’“”()]/[O]', texts)
    output_data = codecs.open('./wordtagsplit.txt','w','utf-8')
    for sentence in sentences:
        if sentence != " ":
            output_data.write(sentence.strip()+'\n')
    output_data.close()

浙/B_product_name 江/M_product_name 在/M_product_name 线/M_product_name 杭/M_product_name 州/E_product_name 4/B_time 月/M_time 2/M_time 5/M_time 日/E_time 讯/O

第三层处理:制作对应数据,单个字对应的id,tag对应的id,tag对应的字,训练用的数据集

def data2pkl():
    datas = list()
    labels = list()
    linedata=list()
    linelabel=list()
    tags = set()

    # 将标注的文本进行数据处理(获取实体文本以及标签,分别存入两个list datas labels,且一一对应,用集合tag统计存在多少种类型的标签)
    input_data = codecs.open('./wordtagsplit.txt','r','utf-8')  #处理已经打好标签的文本
    for line in input_data.readlines():
        line = line.split()
        linedata=[]
        linelabel=[]
        numNotO=0
        for word in line:
            word = word.split('/') #数据中每个词对用空格隔开,每个词和对应的标签使用“/”分隔符隔开的
            linedata.append(word[0])
            linelabel.append(word[1])
            tags.add(word[1])
            if word[1]!='O':  #o不是我们所需要识别的内容的标签
                numNotO+=1
        if numNotO!=0:
            datas.append(linedata)
            labels.append(linelabel)
    input_data.close()

    print(len(datas),tags)
    print(len(labels))

    # 实体打id
#    from compiler.ast import flatten
    all_words = flatten(datas)
    sr_allwords = pd.Series(all_words) #给words打对应的id
    sr_allwords = sr_allwords.value_counts() #统计各word出现的次数,且按照由高到低排列
    set_words = sr_allwords.index
    set_ids = list(range(1, len(set_words)+1))

    # 标签打id
    tags = [i for i in tags]
    tag_ids = list(range(len(tags)))

    # 四种二元关系
    word2id = pd.Series(set_ids, index=set_words)
    id2word = pd.Series(set_words, index=set_ids)
    tag2id = pd.Series(tag_ids, index=tags)
    id2tag = pd.Series(tags, index=tag_ids)

    # 给找不到的实体单独打一个id
    word2id["unknow"] = len(word2id)+1
    print(word2id)

    # 每60个词打包在一起,不足的就截断到60个词
    max_len = 60
    def X_padding(words):
        ids = list(word2id[words])
        if len(ids) >= max_len:  
            return ids[:max_len]
        ids.extend([0]*(max_len-len(ids))) 
        return ids

    def y_padding(tags):
        ids = list(tag2id[tags])
        if len(ids) >= max_len: 
            return ids[:max_len]
        ids.extend([0]*(max_len-len(ids))) 
        return ids

    #建立word和tag的一一对应的二维表,行名是顺序数字
    df_data = pd.DataFrame({'words': datas, 'tags': labels}, index=list(range(len(datas))))
    # 填充数据
    df_data['x'] = df_data['words'].apply(X_padding)
    df_data['y'] = df_data['tags'].apply(y_padding)
    # 数据结构化
    x = np.asarray(list(df_data['x'].values))
    y = np.asarray(list(df_data['y'].values))

    # 划分数据集(训练:验证:测试 =0.66 : 0.16 : 0.2)
    from sklearn.model_selection import train_test_split
    x_train,x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=43)
    x_train, x_valid, y_train, y_valid = train_test_split(x_train, y_train,  test_size=0.2, random_state=43)


    # 将结构化后的数据送入pkl中存储
    import pickle
    import os
    with open('../Bosondata.pkl', 'wb') as outp:
        pickle.dump(word2id, outp)
        pickle.dump(id2word, outp)
        pickle.dump(tag2id, outp)
        pickle.dump(id2tag, outp)
        pickle.dump(x_train, outp)
        pickle.dump(y_train, outp)
        pickle.dump(x_test, outp)
        pickle.dump(y_test, outp)
        pickle.dump(x_valid, outp)
        pickle.dump(y_valid, outp)
    print('** Finished saving the data.')
import collections
# 数据拉成一维的
def flatten(x):
    result = []
    for el in x:
        if isinstance(x, collections.Iterable) and not isinstance(el, str):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

BILSTM-CRF

具体解析
数据在BISTM-CRF层中的整个流程:

Created with Raphaël 2.2.0 数据进入 lstm训练得到每个词的标签分数 crf层对lstm层输出的标签序列进行路程打分

实现:

  • 初始化模型
  • 前馈
  • 损失函数
  • 反馈
    (具体解析详见链接)

train

加载处理过的数据

with open('../data/Bosondata.pkl', 'rb') as inp:
	word2id = pickle.load(inp)
	id2word = pickle.load(inp)
	tag2id = pickle.load(inp)
	id2tag = pickle.load(inp)
	x_train = pickle.load(inp)
	y_train = pickle.load(inp)
	x_test = pickle.load(inp)
	y_test = pickle.load(inp)
	x_valid = pickle.load(inp)
	y_valid = pickle.load(inp)

设置初始值

START_TAG = "<START>"
STOP_TAG = "<STOP>"
EMBEDDING_DIM = 100
HIDDEN_DIM = 200
EPOCHS = 5

tag2id[START_TAG]=len(tag2id)
tag2id[STOP_TAG]=len(tag2id)

模型

model = BiLSTM_CRF(len(word2id)+1, tag2id, EMBEDDING_DIM, HIDDEN_DIM)

优化器

optimizer = optim.SGD(model.parameters(), lr=0.005, weight_decay=1e-4)

训练

    for sentence, tags in zip(x_train,y_train):
        index+=1
        model.zero_grad()

	    # 数据处理的时候已将word转换成id进行存储
        # sentence = torch.tensor([word2id[w] for w in sentence], dtype=torch.long)
        # 数据处理的时候已将tag转换成id进行存储
        # tags = torch.tensor([tag2id[t] for t in tags], dtype=torch.long)
        sentence = torch.tensor(sentence)
        tags = torch.tensor(tags)

        loss = model.neg_log_likelihood(sentence, tags)

        loss.backward()
        optimizer.step()
        if index%30==0:
            print("epoch", epoch, "index", index)

测试

 entityres=[]
    entityall=[]
    for sentence, tags in zip(x_test,y_test):
        sentence=torch.tensor(sentence, dtype=torch.long)
        score,predict = model(sentence)
        sentence = sentence.numpy().tolist()
        tags = tags.tolist()
        entityres = calculate(sentence,predict,id2word,id2tag,entityres)
        entityall = calculate(sentence,tags,id2word,id2tag,entityall)
    jiaoji = [i for i in entityres if i in entityall]
    if len(jiaoji)!=0:
        zhun = float(len(jiaoji))/len(entityres)
        zhao = float(len(jiaoji))/len(entityall)
        print("test:")
        print("zhun:", zhun)
        print("zhao:", zhao)
        print("f:", (2 * zhun * zhao) / (zhun + zhao))
    else:
        print("zhun:",0)

保存模型

 path_name = "./model"+str(epoch)+".pkl"
    print(path_name)
    torch.save(model, path_name)
    print("model has been saved")

模型能力

epoch=1
train len: 1216
test len: 380
在这里插入图片描述
在这里插入图片描述

epoch=1
train len: 1600
test len: 500
在这里插入图片描述

迁移MSRA数据集

数据处理

  • 分割数据集中的data和lable
    • 按行将单词提取到列表中
      • 按照bme格式,给单字打label
  • 按逻辑(’[,。!?、‘’“”()]/[O]’)分行
  • 自定义tag2id&&id2tag
  • 制作数据集(分单词,分单字,数据拉成一维)
  • 通过pd.Series()给word打id
  • 将word转成id,tag转成id,并进行数据规范(通过填充或删减将其长度固定)
  • 划分训练集,测试集,验证集

注意:生成 tag2id 时,应该将空设置成 id = 0,否则在进行padding时用 0填充会打上其他标签!!!!!影响整个模型的训练
数据集一定要仔细仔细再仔细!!!否则可能有test数据集无法验证,训练出的模型根本没有识别能力等等等问题!!!!,tag如果不多建议自定义,在msra数据集中,自动生成tag2id和id2tag存在bug

BILSTM-CRF&&resuleCal

直接用现成的

训练

  • 定model,loss,optimizer

  • START_TAG
    STOP_TAG
    EMBEDDING_DIM
    HIDDEN_DIM
    EPOCHS
  • 通过训练集进行训练
  • 通过测试集验证准确率
  • 保存模型

模型能力

train len: 1440
test len: 200
valid len 360
epoch = 1
在这里插入图片描述
train len: 1440
test len: 200
valid len 360
epoch = 1
在这里插入图片描述

处理brat标注后的数据

天池瑞金医院MMC人工智能辅助构建知识图谱大赛
代码数据集采用txt+ann类型,与brat相同,参考该代码进行分析

  • def clean_ann(): ann数据将其lable和对应txt中的位置提取出来存在csv中
  • **def word_level_tag2(filename)

    标签:name,tags,train,len,源码,CRF,time,pickle,BISTML
    来源: https://blog.csdn.net/weixin_45675311/article/details/116034305

    本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
    2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
    3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
    4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
    5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有