1. 程式人生 > 其它 >tf計算矩陣維度_tf.nn.embedding_lookup_sparse

tf計算矩陣維度_tf.nn.embedding_lookup_sparse

技術標籤:tf計算矩陣維度

官方連結

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都比較簡單,注意加權求和,加權求平均就可以了,不再說明了。