语义依存分析

定义(ltp)

语义依存分析 (Semantic Dependency Parsing, SDP),分析句子各个语言单位之间的语义关联,并将语义关联以依存结构呈现。
使用语义依存刻画句子语义,好处在于不需要去抽象词汇本身,而是通过词汇所承受的语义框架来描述该词汇,而论元的数目相对词汇来说数量总是少了很多的。
语义依存分析目标是跨越句子表层句法结构的束缚,直接获取深层的语义信息。
例如以下三个句子,用不同的表达方式表达了同一个语义信息,即张三实施了一个吃的动作,吃的动作是对苹果实施的。

语义依存分析不受句法结构的影响,将具有直接语义关联的语言单元直接连接依存弧并标记上相应的语义关系。这也是语义依存分析与句法依存分析的重要区别。

如上例对比了句法依存和语义分析的结果,可以看到两者存在两个显著差别。
第一,句法依存某种程度上更重视非实词(如介词)在句子结构分析中的作用,而语义依存更倾向在具有直接语义关联的实词之间建立直接依存弧,非实词作为辅助标记存在。
第二,两者依存弧上标记的语义关系完全不同,语义依存关系是由论元关系引申归纳而来,可以用于回答问题,如我在哪里喝汤,我在用什么喝汤,谁在喝汤,我在喝什么。但是句法依存却没有这个能力。
第三,句法依存为树结构,语义依存为图结构,即是说当前词的依存弧可以有多个。

语义依存与语义角色标注之间也存在关联,语义角色标注只关注句子主要谓词的论元及谓词与论元之间的关系,而语义依存不仅关注谓词与论元的关系,还关注谓词与谓词之间、论元与论元之间、论元内部的语义关系。语义依存对句子语义信息的刻画更加完整全面。

实现

https://github.com/geasyheart/semantic-dependency-parser

欢迎Star!

1. 数据集

目前貌似公开的只有SEMEVAL2016数据集,地址在:HIT-SCIR/SemEval-2016,代码仓库中的数据集是将text和news两类合并而来。

额外插一句,对于一个算法项目来讲,不仅仅是算法部分,还要有数据,即使不能公开,也可以造一些例子,能够跑通算法,HanLP在这方面真的是无敌存在!

2. 模型结构

  • 这里使用到的模型结构:
1
2
3
4
5
6
7
8
9
10
11
semantic_dependency_parser.py [line:34] INFO SemanticDependencyModel(
(encoder): TransformerEmbedding(hfl/chinese-electra-180g-small-discriminator, n_layers=4, n_out=256, stride=256, pooling=mean, pad_index=0, dropout=0.33, requires_grad=True)
(tag_embedding): Embedding(41, 64)
(edge_mlp_d): MLP(n_in=320, n_out=600, dropout=0.33)
(edge_mlp_h): MLP(n_in=320, n_out=600, dropout=0.33)
(label_mlp_d): MLP(n_in=320, n_out=600, dropout=0.33)
(label_mlp_h): MLP(n_in=320, n_out=600, dropout=0.33)
(edge_attn): Biaffine(n_in=600, n_out=2, bias_x=True, bias_y=True)
(label_attn): Biaffine(n_in=600, n_out=158, bias_x=True, bias_y=True)
(criterion): CrossEntropyLoss()
)
  • HanLP使用的模型结构:
1
2
3
4
5
6
7
8
9
10
11
BiaffineDependencyModel(
(encoder): EncoderWithContextualLayer()
(biaffine_decoder): BiaffineDecoder(
(mlp_arc_h): MLP(n_in=256, n_out=500, dropout=0.33)
(mlp_arc_d): MLP(n_in=256, n_out=500, dropout=0.33)
(mlp_rel_h): MLP(n_in=256, n_out=100, dropout=0.33)
(mlp_rel_d): MLP(n_in=256, n_out=100, dropout=0.33)
(arc_attn): Biaffine(n_in=500, n_out=1, bias_x=True)
(rel_attn): Biaffine(n_in=100, n_out=136, bias_x=True, bias_y=True)
)
)

和dependency parser结构相同,但是loss计算和解码部分不同。

区别点在于,举个例子:

1
2
3
4
# pred_arcs.shape
(32, 49, 49)
# true_arcs.shape
(32, 49)

因为dependency parser有一个限制,即当前词只可能依存其他一个词,那么argmax(-1)即是在49那里获取最大的,表示和这49个词中最大的作为依存关系,使用交叉熵。

而semantic dependency parser没有这个限制,当前词可能和多个词存在依存关系,那么他的pred_arcs和true_arcs的维度是一样的,都是(32, 49, 49),所以使用BCELoss。

当然也可以用交叉熵,只需要将pred_arcs的维度转换成(32, 49, 49, 2)即可,也是我下面的做法。

3. loss计算和解码

这里计算loss时,采用的是交叉熵,也就是说s_edge.size(-1) == 2,表示当前词和句子所有词之间或者,然后argmax(-1)进行解码。

HanLP计算loss时,对于arc(即edge)的shape为(batch_size, seq_length, seq_length),因为biaffine的输出维度为1,所以这里计算loss时使用BCELoss,表示当前词和句子所有词之间是否存在关系。

另外一个两者的区别点在于计算rel时,HanLP采取的方式是各自计算各自的loss(即arc和rel),然后loss相加。
这里计算rel loss时融合了arc的信息进来,好处就在于能够快速收敛和提升准确度吧。

各模块技术指标

https://www.ltp-cloud.com/intro#benchmark

ltp关系类型

关系类型TagDescriptionExample
施事关系AgtAgent我送她一束花 (我 <-- 送)
当事关系ExpExperiencer我跑得快 (跑 --> 我)
感事关系AftAffection我思念家乡 (思念 --> 我)
领事关系PossPossessor他有一本好读 (他 <-- 有)
受事关系PatPatient他打了小明 (打 --> 小明)
客事关系ContContent他听到鞭炮声 (听 --> 鞭炮声)
成事关系ProdProduct他写了本小说 (写 --> 小说)
源事关系OrigOrigin我军缴获敌人四辆坦克 (缴获 --> 坦克)
涉事关系DatvDative他告诉我个秘密 ( 告诉 --> 我 )
比较角色CompComitative他成绩比我好 (他 --> 我)
属事角色BelgBelongings老赵有俩女儿 (老赵 <-- 有)
类事角色ClasClassification他是中学生 (是 --> 中学生)
依据角色AccdAccording本庭依法宣判 (依法 <-- 宣判)
缘故角色ReasReason他在愁女儿婚事 (愁 --> 婚事)
意图角色IntIntention为了金牌他拼命努力 (金牌 <-- 努力)
结局角色ConsConsequence他跑了满头大汗 (跑 --> 满头大汗)
方式角色MannManner球慢慢滚进空门 (慢慢 <-- 滚)
工具角色ToolTool她用砂锅熬粥 (砂锅 <-- 熬粥)
材料角色MaltMaterial她用小米熬粥 (小米 <-- 熬粥)
时间角色TimeTime唐朝有个李白 (唐朝 <-- 有)
空间角色LocLocation这房子朝南 (朝 --> 南)
历程角色ProcProcess火车正在过长江大桥 (过 --> 大桥)
趋向角色DirDirection部队奔向南方 (奔 --> 南)
范围角色ScoScope产品应该比质量 (比 --> 质量)
数量角色QuanQuantity一年有365天 (有 --> 天)
数量数组QpQuantity-phrase三本书 (三 --> 本)
频率角色FreqFrequency他每天看书 (每天 <-- 看)
顺序角色SeqSequence他跑第一 (跑 --> 第一)
描写角色Desc(Feat)Description他长得胖 (长 --> 胖)
宿主角色HostHost住房面积 (住房 <-- 面积)
名字修饰角色NmodName-modifier果戈里大街 (果戈里 <-- 大街)
时间修饰角色TmodTime-modifier星期一上午 (星期一 <-- 上午)
反角色r + main role打篮球的小姑娘 (打篮球 <-- 姑娘)
嵌套角色d + main role爷爷看见孙子在跑 (看见 --> 跑)
并列关系eCooevent Coordination我喜欢唱歌和跳舞 (唱歌 --> 跳舞)
选择关系eSeltevent Selection您是喝茶还是喝咖啡 (茶 --> 咖啡)
等同关系eEquevent Equivalent他们三个人一起走 (他们 --> 三个人)
先行关系ePrecevent Precedent首先,先
顺承关系eSuccevent Successor随后,然后
递进关系eProgevent Progression况且,并且
转折关系eAdvtevent adversative却,然而
原因关系eCauevent Cause因为,既然
结果关系eResuevent Result因此,以致
推论关系eInfevent Inference才,则
条件关系eCondevent Condition只要,除非
假设关系eSuppevent Supposition如果,要是
让步关系eConcevent Concession纵使,哪怕
手段关系eMetdevent Method
目的关系ePurpevent Purpose为了,以便
割舍关系eAbanevent Abandonment与其,也不
选取关系ePrefevent Preference不如,宁愿
总括关系eSumevent Summary总而言之
分叙关系eRectevent Recount例如,比方说
连词标记mConjRecount Marker和,或
的字标记mAuxAuxiliary 的,地,得
介词标记mPrepPreposition 把,被
语气标记mToneTone 吗,呢
时间标记mTimeTime 才,曾经
范围标记mRangRange 都,到处
程度标记mDegrDegree 很,稍微
频率标记mFreqFrequency Marker 再,常常
趋向标记mDirDirection Marker 上去,下来
插入语标记mParsParenthesis Marker总的来说,众所周知
否定标记mNegNegation Marker不,没,未
情态标记mModModal Marker幸亏,会,能
标点标记mPuncPunctuation Marker,。!
重复标记mPeptRepetition Marker走啊走 (走 --> 走)
多数标记mMajMajority Marker们,等
实词虚化标记mVainVain Marker
离合标记mSepaSeperation Marker 吃了个饭 (吃 --> 饭) 洗了个澡 (洗 --> 澡)
根节点RootRoot 全句核心节点
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 语义依存分析是一种将句子解析成依存关系的语法分析技术,可以用于从句子中提取语义信息。为了从语义依存分析树中提取完整的语义结构,您可以编写一个Python程序,遵循以下步骤: 1. 导入相关的Python库和语义依存分析工具,例如Stanford Parser或SpaCy。 2. 将需要分析的句子输入程序。 3. 使用语义依存分析工具将句子解析成依存树。 4. 从依存树中提取出每个单词及其对应的依存关系,可以使用遍历算法或递归算法。 5. 将每个单词及其对应的依存关系存储到一个数据结构中,例如列表或字典。 6. 根据依存关系建立语义结构,例如建立一个以谓词为中心的结构,其中主语、宾语、定语等作为关联词连接。 7. 输出提取到的完整语义结构。 注意,具体的实现方法可能因语义依存分析工具的不同而异。同时,语义依存分析的精确度也取决于输入的句子和分析工具的参数配置。 ### 回答2: 要编写一个Python程序,从语义依存分析树中提取完整的语义结构,可以按照以下步骤进行: 1. 导入所需的Python库和模块,例如nltk库和语义依存分析的模块。 2. 读取输入的语义依存分析树。 3. 对语义依存分析树进行解析,提取每个词语和其对应的依存关系。 4. 构建完整的语义结构表示。可以使用字典或其他数据结构来存储每个词语及其对应的依存关系。 5. 输出提取的语义结构表示。 以下是一个简单的示例代码,展示了如何按照上述步骤从语义依存分析树中提取完整的语义结构: ```python import nltk from nltk.tree import Tree from nltk.parse.stanford import StanfordDependencyParser # 读取语义依存分析树 tree_str = "(ROOT (NP (NLP learning) (VP (is important))))" # 解析语义依存分析树 tree = Tree.fromstring(tree_str) dependencies = tree.pformat().split('\n')[1:-1] dependency_pairs = [dep.split('->') for dep in dependencies] # 构建语义结构表示 semantics = {} for pair in dependency_pairs: head = pair[1].strip().split(' ')[0][1:] dependent = pair[0].strip().split(' ')[0][1:] dep_type = pair[1].strip().split(' ')[1][:-1] if head not in semantics: semantics[head] = [] semantics[head].append((dependent, dep_type)) # 输出语义结构表示 for head, dependents in semantics.items(): print(f"Head: {head}") for dependent, dep_type in dependents: print(f"Dependent: {dependent} - Dependency Type: {dep_type}") ``` 以上代码使用了NLTK库中的Tree类和StanfordDependencyParser模块来解析语义依存分析树,并提取了每个词语及其对应的依存关系。然后,根据依存关系构建了一个字典(semantics),并输出了所提取的语义结构表示。请注意,以上代码是一个简化版本,实际应用中可能需要根据具体的语义解析工具和数据格式进行调整。 ### 回答3: 要编写一个Python程序来提取完整的语义结构,可以使用自然语言处理库,比如NLTK(Natural Language Toolkit)。 首先,我们需要安装和导入所需的库。在Python中,可以使用以下代码安装和导入NLTK库: ```python !pip install nltk import nltk ``` 接下来,我们需要下载NLTK中所需的语料库和模型。可以使用以下代码下载: ```python nltk.download('punkt') # 下载句子分割器所需的标点符号数据 nltk.download('averaged_perceptron_tagger') # 下载词性标注模型 nltk.download('dependency_treebank') # 下载依存语法树语料库 ``` 然后,我们可以定义一个函数来提取语义结构。可以使用NLTK的依存语法分析器来实现这一点。下面是一个示例函数,用于提取给定句子的完整语义结构: ```python from nltk.parse import DependencyGraph def extract_semantic_structure(sentence): parser = nltk.parse.CoreNLPParser() parse_trees = parser.raw_parse(sentence) for tree in parse_trees: dependencies = tree.to_conll(4) dep_graph = DependencyGraph(dependencies, top_relation_label='root') semantic_structure = [] for idx, node in sorted(dep_graph.nodes.items()): if idx != 0 and node['head'] is not None: dependency = (node['word'], node['rel'], dep_graph.nodes[node['head']]['word']) semantic_structure.append(dependency) return semantic_structure ``` 现在,我们可以使用上述函数来提取给定句子的语义结构。以下是一个示例使用: ```python sentence = "我喜欢吃水果。" semantic_structure = extract_semantic_structure(sentence) print(semantic_structure) ``` 该程序将输出以下语义结构: ``` [('我', 'nsubj', '喜欢'), ('喜欢', 'root', '喜欢'), ('吃', 'xcomp', '喜欢'), ('水果', 'dobj', '吃')] ``` 这表示句子中的主语是“我”,谓语是“喜欢”,“喜欢”是整个句子的根,它的扩展成分是“吃”,“吃”的直接宾语是“水果”。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值