神经网络嵌入解释
近年来,从图像分割到自然语言处理再到时间序列预测,神经网络的应用已经显着扩展。深度学习的一个显着成功的用途是嵌入,一种用于将离散变量表示为连续向量的方法。该技术已经发现了用于机器翻译的单词嵌入和用于分类变量的实体嵌入的实际应用。
在本文中,我将解释什么是神经网络嵌入,我们为什么要使用它们,以及如何学习它们。我们将在我正在研究的一个真正的问题的背景下审视这些概念:将维基百科上的所有书籍都表示为向量来创建书籍推荐系统。
维基百科上所有书籍的神经网络嵌入
嵌入(Embeddings)
嵌入是discrete — categorical — variable到连续数向量的映射。 在神经网络中,嵌入是离散变量的低维连续向量表示。在神经网络中,嵌入是离散变量的低维连续向量表示。神经网络嵌入是有用的,因为它可以降低分类变量的维数,并在变换后的空间中有意义地表示类别。
神经网络嵌入有三个主要目的:
- 在嵌入空间中查找最近邻。这些可用于根据用户兴趣或群集类别提出建议。
- 作为监督任务的机器学习模型的输入。
- 用于可视化概念和类别之间的关系。
这意味着就书籍项目而言,使用神经网络嵌入,我们可以在维基百科上获取所有37,000本书籍文章,并在向量中仅使用50个数字来表示每一篇。此外,因为嵌入是学习的,所以在我们的学习问题的背景下更相似的书籍在嵌入空间中彼此更接近。
神经网络嵌入克服了表示分类变量的常用方法的两个局限性:one-hot编码。
one-hot编码的局限性
one-hot编码分类变量的操作实际上是简单的嵌入,其中每个类别被映射到不同的向量。这个过程包含了离散的实体并将每个观察映射到0和1的矢量,表示特定的类别。
one-hot编码技术有两个主要缺点:
- 对于高基数变量 - 具有许多唯一类别的变量 - 变换后的矢量的维数变得难以管理。
- 映射完全不知情:“类似”类别在嵌入空间中不会彼此靠近。
第一个问题很容易理解:对于每一个额外的类别—被称为实体—我们必须向one-hot编码的向量添加另一个数字。如果我们在维基百科上有37000本书,那么每本书都需要一个37000维的向量来表示,这就使得在这种表示上训练任何机器学习模型都不可行。
第二个问题同样具有局限性:在向量空间中,one-hot编码不会使相似的实体彼此更接近。如果我们使用余弦距离度量向量之间的相似性,那么在one-hot编码之后,实体之间的每一次比较的相似性为0。
这意味着像《战争与和平》和《安娜·卡列尼娜》(都是列夫·托尔斯泰的经典著作)这样的实体彼此之间的距离并不比《战争与和平》(War and Peace)和《银河系漫游指南》(Hitchhiker’s Guide to The Galaxy, if we use one-hot encoding)更接近。
Python代码如下:
# One Hot Encoding Categoricals books = ["War and Peace", "Anna Karenina", "The Hitchhiker's Guide to the Galaxy"] books_encoded = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] Similarity (dot product) between First and Second = 0 Similarity (dot product) between Second and Third = 0 Similarity (dot product) between First and Third = 0
考虑到这两个问题,表示类别变量的理想解决方案需要的数字将少于唯一类别的数量,并将相似类别放在彼此更接近的位置。Python代码如下:
# Idealized Representation of Embedding books = ["War and Peace", "Anna Karenina", "The Hitchhiker's Guide to the Galaxy"] books_encoded_ideal = [[0.53, 0.85], [0.60, 0.80], [-0.78, -0.62]] Similarity (dot product) between First and Second = 0.99 Similarity (dot product) between Second and Third = -0.94 Similarity (dot product) between First and Third = -0.97
为了构建更好的分类实体表示,我们可以使用嵌入式神经网络和监督任务来学习嵌入。
学习嵌入
one-hot编码的主要问题是转换不依赖于任何监督。通过在有监督的任务中使用神经网络来学习嵌入,我们可以大大改进嵌入。嵌入形成网络的参数—权重—这些参数被调整以使任务的损失最小化。产生的嵌入向量是类别的表示,在这些类别中,与任务相关的相似类别彼此更接近。
例如,如果我们在电影评论集合中使用了50,000个单词的词汇表,我们可以使用经过训练的嵌入式神经网络来学习每个单词的100维嵌入,以预测评论的情感。词汇中与正面评论相关联的单词(如“brilliant”或“excellent”)将在嵌入空间中更接近,因为网络已经了解这些与正面评论相关联。
电影情感词嵌入
在上面给出的书籍例子中,我们的监督任务可能是“确定一本书是否由Leo Tolstoy撰写”,并且由此产生的嵌入将使托尔斯泰写的书更接近彼此。弄清楚如何创建监督任务以产生相关表示是制作嵌入的最艰难的部分。
Python实现
在维基百科图书项目(完整Python代码:https://github.com/WillKoehrsen/wikipedia-data-science/blob/master/notebooks/Book%20Recommendation%20System.ipynb)中,监督学习任务被设置为预测某个维基百科页面的链接是否出现在一本书的文章中。我们输入成对的(书名,链接)训练例子,混合了positive — true — and negative — false — pairs。这种设置是基于这样一种假设,即链接到类似维基百科页面的图书彼此相似。因此,由此产生的嵌入应该将类似的书籍放在向量空间中更紧密地放在一起。
我使用的网络有两个平行的嵌入层,将书和wikilink映射到单独的50维向量上,还有一个点积层,将嵌入的内容组合到一个数字中进行预测。嵌入是网络的参数,或权重,在训练过程中被调整,以最小化监督任务的损失。
在Keras代码中,如下所示
# Both inputs are 1-dimensional book = Input(name = 'book', shape = [1]) link = Input(name = 'link', shape = [1]) # Embedding the book (shape will be (None, 1, 50)) book_embedding = Embedding(name = 'book_embedding', input_dim = len(book_index), output_dim = embedding_size)(book) # Embedding the link (shape will be (None, 1, 50)) link_embedding = Embedding(name = 'link_embedding', input_dim = len(link_index), output_dim = embedding_size)(link) # Merge the layers with a dot product along the second axis (shape will be (None, 1, 1)) merged = Dot(name = 'dot_product', normalize = True, axes = 2)([book_embedding, link_embedding]) # Reshape to be a single number (shape will be (None, 1)) merged = Reshape(target_shape = [1])(merged) # Output neuron out = Dense(1, activation = 'sigmoid')(merged) model = Model(inputs = [book, link], outputs = out) # Minimize binary cross entropy model.compile(optimizer = 'Adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
虽然在监督的机器学习任务中,目标通常是训练模型来对新数据进行预测,但在此嵌入模型中,预测可能只是达到目的的手段。我们想要的是嵌入权重,书籍和链接的表示作为连续向量。
嵌入本身并不那么有趣:它们只是数字的向量:
书籍推荐嵌入模型的嵌入示例
但是,嵌入可用于前面列出的3个目的,对于此项目,我们主要感兴趣的是根据最近邻推荐书籍。为了计算相似性,我们采用查询书并找到其向量与所有其他书籍之间的点积。(如果我们的嵌入被归一化,这个点积是向量之间的余弦距离,范围从-1,最不相似,到+1,最相似。我们也可以使用欧几里德距离来测量相似性)。
这是我构建的书籍嵌入模型的输出:
(矢量与其自身之间的余弦相似度必须为1.0)。在减少一些维数后,我们可以制作如下数字:
嵌入最近邻居的书籍
我们可以清楚地看到学习嵌入的价值!我们现在在维基百科上有每本书的50个数字代表,类似的书籍彼此更接近。
嵌入可视化
嵌入式的最酷的部分之一是,它们可以用来可视化概念,例如小说或非小说之间的关系。这需要进一步的降维技术来将维度降至2或3。最流行的约简技术本身就是一种嵌入方法:TSNE。
我们可以把维基百科上所有书的37000个维度,用神经网络嵌入把它们映射到50个维度,然后用TSNE把它们映射到2个维度。结果如下:
在维基百科上嵌入所有37,000本书籍
在维基百科上嵌入所有37,000本书籍
(TSNE是一种流形学习技术,意味着它试图将高维数据映射到低维流形,创建嵌入,试图在数据中维护局部结构。它几乎专门用于可视化,因为输出是随机的,它不支持转换新数据。一种新的选择是UMAP,它更快,并且支持将新数据转换为嵌入空间)。
这本身并不是很有用,但是一旦我们根据不同的书籍特征开始着色它就会很有见地。
按类型着色的嵌入
我们可以清楚地看到属于同一类型的书籍的分组。它并不完美,但令人印象深刻的是,我们只用2个数字代表维基百科上的所有书籍,这些数字仍能捕捉到不同类型之间的差异。
书中的例子(即将发表的完整文章)展示了神经网络嵌入的价值:我们有一个分类对象的矢量表示,它是低维的,并且在嵌入空间中将相似的实体彼此靠近。
交互式可视化
静态图的问题在于我们无法真正探索数据并调查变量之间的分组或关系。为了解决这个问题,TensorFlow开发了projector,,这是一个在线应用程序,可以让我们可视化并与嵌入交互。结果如下:
利用projector互动探索书籍嵌入
结论
神经网络嵌入是离散数据的低维表示,作为连续向量。这些嵌入克服了传统编码方法的局限性,可用于寻找最近邻,输入另一个模型和可视化等目的。
尽管在学术术语中讨论了许多深度学习概念,但神经网络嵌入既直观又易于实现。我坚信任何人都可以学习深度学习,并使用像Keras这样的库来构建深度学习解决方案。嵌入是处理离散变量的有效工具,并提供深度学习的有用应用。