使用嵌入模型探索语料库中的语义关系

2023年12月01日 由 alex 发表 248 0

嵌入是文本数据的数值表示,已成为文本语义查询的典型方法。在本文章中,我们将探索一些使用嵌入来探索文本数据的方式。


通过词嵌入捕捉概念之间的关系


词嵌入模型是一系列以无监督方式学习术语潜在向量表示的方法。当从自然语言中学习词嵌入时,本质上获得了嵌入空间中语义关系的映射。


词嵌入通常在大型语料库上训练,以便它们可以捕捉人类语言中的普遍词与词之间的关系。这是有用的,因为人们可以将关于语言的一般知识注入到特定应用的模型中。这也被称为迁移学习,长时间以来一直是机器学习的热门话题。


如果不是要将一般知识迁移到特定模型,而只是想要获取一个小语料库的语义特定方面的映射怎么办呢?假设我们有一个来自论坛的评论语料库,我们想探索其中可以发现的那些关联关系。


我们可能实现这一目标的一个方法是,从头开始在这个语料库上训练一个词嵌入模型,而不是使用为我们预先训练好的模型。在这个例子中,我将使用20Newsgroups数据集作为语料库,在其中探索语义关系。


训练模型


现在我们开始训练一个词嵌入模型。你可能熟悉Word2Vec,这是一个在研究和实践中推广使用静态词嵌入的方法。另一方面,由斯坦福的团队开发的GloVe在大多数情况下似乎是更好的方法,我的经验表明它提供的嵌入质量更高,特别是在较小的语料库上。

不幸的是GloVe没有在Gensim中实现,但幸运的是,我为原始的GloVe代码制作了一个完全兼容Gensim的接口,我们将使用它来训练模型。


我们安装gensim、glovpy、scikit-learn,以便我们可以获取20Newsgroups以及embedding-explorer:


pip install glovpy gensim scikit-learn


首先,我们需要加载数据集并对其进行分词,为此我们将使用gensim内置的分词器。我们还将过滤掉停用词,因为它们对于当前的任务没有任何有意义的信息。


from gensim.utils import tokenize
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS
def clean_tokenize(text: str) -> list[str]:
    """This function tokenizes texts and removes stop words from them"""
    tokens = tokenize(text, lower=True, deacc=True)
    tokens = [token for token in tokens if token not in ENGLISH_STOP_WORDS]
    return tokens
# Loading the dataset
dataset = fetch_20newsgroups(
    remove=("headers", "footers", "quotes"), categories=["sci.med"]
)
newsgroups = dataset.data
# Tokenizing the dataset
tokenized_corpus = [clean_tokenize(text) for text in newsgroups]


在此之后,我们可以轻松地在已分词的语料库上训练一个GloVe模型。


from glovpy import GloVe
# Training word embeddings
model = GloVe(vector_size=25)
model.train(tokenized_corpus)


我们已经可以查询这个词嵌入模型了,比如我们来看看哪十个词离“child”最近。


model.wv.most_similar("child")
==============================
+------------+----------+
| age        | 0.849304 |
| consistent | 0.844267 |
| adult      | 0.805101 |
| range      | 0.800615 |
| year       | 0.798799 |
| hand       | 0.792965 |
| children   | 0.792113 |
| use        | 0.789804 |
| restraint  | 0.773764 |
| belt       | 0.77003  |
+------------+----------+


调查,可视化


但是,单独调查每个单词与其他单词的关系很快就会变得乏味。理想情况下,我们也希望能够可视化关系,甚至可能得到一些网络。


幸运的是,我开发的embedding-explorer软件包在这里可以帮助我们。在计算人文学中,我们经常使用词嵌入模型和基于这些模型中的关系构建的语义网络,embedding-explorer帮助我们以互动和直观的方式来探索这些网络。该软件包包含多个交互式Web应用程序,我们将首先看一下“网络探索器”。


这个应用的背后思想是,在嵌入模型中,概念自然形成某种网络结构。关系密切的词语拥有强链接,而其他的可能没有任何链接。在应用中,你可以根据你指定的一组种子词和两级自由关联构建概念图。


在关联的每一个等级,我们取嵌入模型中最接近我们已有词语的五个词,并将其以与之关联的词的连接加入到我们的网络中。连接的强度由嵌入空间中概念的余弦距离决定。这种类型的网络对我或我的同事进行的多个研究项目都被证明是有用的。


让我们在我们的词嵌入模型上启动这个应用。


from embedding_explorer import show_network_explorer
vocabulary = model.wv.index_to_key
embeddings = model.wv.vectors
show_network_explorer(vocabulary, embeddings=embeddings)


这将打开一个浏览器窗口,在那里你可以自由地探索语料库中的语义关系。这是我查看围绕“jesus”、“science”和“religion”这些词出现的网络时的屏幕截图。


3


N元语法网络与句子转换器


现在,如果我们不仅仅想看单词层面的关系,而是短语或句子呢?


我的建议是使用N元语法。N元语法本质上只是在文本中相互跟随的N个术语。例如,在句子“I love my little cute dog”(我爱我的小狗)中,我们会有4-gram:“I love my little”(我爱我的小)、“love my little cute”(爱我小小的可爱)和“my little cute dog”(我的小可爱狗)。现在的问题是,我们如何学习好的N元语法的语义表征呢?


从技术上讲,你仍然可以通过将短语或句子作为一个标记来使用GloVe,但是有一个问题。由于N元语法的多样性随着N的增加而急剧增加,一个特定的N元语法可能只出现一次或两次,我们可能无法学习到它们的好的表征。


那么取短语中词嵌入的平均值如何呢?这可能有很大帮助,但问题是我们完全失去了不同词汇的重要性信息、它们在句子中的顺序以及所有上下文信息。


解决这一问题的方法是使用句子转换器,这些深层神经语言模型能够产生对上下文敏感的文本表征。它们在过去几年中已经超越了所有其他方法,并已成为嵌入文本的行业标准。


N元语法提取


让我们首先从我们的语料库中提取N元语法。我选择使用四元语法,但你可以选择任何你喜欢的数字。我们将使用scikit-learn的CountVectorizer来进行这项工作。


from sklearn.feature_extraction.text import CountVectorizer
# First we train a model on the corpus that learns all 4-grams
# We will only take the 4000 most frequent ones into account for now,
# But you can freely experiment with this
feature_extractor = CountVectorizer(ngram_range=(4,4), max_features=4000)
feature_extractor.fit(newsgroups)
# Then we get the vectorizer's vocabulary
four_grams = feature_extractor.get_feature_names_out()


嵌入模型


我们需要一个嵌入模型来进行文本表示。正如我之前所说的,我们将使用一个预训练的模型。我选择了all-MiniLM-L6-v2,因为它非常稳定,广泛使用,而且体积相对较小,所以即使在你的个人电脑上运行也可能会很顺利。


我们将使用另一个包embetter,这样我们就可以以scikit-learn兼容的方式使用句子转换器。


pip install embetter[text]


我们可以像这样在Python中加载模型:


from embetter.text import SentenceEncoder
encoder = SentenceEncoder("all-MiniLM-L6-v2")


接下来我们可以将模型和n-gram加载到embedding-explorer中。


from embedding_explorer import show_network_explorer
show_network_explorer(four_grams, vectorizer=encoder)


这里有一张我输入两个句子并观察围绕它们构建的四元组网络的种类的屏幕截图。


4


观察中间的短语是很有趣的。看起来像法律和历史在这里充当了连接宗教和科学的桥梁。


使用文档嵌入研究语料库级语义结构


文档表示


我们需要考虑我们将如何表示单个文档,以捕捉它们的语义内容。


更传统的机器学习实践通常会使用词袋表示法或训练Doc2Vec模型。这些都是不错的选择(并且你可以并且应该尝试它们),但它们缺乏对文本上下文的理解。由于我们语料库中的文本不是太长,我们仍然可以使用句子转换器来嵌入它们。让我们继续使用我们用于短语的相同嵌入模型。


投影与聚类


探索文档的语义表示的一个自然方式是将它们投影到低维空间(通常是2D),并使用这些投影来可视化文档。我们还可以看看在某些聚类方法下文档是如何被聚集的。


以下是工作流程:


  1. 我们可能要或者不要在继续之前减少嵌入的维度。你可以从各种降维方法中选择,或者你可以关闭它。
  2. 我们想要将我们的嵌入投影到2D空间中,以便我们可以可视化它们。
  3. 我们可能想要聚类嵌入,看看有哪些类型的文档被聚在一起。


5


我们也需要了解一些关于文件的外部信息(文本内容、标题等),否则我们很难进行解释。


让我们创建一个数据框,包含以下列:


  1. 每个文件的前400个字符,这样我们可以感知文本的主旨。
  2. 文本的长度,这样我们可以在可视化中看出哪些文本较长,哪些较短。
  3. 它们在我们数据集中所属的组。


import pandas as pd
import numpy as np
# Extracting text lengths in number of characters.
lengths = [len(text) for text in corpus]
# Extracting first 400 characters from each text.
text_starts = [text[:400] for text in corpus]
# Extracting the group each text belongs to
# Sklearn gives the labels back as integers, we have to map them back to
# the actual textual label.
group_labels = np.array(dataset.target_names)[dataset.target]
# We build a dataframe with the available metadata
metadata = pd.DataFrame(dict(length=lengths, text=text_starts, group=group_labels))


然后我们可以启动应用程序,并传递元数据,这样我们就可以悬停并查看有关文档的信息。


from embedding_explorer import show_clustering
show_clustering(
  newsgroups,
  vectorizer=encoder,
  metadata=metadata,
  hover_name="group", # Title of hover box is going to be the group
  hover_data=["text", "length"] # We would also like to see these on hover
)


当应用程序首次启动时,你会看到这个屏幕:


6


在运行聚类后,你将能够查看按簇着色的所有文档的地图。你可以将鼠标悬停在点上以查看有关文档的元数据……


7


在底部,你甚至可以选择如何对点进行颜色、标签和大小的设置。


8


总结


文本数据的探索性分析很有挑战性。我们查看了几种使用最先进机器学习技术进行交互式调查的方法。


文章来源:https://medium.com/towards-data-science/explore-semantic-relations-in-corpora-with-embedding-models-0a6d64c3ec7f
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消