角色标注

参考来源:https://www.paddlepaddle.org.cn/documentation/docs/zh/user_guides/nlp_case/label_semantic_roles/README.cn.html

1.源数据介绍

自然语言分析技术大致分为三个层面:词法分析、句法分析和语义分析。语义角色标注是实现浅层语义分析的一种方式。在一个句子中,谓词是对主语的陈述或说明,指出“做什么”、“是什么”或“怎么样,代表了一个事件的核心,跟谓词搭配的名词称为论元。语义角色是指论元在动词所指事件中担任的角色。主要有:施事者(Agent)、受事者(Patient)、客体(Theme)、经验者(Experiencer)、受益者(Beneficiary)、工具(Instrument)、处所(Location)、目标(Goal)和来源(Source)等。

请看下面的例子,“遇到” 是谓词(Predicate,通常简写为“Pred”),“小明”是施事者(Agent),“小红”是受事者(Patient),“昨天” 是事件发生的时间(Time),“公园”是事情发生的地点(Location)。

语义角色标注(Semantic Role Labeling,SRL)以句子的谓词为中心,不对句子所包含的语义信息进行深入分析,只分析句子中各成分与谓词之间的关系,即句子的谓词(Predicate)- 论元(Argument)结构,并用语义角色来描述这些结构关系,是许多自然语言理解任务(如信息抽取,篇章分析,深度问答等)的一个重要中间步骤。在研究中一般都假定谓词是给定的,所要做的就是找出给定谓词的各个论元和它们的语义角色。

2.神经网络结构

  1. 构造输入;
  • 输入1是谓词,输入2是句子
  • 将输入1扩展成和输入2一样长的序列,用one-hot方式表示;
  1. one-hot方式的谓词序列和句子序列通过词表,转换为实向量表示的词向量序列;
  2. 将步骤2中的2个词向量序列作为双向LSTM的输入,学习输入序列的特征表示;
  3. CRF以步骤3中模型学习到的特征为输入,以标记序列为监督信号,实现序列标注;

大家可以尝试上面这种方法。这里,我们提出一些改进,引入两个简单但对提高系统性能非常有效的特征:

  • 谓词上下文:上面的方法中,只用到了谓词的词向量表达谓词相关的所有信息,这种方法始终是非常弱的,特别是如果谓词在句子中出现多次,有可能引起一定的歧义。从经验出发,谓词前后若干个词的一个小片段,能够提供更丰富的信息,帮助消解歧义。于是,我们把这样的经验也添加到模型中,为每个谓词同时抽取一个“谓词上下文” 片段,也就是从这个谓词前后各取nn个词构成的一个窗口片段;
  • 谓词上下文区域标记:为句子中的每一个词引入一个0-1二值变量,表示它们是否在“谓词上下文”片段中;

3.初始化环境

from __future__ import print_function

import math, os
import numpy as np
import paddle
import paddle.dataset.conll05 as conll05
import paddle.fluid as fluid
import six
import time

with_gpu = os.getenv(‘WITH_GPU‘, ‘0‘) != ‘0‘

word_dict, verb_dict, label_dict = conll05.get_dict()
word_dict_len = len(word_dict)
label_dict_len = len(label_dict)
pred_dict_len = len(verb_dict)

print(‘word_dict_len: ‘, word_dict_len)
print(‘label_dict_len: ‘, label_dict_len)
print(‘pred_dict_len: ‘, pred_dict_len)

 mark_dict_len = 2 # 谓上下文区域标志的维度,是一个0-1 2值特征,因此维度为2
 word_dim = 32 # 词向量维度
 mark_dim = 5 # 谓词上下文区域通过词表被映射为一个实向量,这个是相邻的维度
 hidden_dim = 512 # LSTM隐层向量的维度 : 512 / 4
 depth = 8 # 栈式LSTM的深度
 mix_hidden_lr = 1e-3 # linear_chain_crf层的基础学习率

IS_SPARSE = True # 是否以稀疏方式更新embedding
 PASS_NUM = 10 # 训练轮数
 BATCH_SIZE = 10 # batch size 大小

embedding_name = ‘emb‘

2.定义神经网络

use_cuda = False #在cpu上执行训练
save_dirname = "label_semantic_roles.inference.model" #训练得到的模型参数保存在文件中
is_local = True

word = fluid.data(
    name=‘word_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)

# 谓词
predicate = fluid.data(
    name=‘verb_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)

# 谓词上下文5个特征
ctx_n2 = fluid.data(
    name=‘ctx_n2_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)
ctx_n1 = fluid.data(
    name=‘ctx_n1_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)
ctx_0 = fluid.data(
    name=‘ctx_0_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)
ctx_p1 = fluid.data(
    name=‘ctx_p1_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)
ctx_p2 = fluid.data(
    name=‘ctx_p2_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)

# 谓词上下区域标志
mark = fluid.data(name=‘mark_data‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)

predicate_embedding = fluid.embedding(
    input=predicate,
    size=[pred_dict_len, word_dim],
    dtype=‘float32‘,
    is_sparse=IS_SPARSE,
    param_attr=‘vemb‘)

mark_embedding = fluid.embedding(
    input=mark,
    size=[mark_dict_len, mark_dim],
    dtype=‘float32‘,
    is_sparse=IS_SPARSE)

#句子序列和谓词上下文5个特征并预训练
word_input = [word, ctx_n2, ctx_n1, ctx_0, ctx_p1, ctx_p2]
# 因词向量是预训练好的,这里不再训练embedding表,
# 参数属性trainable设置成False阻止了embedding表在训练过程中被更新
emb_layers = [
    fluid.embedding(
        size=[word_dict_len, word_dim],
        input=x,
        param_attr=fluid.ParamAttr(
            name=embedding_name, trainable=False)) for x in word_input
]
#加入谓词和谓词上下区域标志的预训练结果
emb_layers.append(predicate_embedding)
emb_layers.append(mark_embedding)

hidden_0_layers = [
    fluid.layers.fc(input=emb, size=hidden_dim, act=‘tanh‘)
    for emb in emb_layers
]

hidden_0 = fluid.layers.sums(input=hidden_0_layers)

lstm_0 = fluid.layers.dynamic_lstm(
    input=hidden_0,
    size=hidden_dim,
    candidate_activation=‘relu‘,
    gate_activation=‘sigmoid‘,
    cell_activation=‘sigmoid‘)

# 用直连的边来堆叠L-LSTM、R-LSTM
input_tmp = [hidden_0, lstm_0]

# 其余的栈结构
for i in range(1, depth):
    mix_hidden = fluid.layers.sums(input=[
        fluid.layers.fc(input=input_tmp[0], size=hidden_dim, act=‘tanh‘),
        fluid.layers.fc(input=input_tmp[1], size=hidden_dim, act=‘tanh‘)
    ])

    lstm = fluid.layers.dynamic_lstm(
        input=mix_hidden,
        size=hidden_dim,
        candidate_activation=‘relu‘,
        gate_activation=‘sigmoid‘,
        cell_activation=‘sigmoid‘,
        is_reverse=((i % 2) == 1))

    input_tmp = [mix_hidden, lstm]

# 取最后一个栈式LSTM的输出和这个LSTM单元的输入到隐层映射,
# 经过一个全连接层映射到标记字典的维度,来学习 CRF 的状态特征
feature_out = fluid.layers.sums(input=[
    fluid.layers.fc(input=input_tmp[0], size=label_dict_len, act=‘tanh‘),
    fluid.layers.fc(input=input_tmp[1], size=label_dict_len, act=‘tanh‘)
])

3.损失函数

target = fluid.data(
    name=‘target‘, shape=[None, 1], dtype=‘int64‘, lod_level=1)

# 学习 CRF 的转移特征
crf_cost = fluid.layers.linear_chain_crf(
    input=feature_out,
    label=target,
    param_attr=fluid.ParamAttr(
        name=‘crfw‘, learning_rate=mix_hidden_lr))

avg_cost = fluid.layers.mean(crf_cost)

# 使用最基本的SGD优化方法(momentum设置为0)
sgd_optimizer = fluid.optimizer.SGD(
    learning_rate=fluid.layers.exponential_decay(
        learning_rate=0.01,
        decay_steps=100000,
        decay_rate=0.5,
        staircase=True))

sgd_optimizer.minimize(avg_cost)

这里的损失函数使用的crf,以计算到的标记去标记真实的标记,得到P(Y|X)最新为目标

4.训练数据

crf_decode = fluid.layers.crf_decoding(input=feature_out, param_attr=fluid.ParamAttr(name=‘crfw‘))

train_data = paddle.batch(paddle.reader.shuffle(paddle.dataset.conll05.test(), buf_size=8192), batch_size=BATCH_SIZE)

place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()

feeder = fluid.DataFeeder(
    feed_list=[
        word, ctx_n2, ctx_n1, ctx_0, ctx_p1, ctx_p2, predicate, mark, target
    ],
    place=place)
exe = fluid.Executor(place)

main_program = fluid.default_main_program()

exe.run(fluid.default_startup_program())
embedding_param = fluid.global_scope().find_var(
    embedding_name).get_tensor()
embedding_param.set(
    load_parameter(conll05.get_embedding(), word_dict_len, word_dim),
    place)

start_time = time.time()
batch_id = 0
for pass_id in six.moves.xrange(PASS_NUM):
    for data in train_data():
        cost = exe.run(main_program,
                       feed=feeder.feed(data),
                       fetch_list=[avg_cost])
        cost = cost[0]

        if batch_id % 10 == 0:
            print("avg_cost: " + str(cost))
            if batch_id != 0:
                print("second per batch: " + str((time.time(
                ) - start_time) / batch_id))
            # Set the threshold low to speed up the CI test
            if float(cost) < 60.0:
                if save_dirname is not None:
                    fluid.io.save_inference_model(save_dirname, [
                        ‘word_data‘, ‘verb_data‘, ‘ctx_n2_data‘,
                        ‘ctx_n1_data‘, ‘ctx_0_data‘, ‘ctx_p1_data‘,
                        ‘ctx_p2_data‘, ‘mark_data‘
                    ], [feature_out], exe)
                break

        batch_id = batch_id + 1

原文地址:https://www.cnblogs.com/yangyang12138/p/12596322.html

时间: 2024-10-14 01:42:19

角色标注的相关文章

层叠HMM-Viterbi角色标注模型下的地名识别

命名实体识别中最难的部分当属实体机构名了,这是因为机构名的组成成分十分复杂,可以是人名.地名.序数词.企业字号甚至是上级机构名.本文介绍一种基于角色标注的层叠HMM模型下中文机构名识别方法.目前代码已整合到HanLP中,即将开源.原理基本原理请参考<实战HMM-Viterbi角色标注地名识别>,不再赘述.与人名和地名识别稍有不同的是,在命名实体识别之前,需要先执行人名和地名识别,将粗分结果送入HMM模型求解,得出细分结果后才能进行,这是因为人名和地名也是机构名中的常见成分.这是与<实战H

实战HMM-Viterbi角色标注地名识别

命名实体识别(Named Entity Recognition)也是自然语言处理中的一个难关,特别是中文这样没有大小写等固定形态的语言.上次介绍过<实战HMM-Viterbi角色标注中国人名识别>,这次基于类似的原理,为HanLP实现中文地址地名(NS)的自动识别.原理训练对熟语料自动角色标注,统计单词的角色频次.角色的转移概率等,训练出一个模型,同时总结一些可用的模式串.识别根据上述模型,利用HMM-Viterbi算法标注陌生文本,利用Aho-Corasick算法模式匹配,匹配出可能的地址,

使用RNN解决NLP中序列标注问题的通用优化思路

/* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/ author: 张俊林 序列标注问题应该说是自然语言处理中最常见的问题,而且很可能是最而没有之一.在深度学习没有广泛渗透到各个应用领域之前,传统的最常用的解决序列标注问题的方案是最大熵.CRF等模型,尤其是CRF,基本是最主流的方法.随着深度学习的不断探索和发展,很可能RNN模型会取代CRF的传统霸主地位,会成为解决序列标注问题的标配解决方案. 本文主要抽象出利用RNN解决序列标注问题的通用优化思路.这个RNN优化思路应该

转:使用RNN解决NLP中序列标注问题的通用优化思路

http://blog.csdn.net/malefactor/article/details/50725480 /* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/ author: 张俊林 序列标注问题应该说是自然语言处理中最常见的问题,而且很可能是最而没有之一.在深度学习没有广泛渗透到各个应用领域之前,传统的最常用的解决序列标注问题的方案是最大熵.CRF等模型,尤其是CRF,基本是最主流的方法.随着深度学习的不断探索和发展,很可能RNN模型会取代CRF的传统霸主地位,会成

编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码

转自:编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码 JDK:java version “1.8.0_31”Java(TM) SE Runtime Environment (build 1.8.0_31-b13)Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)OS:win7 64bitcmake:V2.8.12/V3.2.2LTP:V3.2.0LTP4J:V1.0Microsoft VS C+

LTP语言云API使用文档

简介 语言云新版API是REST风格的WEB API调用服务,REST API服务有诸多优点,这使得它越来越流行.应用于语言云服务中,主要有如下特点: 免SDK安装:REST API的调用无须用户下载SDK,使得语言分析更为便捷. 结果表示格式丰富:API提供了包括PLAIN/XML/JSON/CONLL等多种格式的结果表示.且返回结果容易扩展,便于进行二次开发. 支持JavaScript调用:语言云支持JavaScript以JSON-P回调的方式调用API,使得返回结果可以嵌入到Web页面或者

浅谈自然语言处理基础(下)

命名实体识别 命名实体的提出源自信息抽取问题,即从报章等非结构化文本中抽取关于公司活动和国防相关活动的结构化信息,而人名.地名.组织机构名.时间和数字表达式结构化信息的关键内容,所以需要从文本中去识别这些实体指称及其类别,即命名实体识别和分类. 21世纪以后,基于大规模语料库的统计方法成为自然语言处理的主流,以下是基于统计模型的命名实体识别方法归纳: 基于CRF的命名实体识别方法 基于CRF的命名实体识别方法简便易行,而且可以获得较好的性能,广泛地应用于人名.地名和组织机构等各种类型命名实体的识

Python下的自然语言处理利器-LTP语言技术平台 pyltp 学习手札

1 什么是pyltp 语言技术平台(LTP) 是由 哈工大社会计算与信息检索研究中心 11 年的持续研发而形成的一个自然语言处理工具库,其提供包括中文分词.词性标注.命名实体识别.依存句法分析.语义角色标注等丰富. 高效.精准的自然语言处理技术.LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法.句法.语义等6项中文处理核心技术),以及基于动态链接库(Dynamic Link Library, DLL)的应用程序接口,可视化工具,

NLP:language model(n-gram/Word2Vec/Glove)

首先,大概讲一下自然语言处理的背景.互联网上充斥着大规模.多样化.非结构化的自然语言描述的文本,如何较好的理解这些文本,服务于实际业务系统,如搜索引擎.在线广告.推荐系统.问答系统等, 给我们提出了挑战.例如在效果广告系统中,需要将 Query(User or Page) 和广告 Ad 投影到相同的特征语义空间做精准匹配,如果 Query 是用户,需要基于用户历史数据离线做用户行为分析,如果 Query 是网页,则需要离线或实时做网页语义分析.文本语义分析(又称文本理解.文本挖掘)技术研究基于词