tf计算矩阵维度_tf.nn.embedding_lookup_sparse

官方链接

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]来详细举例:

  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)

结果:

011cfcaad898684616cacae92ecdcdbf.png

例子2: 自己设置权重参数再来算一遍

现在设置权重参数为[3,4,0.5,2]。需要注意有多少个values就要设置多少个权重,这两个是一一对应的。

weights长什么样子(自己配的):

[
 [0, 3, 0, 4]
 [0, 0, 0.5, 2]
]

还是拿上面的例子来算:

  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. 分别给每一个乘上它自己对应的权重,注意这里权重改变了,一个是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)


结果如下:

a94f4ef2e705c1037362a147379bd969.png

最后

combiner方式求mean和求sum都比较简单,注意加权求和,加权求平均就可以了,不再说明了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值