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]來詳細舉例:
- 用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都比較簡單,注意加權求和,加權求平均就可以了,不再說明了。