tf.nn.embedding_lookup_sparse(
params,
sp_ids,
sp_weights,
partition_strategy='mod',
name=None,
combiner=None,
max_norm=None
)
主要的作用是接收一个稀疏矩阵,返回一个embedding,这个embedding是在params表中查找到的embedding加上权重以后的结果。
- params参数在前面tf.nn.embedding_lookup中已经有说明
- sp_ids接收一个tf.SparseTensor类,在前面tf.SparseTensor中有详细说明
- sp_weights为每个值的权重,None时默认为1
- partition_strategy暂时没弄明白什么意思
- max_norm暂时没弄明白什么意思
- combiner是每个embedding查找后合并的方式,默认为求sqrtn,sqrtn的求法会在例子中有详细说明。那我们快来看下例子吧!
例子1: 权重为None,也就是默认每个value的权重都为1。权重也是一个SparseTensor类,indices和dense_shape都和ids一样,只有values不一样,但values的大小和ids是一一对应的
import tensorflow as tf
x = tf.sparse_placeholder(tf.float32)
params = tf.constant([[0.1, 0.4, 0.5, 7.0, 6.4, 1.2, 0.5, 0.3, 3.3, 2.0],
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2],
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]])
ids = tf.SparseTensor(indices=[[0, 1],
[0, 3],
[1, 2],
[1, 3]],
values=[2, 1, 1, 1],
dense_shape=[2, 4])
with tf.Session() as sess:
lookup = sess.run(
tf.nn.embedding_lookup_sparse(params, ids, None,
partition_strategy="div"))
print(lookup)
首先看看我们的ids长什么样子:
[
[0, 2, 0, 1]
[0, 0, 1, 1]
]
一个2*4的矩阵。在tf.nn.embedding_lookup中我也举的是同样的数据例子。
weights长什么样子(默认为None时):
[
[0, 1, 0, 1]
[0, 0, 1, 1]
]
重点来了:
tf.nn.embedding_lookup中该矩阵的0也是需要从params中找索引的,但是这里,这个矩阵的0是没有实际意义的,不能拿来找索引!也就是说我们第一行只找id为2和id为1的embedding,第二行只找id为1和id为1的embedding。找到的结果如下:(代码中打印不方便,这里手动写一下)
[
[
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2]
]
[
[0.1, 0.4, 0.5, 7.0, 6.4, 1.2, 0.5, 0.3, 3.3, 2.0]
[0.1, 0.4, 0.5, 7.0, 6.4, 1.2, 0.5, 0.3, 3.3, 2.0]
]
]
先来说说sqrtn的算法
(ps:公式是我自己写的,算法也是自己揣摩的,如果错误欢迎指正。算法揣摩的依据来源于源代码注释内mean模式的算法,还有程序输出的结果对比这两个参考):
什么意思呢?
我们来拿原矩阵的第一行[0,2,0,1]来详细举例:
- 用id在params中找到对应的embedding
[0,2,0,1]对应着:
[
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2]
]
而[0,2,0,1]中,id=2的权重取默认值1,id=1的权重也取默认值为1,所以在计算输出的embedding时,两行都对应乘1即可。
2. 分别给每一个乘上它自己对应的权重
[
[0.4*1, 0.9*1, 1.1*1, 4.3*1, 3.4*1, 0.2*1, 0.3*1, 0.2*1, 0.5*1, 0.1*1]
[0.3*1, 0.4*1, 0.9*1, 0.8*1, 0.5*1, 0.3*1, 0.7*1, 0.5*1, 0.8*1, 3.2*1]
]
3. 把结果对应位置加起来,这个作为分子
[
[0.7, 1.3, 2.0, 5.1, 3.9, 0.5, 1.0, 0.7, 1.3, 3.3]
]
4. 计算分母,各自的权重平方后取平方根,再求和。
(这里跟官方注释中解释的不一样。官方注释中所写的是权重平方先求和再取平方根,但是从代码输出结果来看这样的算法并不正确)
这里按照我自己的方式计算为:
5. 用第3步的结果除以第四步的结果得到
[
[0.35,0.65,1.0,2.55,1.95,0.25,0.5,0.35,0.65,1.65]
]
这是原矩阵的第一行[0,2,0,1]的最终输出的embedding的结果。第二行同理,这里不再赘述。
代码如下(和前面开篇的代码段一样):
import tensorflow as tf
x = tf.sparse_placeholder(tf.float32)
params = tf.constant([[0.1, 0.4, 0.5, 7.0, 6.4, 1.2, 0.5, 0.3, 3.3, 2.0],
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2],
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]])
ids = tf.SparseTensor(indices=[[0, 1],
[0, 3],
[1, 2],
[1, 3]],
values=[2, 1, 1, 1],
dense_shape=[2, 4])
with tf.Session() as sess:
lookup = sess.run(
tf.nn.embedding_lookup_sparse(params, ids, None,
partition_strategy="div"))
print(lookup)
结果:
例子2: 自己设置权重参数再来算一遍
现在设置权重参数为[3,4,0.5,2]。需要注意有多少个values就要设置多少个权重,这两个是一一对应的。
weights长什么样子(自己配的):
[
[0, 3, 0, 4]
[0, 0, 0.5, 2]
]
还是拿上面的例子来算:
- 用id在params中找到对应的embedding
[0,2,0,1]对应着:
[
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2]
]
而[0,2,0,1]中,id=2的权重取默认值1,id=1的权重也取默认值为1,所以在计算输出的embedding时,两行都对应乘1即可。
2. 分别给每一个乘上它自己对应的权重,注意这里权重改变了,一个是3一个是4
[
[0.4*3, 0.9*3, 1.1*3, 4.3*3, 3.4*3, 0.2*3, 0.3*3, 0.2*3, 0.5*3, 0.1*3]
[0.3*4, 0.4*4, 0.9*4, 0.8*4, 0.5*4, 0.3*4, 0.7*4, 0.5*4, 0.8*4, 3.2*4]
]
3. 把结果对应位置加起来,这个作为分子
[
[2.4, 4.3, 6.9, 16.1, 12.2, 1。8, 1.0, 0.7, 1.3, 3.3]
]
4. 计算分母,各自的权重平方后取平方根,再求和。
(这里跟官方注释中解释的不一样。官方注释中所写的是权重平方先求和再取平方根,但是从代码输出结果来看这样的算法并不正确)
这里按照我自己的方式计算为:
5. 用第3步的结果除以第四步的结果得到
[
[0.34285715,0.61428565,0.9857143,2.3,1.7428572,0.25714287,0.5285714,0.37142855,
0.67142856,1.8714286]
]
这是原矩阵的第一行[0,2,0,1]的最终输出的embedding的结果。第二行同理,这里不再赘述。
代码如下:
import tensorflow as tf
x = tf.sparse_placeholder(tf.float32)
params = tf.constant([[0.1, 0.4, 0.5, 7.0, 6.4, 1.2, 0.5, 0.3, 3.3, 2.0],
[0.3, 0.4, 0.9, 0.8, 0.5, 0.3, 0.7, 0.5, 0.8, 3.2],
[0.4, 0.9, 1.1, 4.3, 3.4, 0.2, 0.3, 0.2, 0.5, 0.1]])
ids = tf.SparseTensor(indices=[[0, 1],
[0, 3],
[1, 2],
[1, 3]],
values=[2, 1, 1, 1],
dense_shape=[2, 4])
sp_weights = tf.SparseTensor(indices=[[0, 1],
[0, 3],
[1, 2],
[1, 3]],
values=[3, 4, 0.5, 2],
dense_shape=[2, 4])
with tf.Session() as sess:
lookup = sess.run(
tf.nn.embedding_lookup_sparse(params, ids, sp_weights,
partition_strategy="div"))
print(lookup)
结果如下:
最后:
combiner方式求mean和求sum都比较简单,注意加权求和,加权求平均就可以了,不再说明了。