【论文复现】上下位关系自动检测方法

server/2024/11/30 18:41:49/

在这里插入图片描述

📝个人主页🌹:Eternity._
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述
在这里插入图片描述

❀ 上下位关系自动检测方法

  • 算法原理
    • Hearst 模式
    • 上下位关系得分
  • 核心逻辑
  • 效果演示
  • 使用方式
  • 参考文献

本文复现论文 Hearst patterns revisited: Automatic hypernym detection from large text corpora[1] 提出的文本中上位词检测方法。

在自然语言处理中,上下位关系(Is-a Relationship)表示的是概念(又称术语)之间的语义包含关系。其中,上位词(Hypernym)表示的是下位词(Hyponym)的抽象化和一般化,而下位词则是对上位词的具象化和特殊化。举例来说:“水果”是“苹果”、“香蕉”、“橙子”等的上位词,“汽车”、“电动车”、“自行车”等则是“交通工具”的下位词。在自然语言处理任务中,理解概念之间的上下位关系对于诸如词义消歧、信息检索、自动问答、语义推理等任务都具有重要意义。
在这里插入图片描述
文本中上位词检测方法,即从文本中提取出互为上下位关系的概念。现有的无监督上位词检测方法大致可以分为两类——基于模式的方法和基于分布模型的方法:

(1)基于模式的方法:其主要思想是利用特定的词汇-句法模式来检测文本中的上下位关系。例如,我们可以通过检测文本中是否存在句式“【词汇1】是一种【词汇2】”或“【词汇1】,例如【词汇2】”来判断【词汇1】和【词汇2】间是否存在上下位关系。这些模式可以是预定义的,也可以是通过机器学习得到的。然而,基于模式的方法存在一个众所周知的问题——极端稀疏性,即词汇必须在有限的模式中共同出现,其上下位关系才能被检测到。

(2)基于分布模型的方法:基于大型文本语料库,词汇可以被学习并表示成向量的形式。利用特定的相似度度量,我们可以区分词汇间的不同关系。

在该论文中,作者研究了基于模式的方法和基于分布模型的方法在几个上下位关系检测任务中的表现,并发现简单的基于模式的方法在常见的数据集上始终优于基于分布模型的方法。作者认为这种差异产生的原因是:基于模式的方法提供了尚不能被分布模型准确捕捉到的重要上下文约束。

本文所涉及的所有资源的获取方式:这里

算法原理


Hearst 模式


作者使用如下模式来捕捉文本中的上下位关系:
在这里插入图片描述
通过对大型语料库使用模式捕捉候选上下位词对并统计频次,可以计算任意两个词汇之间存在上下位关系的概率

上下位关系得分

设 p(x,y)是词汇 x和 y 分别作为下位词和上位词出现在预定义模式集合
P 中的频率, ( p − ) (p^-) (p)(x)是x 作为任意词汇的下位词出现在预定义模式中的频率, ( p + ) (p^+) (p+)(y)是 yy 作为任意词汇的上位词出现在预定义模式中的频率。作者定义正逐点互信息(Positive Point-wise Mutual Information)作为词汇间上下位关系得分的依据:
在这里插入图片描述
由于模式的稀疏性,部分存在上下位关系的词对并不会出现在特定的模式中。为了解决这一问题,作者利用PPMI得分矩阵的稀疏表示来预测任意未知词对的上下位关系得分。PPMI得分矩阵定义如下:
在这里插入图片描述
,其中 m=|{x|(x,y)\in P\or(y,x)\in P}|。

对矩阵 M 做奇异值分解可得 M = U Σ V T M = U\Sigma V^T M=UΣVT ,然后我们可以通过下式计算出上下位关系 spmi 得分:
在这里插入图片描述
其中 ( u x ) (u_x) (ux) ( v y ) (v_y) (vy)​分别是矩阵 U 和 V 的第 x行和第 y 行,Σr 是对 Σ 的 r 截断(即除了最大的 r 个元素其余全部置零)。

核心逻辑


具体的核心逻辑如下所示:

import spacy
import json
from tqdm import tqdm
import re
from collections import Counter
import numpy as np
import mathnlp = spacy.load("en_core_web_sm")def clear_text(text):"""对文本进行清理"""# 这里可以添加自己的清理步骤# 删去交叉引用标识,例如"[1]"pattern = r'\[\d+\]'result = re.sub(pattern, '', text)return resultdef split_sentences(text):"""将文本划分为句子"""doc = nlp(text)sentences = [sent.text.strip() for sent in doc.sents]return sentencesdef extract_noun_phrases(text):"""从文本中抽取出术语"""doc = nlp(text)terms = []# 遍历句子中的名词性短语(例如a type of robot)for chunk in doc.noun_chunks:term_parts = []for token in list(chunk)[-1::]:# 以非名词且非形容词,或是代词的词语为界,保留右半部分(例如robot)if token.pos_ in ['NOUN', 'ADJ'] and token.dep_ != 'PRON':term_parts.append(token.text)else:breakif term_parts != []:term = ' '.join(term_parts)terms.append(term)return termsdef term_lemma(term):"""将术语中的名词还原为单数"""lemma = []doc = nlp(term)for token in doc:if token.pos_ == 'NOUN':lemma.append(token.lemma_)else:lemma.append(token.text)return ' '.join(lemma)def find_co_occurrence(sentence, terms, patterns):"""找出共现于模板的术语对"""pairs = []# 两两之间匹配for hyponym in terms:for hypernym in terms:if hyponym == hypernym:continuefor pattern in patterns:# 将模板中的占位符替换成候选上下位词pattern = pattern.replace('__HYPONYM__', re.escape(hyponym))pattern = pattern.replace('__HYPERNYM__', re.escape(hypernym))# 在句子中匹配if re.search(pattern, sentence) != None:# 将名词复数还原为单数pairs.append((term_lemma(hyponym), term_lemma(hypernym)))return pairsdef count_unique_tuple(tuple_list):"""统计列表中独特元组出现次数"""counter = Counter(tuple_list)result = [{"tuple": unique, "count": count} for unique, count in counter.items()]return resultdef find_rth_largest(arr, r):"""找到第r大的元素"""rth_largest_index = np.argpartition(arr, -r)[-r]return arr[rth_largest_index]def find_pairs(corpus_file, patterns, disable_tqdm=False):"""读取文件并找出共现于模板的上下位关系术语对"""pairs = []# 按行读取语料库lines = corpus_file.readlines()for line in tqdm(lines, desc="Finding pairs", ascii=" 123456789#", disable=disable_tqdm):# 删去首尾部分的空白字符line = line.strip()# 忽略空白行if line == '':continue# 清理文本line = clear_text(line)# 按句处理sentences = split_sentences(line)for sentence in sentences:# 抽取出句子中的名词性短语并分割成术语candidates_terms = extract_noun_phrases(sentence)# 找出共现于模板的术语对pairs = pairs + find_co_occurrence(sentence, candidates_terms, patterns)return pairsdef spmi_calculate(configs, unique_pairs):"""基于对共现频率的统计,计算任意两个术语间的spmi得分"""# 计算每个术语分别作为上下位词的出现频次terms = list(set([pair["tuple"][0] for pair in unique_pairs] + [pair["tuple"][1] for pair in unique_pairs]))term_count = {term: {'hyponym_count': 0, 'hypernym_count': 0} for term in terms}all_count = 0for pair in unique_pairs:term_count[pair["tuple"][0]]['hyponym_count'] += pair["count"]term_count[pair["tuple"][1]]['hypernym_count'] += pair["count"]all_count += pair["count"]# 计算PPMI矩阵 ppmi_matrix = np.zeros((len(terms), len(terms)), dtype=np.float32)for pair in unique_pairs:hyponym = pair["tuple"][0]hyponym_id = terms.index(hyponym)hypernym = pair["tuple"][1]hypernym_id = terms.index(hypernym)ppmi = (pair["count"] * all_count) / (term_count[hyponym]['hyponym_count'] * term_count[hypernym]['hypernym_count'])ppmi = max(0, math.log(ppmi))ppmi_matrix[hyponym_id, hypernym_id] = ppmi# 对PPMI进行奇异值分解并截断r = configs['clip']U, S, Vt = np.linalg.svd(ppmi_matrix)S[S < find_rth_largest(S, r)] = 0S_r = np.diag(S)# 计算任意两个术语间的spmiparis2spmi = []for hyponym_id in range(len(terms)):for hypernym_id in range(len(terms)):# 同一个术语间不计算得分if hyponym_id == hypernym_id:continuespmi = np.dot(np.dot(U[hyponym_id , :], S_r), Vt[:, hypernym_id]).item()# 保留得分大于阈值的术语对if spmi > configs["threshold"]:hyponym = terms[hyponym_id]hypernym = terms[hypernym_id]paris2spmi.append({"hyponym": hyponym, "hypernym": hypernym, "spmi": spmi})# 按spmi从大到小排序paris2spmi = sorted(paris2spmi, key=lambda x: x["spmi"], reverse=True)return paris2spmiif __name__ == "__main__":# 读取配置文件with open('config.json', 'r') as config_file:configs = json.load(config_file)# 读取模板with open(configs['patterns_path'], 'r') as patterns_file:patterns = json.load(patterns_file)# 语料库中共现于模板的术语对with open(configs['corpus_path'], 'r', encoding='utf-8') as corpus_file:pairs = find_pairs(corpus_file, patterns)# 统计上下位关系的出现频次unique_pairs = count_unique_tuple(pairs)with open(configs["pairs_path"], 'w') as pairs_file:json.dump(unique_pairs, pairs_file, indent=6, ensure_ascii=True)# 计算任意两个术语间的spmi得分paris2spmi = spmi_calculate(configs, unique_pairs)with open(configs['spmi_path'], 'w') as spmi_file:json.dump(paris2spmi, spmi_file, indent=6, ensure_ascii=True)

以上代码仅作展示,更详细的代码文件请参见附件。

效果演示


运行脚本main.py,程序会自动检测语料库中存在的上下位关系。运行结果如下所示:
在这里插入图片描述

使用方式


  • 解压附件压缩包并进入工作目录。如果是Linux系统,请使用如下命令:
unzip Revisit-Hearst-Pattern.zip
cd Revisit-Hearst-Pattern
  • 代码的运行环境可通过如下命令进行配置:
pip install -r requirements.txt
python -m spacy download en_core_web_sm
  • 如果希望在本地运行程序,请运行如下命令:
python main.py
  • 如果希望在线部署,请运行如下命令:
python main-flask.py
  • 如果希望添加新的模板,请修改文件data/patterns.json。
    • "HYPONYM"表示下位词占位符;
    • "HYPERNYM"表示上位词占位符;
    • 其余格式请遵照 python.re 模块的正则表达式要求。
  • 如果希望使用自己的文件路径或改动其他实验设置,请在文件config.json中修改对应参数。以下是参数含义对照表:
参数名含义
corpus_path文本语料库文件路径,默认为“data/corpus.txt”。
patterns_path预定义模式库的路径。默认为“data/patterns.json”。
pairs_path利用模式筛选出的上下位关系词对路径,默认为“data/pairs.json”。
spmi_path上下位关系词对及其spmi得分路径,默认为“data/spmi.json”。
clip用于对 Σ 进行截断的参数 r ,默认为10。
thresholdspmi得分小于该值的词对将被舍去。默认为1。
max_bytes输入文件大小上限(用于在线演示),默认为200kB。

(以上内容皆为原创,请勿转载)

参考文献


[1] Roller S, Kiela D, Nickel M. Hearst patterns revisited: Automatic hypernym detection from large text corpora[J]. arXiv preprint arXiv:1806.03191, 2018.


编程未来,从这里启航!解锁无限创意,让每一行代码都成为你通往成功的阶梯,帮助更多人欣赏与学习!

更多内容详见:这里


http://www.ppmy.cn/server/146220.html

相关文章

4. STM32_定时器

概述 什么是定时器&#xff1a; 定时器核心就是计数器&#xff0c;是使用精准的时基&#xff0c;通过硬件的方式&#xff0c;实现定时功能的器件。 定时器的工作原理&#xff1a; 主频时钟CLK通过PSC进行分频后产生定时器时钟TIM CLK&#xff0c;计数器CNT根据TIM CLK的频率…

架构-微服务-服务配置

文章目录 前言一、配置中心介绍1. 什么是配置中心2. 解决方案 二、Nacos Config入门三、Nacos Config深入1. 配置动态刷新2. 配置共享 四、nacos服务配置的核心概念 前言 服务配置--Nacos Config‌ 微服务架构下关于配置文件的一些问题&#xff1a; 配置文件相对分散。在一个…

2025蓝桥杯(单片机)备赛--扩展外设之PWM的原理与应用(十三)

1 PWM原理 PWM :该方法未使用常规的PWM相关的寄存器配置&#xff1b;而是使用了定时器2&#xff1b; 与这个类似。 周期&#xff1a; 通过定时器2设置每次进中断的间隔&#xff0c;来设置最小周期&#xff08;步进&#xff09;&#xff0c;如设置100us,这时PWM 的最小周期为10…

【计算视觉算法与应用】金字塔,下采样Gaussian Pyramid. 上采用 Laplacian Pyramid (code: py)

金字塔&#xff08;Pyramid&#xff09;在图像处理中主要用于多尺度分析和图像压缩。常见的图像金字塔有两种&#xff1a; 高斯金字塔&#xff08;Gaussian Pyramid&#xff09;&#xff1a;用于下采样图像&#xff0c;生成分辨率逐渐降低的图像序列。拉普拉斯金字塔&#xff…

ESP32/ESP8266通过ESP-MESH无线组网协议通信

ESP32/ESP8266通过ESP-MESH无线组网协议通信 简介painlessMesh LibraryESP-MESH广播通信示例ESP-MESH通信验证总结 简介 Wi-Fi Mesh 是一种能够大幅提高 Wi-Fi 信号覆盖范围的无线网络系统。乐鑫基于 Wi-Fi 协议推出了 Wi-Fi Mesh 组网方案 ESP-Mesh-Lite&#xff0c;支持分布…

积鼎科技携手西北工业大学动力与能源学院共建复杂多相流仿真联合实验室

11月26日&#xff0c;复杂多相流仿真联合实验室揭牌仪式及技术研讨活动在西北工业大学动力与能源学院成功举办。复杂多相流仿真联合实验室是由西北工业大学动力与能源学院牵头&#xff0c;携手上海积鼎信息科技有限公司与三航铸剑&#xff08;西安&#xff09;科技发展有限公司…

速盾:介绍一下高防cdn的缓存响应事什么功能?

高防CDN&#xff08;Content Delivery Network&#xff09;是一种基于分布式缓存技术的网络加速服务&#xff0c;能够提供强大的缓存响应功能。它的缓存响应功能主要包括缓存加速和智能缓存两个方面。 首先&#xff0c;高防CDN的缓存加速功能是指通过在全球范围内部署大量的缓…

图像处理里的傅里叶变换:原理与代码实现

简介&#xff1a;本文围绕傅里叶变换在图像处理中的应用展开。先是以通俗易懂的方式详细阐释了傅里叶变换的核心理论&#xff0c;涵盖为何选用正弦和余弦、空间域到频率域的转换以及幅度图像和相位图像的含义等内容&#xff0c;帮助读者理解其原理。接着通过具体代码示例&#…