[常见的自然语言处理技术] 文本相似度(III): Word2vec带你深入word embeddings

前言

继续来讨论语意相似度,今天我们将深入探讨如何实现 word embedding 。也就是说,我们要将单词转为向量(维度可自行决定),并且确保意义相仿的单词在经过向量表示之後也会互相靠近,而相反使用情境天差地远的单词再向量化之後则会有较远的距离。

Word2vec 模型

word embeddings 模型学习的过程中一般并不会提供已经标注好类别的资料,因此被认为属於非监督式学习(unsupervised learning)的范畴。Word2vec 是用来生成 word embeddings 最常见的一类演算法,藉由类神经网络作为架构来学习语料库中单词的意义关联性。 根据分布假说,经常共同出现在上下文的字词意义上也会较为接近,Word2vec 会将它们的词向量分成同一类的词群组( word clusters )。同一集群内的向量彼此靠近,隶属不同集群的向量则彼此相距较远。根据训练资料的设计,Word2vec可分为连续词袋模型(continuous bag-of-words, CBoW)以及跳跃式模型(skip-gram model, SG)两种设计架构。

Word2vec 将意义相近的单词被分类在同一集群:

图片来源:TowardsDataScience

我们先建立一个仅包含四句短文的小型语料库,并且建立其词汇表:

# Create our text corpus of 4 sentences
doc_1 = "he is a king"
doc_2 = "she is a queen"
doc_3 = "he is a man"
doc_4 = "she is a woman"
simple_corpus = [doc_1, doc_2, doc_3, doc_4]

# Build its vocabulary of unique words (fea)
joined_docs = ' '.join(simple_corpus)
tokens = joined_docs.split()
vocab = dict()
index = 0
for token in tokens:
    # leave the words that already exist in vocab
    if token in vocab:
        continue
    else:
        vocab[token] = index
        index += 1
print(vocab) # {'he': 0, 'is': 1, 'a': 2, 'king': 3, 'she': 4, 'queen': 5, 'man': 6, 'woman': 7}

我们得到了词汇表总共有8个相异单词,以及各个单词的编号。

连续词袋模型架构(CBoW)

第一种模型的设计架构为 continuous bag-of-words (CBoW) ,其将语料库中的每个单词当作 target word ,并且藉由上下文( context words )来预测 target word。这个动作藉由指定好长度的 sliding window 扫遍整个语料库来完成,以建立训练资料集。训练资料集是由特徵与标签成对所构成,每一笔资料则为(context word, target word)。

CBoW 模型观察上下文来预测中间的单词:

藉由sliding window遍历语料库中的每个单词以建立训练资料:

图片来源:Practical Natural Language Processing by Sowmya Vajjala et al.

现在,指定 context length k 为2,也就是上下文的采计范围,此时window size=2k+1 即为5。接着我们以 CBoW 演算法建立训练资料集:

# Build a CBoW (contex, target) generator

from sklearn.feature_extraction.text import CountVectorizer

# set context_length
context_length = 2

# function to get cbows
def get_cbow_datapairs(tokens, context_length):
    cbows = list()
    for i, target in enumerate(tokens):
        if i < context_length:
            pass
        elif i < len(tokens) - context_length:
            context = tokens[i - context_length : i] + tokens[i + 1 : i + context_length + 1]
            vectoriser = CountVectorizer()
            vectoriser.fit_transform(context)
            context_no_order = vectoriser.get_feature_names()
            cbows.append((context_no_order, target))
    return cbows
# generate data pairs
cbows = get_cbow_datapairs(tokens, context_length)

# prints out dataset
for cbow in cbows:
    print("Context: {} -> Target: {}".format(cbow[0], cbow[1]))

接下来就是建构神经网络的时刻了! Word2vec 的神经网络并不深,其仅有一个隐藏层和一个输出层,是一种浅层神经网络(shallow neural network)。输入层节点的数量是由词汇数量所决定(在我们的例子中 V=8),而我们可以根据要表示向量的维度来指定隐藏层的节点数(例如N=2就是将单词表示为二维平面向量(x,y)),而输出层的节点数则也是词汇数量V(用意是将上下文单词划归其target word的类别,而我们洽有V个target words)。
Context words 先是根据其在词汇表里的顺序编号,进行one-hot编码为V维向量,加总之後再输入神经网络,因此context words 的顺序并不重要。

CBoW神经网路的结构:

图片来源:Practical Natural Language Processing by Sowmya Vajjala et al.

# Build the CBOW model architecture
import tensorflow.keras.backend as K
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Embedding, Lambda

V = len(vocab)
N = 2

cbow = Sequential(name = "our CBoW model")
# input layer of 8 nodes
cbow.add(Embedding(input_dim = V, output_dim = N, input_length = context_length * 2))
# single hidden layer of 2 nodes
cbow.add(Lambda(lambda x: K.mean(x, axis = 1), output_shape = (N, )))
# output layer of again 8 nodes, "softmax" is used for classification
cbow.add(Dense(V, activation = "softmax"))

cbow.compile(loss = "categorical_crossentropy", optimizer = "adam")

# view model summary
print(cbow.summary())

检视一下我们的模型结构:

又即将到了午夜时分,今天本来想要一口气讲完Skip-Gram结构看来也只能留到明天了。明天我们延续CBoW的实作,并让刚建立好的CBoW network进行单词相似度的学习,产生属於自己的二维 word embeddings 。明天再会,小夥伴们!

阅读更多

  1. Implementing Deep Learning Methods and Feature Engineering for Text Data: The Continuous Bag of Words (CBOW)

<<:  CSS Box-Shadow

>>:  【程序】维护成本 转生成恶役菜鸟工程师避免 Bad End 的 30 件事 - 9

Day30 | 30天系列回顾 X赛程後规划

好啦,今天是第三十天了,今天会分享下赛程心得,并回顾一下前面系列文,最後是三十天後的规划! 参赛动机...

[Day11] Storybook - Controls

Storybook 有一个很强大的辅具工具 Controls ,它提供一个 GUI 介面让我们可以即...

CVSS v3.1如何计算其分数(强制性指标)

以下摘要和解释来自FIRST。 通用漏洞评分系统(CVSS)是一个开放框架,用於传达软件漏洞的特徵和...

Android学习笔记20

今天用了sharedpreferences,在mvvm架构上要使用respository来当作mod...

【不是铁人赛】Day 02|虚拟货币价格预测(二)LSTM与GRU。

友:你要不要一起参加铁人赛? 我:好啊! (几天後) 我:乾我不小心忘了报名...... ----...