原创文章,转载请注明: 转载自慢慢的回味
本文链接地址: Tensorflow Embedding原理
Embedding(嵌入)指的是把低维的流形嵌入到高维空间中。举个简单的例子,三维空间的球体(地球)是一个二维流形嵌入在三维空间(欧几里得空间),即地球上的任意一个点只需一个二维的经纬度就可以表达,但三维空间中用x,y,z。深度学习领域假设“自然的原始数据是低维的流形嵌入到原始数据所在的高维空间中”。所以,深度学习的过程就是把高维原始数据(图像,句子)再回映射到低维流形中,从而是数据变得可分,而这个映射就叫嵌入(Embedding)。比如文档Embedding,就是把每篇文档所组成的单词映射到一个低维的表征向量,使得每篇文档可以用一个表征向量来表示,即Embedding就是从原始数据提取出来的Feature,也就是通过神经网络映射之后的低维向量。
如下例子,蓝色曲线和红色曲线是无法线性可分的(图二),只能用非线性函数分离(图三),但真实的数据中却很难找到这样的非线性函数,但通过对数据进行Embedding过程进行映射后(图四),就可以线性可分了。
文档Embedding原理
在对文本进行分类的过程中,第一步便是需要对文本样本进行降维,比如文本字库大小为10000,不能用10000列队矩阵来进行全连接计算,由于每个样本大概只占300个单词的稀疏向量,所以我们可以用一个列数更少的致密向量来代替每个样本,即可以用300个Embedding向量来对所有的文档进行低维映射。
Embedding方法就是用来把文本样本的稀疏矩阵转换为致密矩阵的一个方法。
假设有如下的矩阵乘法:
一个由m个文本样本,每个样本由n个特征构成的稀疏向量,组成的样本库。每个样本中含有的单词用1表示,比如第一个样本有2个单词。
现在构建一个Embedding矩阵,大小为n * k。其中Embedding矩阵的值可以用uniform方法进行随机初始化。
用样本中对应1的位置进行Embedding向量选择,然后相加,得到最终的向量 [5 7 9 11]。这样,m * n 的稀疏矩阵就变成了 m * k 的致密矩阵了。
测试程序
现在用一个示例程序来测试Tensorflow中Embedding API:
''' Created on Jul 10, 2019 @author: root ''' from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf from tensorflow.python.ops import embedding_ops import numpy as np a = tf.Variable(np.arange(8).reshape(2,4)) b = tf.Variable(np.arange(8,16).reshape(2,4)) c = tf.Variable(np.arange(16, 24).reshape(2,4)) embedded_tensor = embedding_ops.embedding_lookup(params=[a,b,c], ids=[1,2,4,3], partition_strategy='mod', name="embedding") print (a) print (b) print (c) print ("########## embedded_tensor #########") print(embedded_tensor) # 1 0 4 0 # 0 2 1 0 # 3 0 0 5 sparse_tensor = tf.SparseTensor(indices=[[0,0],[0,2],[1,1],[1,2],[2,0],[2,3]], values=[1,4,2,1,3,5], dense_shape=[3,4]) embedded_sparse_tensor = embedding_ops.embedding_lookup_sparse(params=[a,b,c], sp_ids=sparse_tensor, sp_weights=None, partition_strategy='mod', name="embedding", combiner="sum") print ("########## embedded_sparse_tensor #########") print(embedded_sparse_tensor) |
输出结果为:
<tf.Variable 'Variable:0' shape=(2, 4) dtype=int64, numpy= array([[0, 1, 2, 3], [4, 5, 6, 7]])> <tf.Variable 'Variable:0' shape=(2, 4) dtype=int64, numpy= array([[ 8, 9, 10, 11], [12, 13, 14, 15]])> <tf.Variable 'Variable:0' shape=(2, 4) dtype=int64, numpy= array([[16, 17, 18, 19], [20, 21, 22, 23]])> ########## embedded_tensor ######### tf.Tensor( [[ 8 9 10 11] [16 17 18 19] [12 13 14 15] [ 4 5 6 7]], shape=(4, 4), dtype=int64) ########## embedded_sparse_tensor ######### tf.Tensor( [[20 22 24 26] [24 26 28 30] [24 26 28 30]], shape=(3, 4), dtype=int64) |
对第一个API embedding_ops.embedding_lookup,embedding矩阵由3个矩阵顺序排列,形成6*4的矩阵,4个样本的选择分别为1,2,4,3:
embedding矩阵为:
[ 0, 1, 2, 3] [ 4, 5, 6, 7] [ 8, 9, 10, 11] [12, 13, 14, 15] [16, 17, 18, 19] [20, 21, 22, 23] |
因为API调用中,用mod进行分区,取余的结果指向分区号,整除的结果执行分区里面的索引值。所以分区后表示如下,其中分区数为3个向量的数目,即3:
分区0,接受的id为id % 3 = 0,即id为0或3:
[ 0, 1, 2, 3] id = 0 (0/3 = 0) [ 4, 5, 6, 7] id = 3 (1/3 = 0) |
分区1,接受的id为id % 3 = 1,即id为1或4:
[ 8, 9, 10, 11] id = 1 (1/3 = 0) [12, 13, 14, 15] id = 4 (4/3 = 1) |
分区2,接受的id为id % 3 = 2,即id为2或5:
[16, 17, 18, 19] id = 2 (2/3 = 0) [20, 21, 22, 23] id = 5 (5/3 = 1) |
用4个样本进行选择后为:
[ 8 9 10 11] 1 [16 17 18 19] 2 [12 13 14 15] 4 [ 4 5 6 7] 3 |
API embedding_ops.embedding_lookup_sparse则用来对ids为一个稀疏矩阵的情况进行Embedding:
其中稀疏矩阵由SparseTensor生成,indices表示矩阵中的坐标,values表示对应坐标的值,即可以表示为单词样本中该位置的词在词库中的index值。
稀疏矩阵构成后如下:
[ 1 0 4 0] [ 0 2 1 0] [ 3 0 0 5] |
sparse_tensor = tf.SparseTensor(indices=[[0,0],[0,2],[1,1],[1,2],[2,0],[2,3]], values=[1,4,2,1,3,5],
dense_shape=[3,4])
如第一个样本,按照上面的逻辑,分别选择embedding矩阵中1和4
分区1,接受的id为id % 3 = 1
[ 8, 9, 10, 11] id = 1 (1/3 = 0) [12, 13, 14, 15] id = 4 (4/3 = 1) |
根据combiner=”sum”,结果为[20 22 24 26]
依次,整个稀疏矩阵embedding后的结果为:
[20 22 24 26] [24 26 28 30] [24 26 28 30] |
本作品采用知识共享署名 4.0 国际许可协议进行许可。