![](/img/trans.png)
[英]More efficient way to create a mask of top `k` elements in tensorflow
[英]Efficient way to create a "rolling window" type grouping in TensorFlow
假設您有一個 n 維張量,其中一個維度對應於時間。
我想做的是:給定一些 integer window_size
,我想用兩個新維度[..., n_groups, window_size]
替換我的時間維度。 其中n_groups
代表時間維度上大小為window_size
的所有可能分組。 因此,如果我們從大小為n_periods
的時間維度開始,那么n_groups
最終應該是n_periods - window_size
。
使用傳統的“pythonic”循環和切片可以很容易地完成所有這些,例如:
stacked = tf.stack([inputs[i:i+window_size] for i in range(len(inputs) - window_size + 1)], axis=0)
但是,如果時間維度很長,則會產生數量驚人的圖形操作。 我想知道是否沒有內置的 TensorFlow function 可以幫助我更有效地完成這個相對簡單的任務......
“滾動窗口分組”的想法如此普遍,以至於 Pandas 項目有一個非常復雜且規模龐大的 API來處理這種特殊情況。 我本以為 TensorFlow 也會包含這樣的實用程序。
考慮關於 map_fn 的 tf 文檔:
“map_fn 會將 fn 使用的操作應用於 elems 的每個元素,從而導致 O(elems.shape[0]) 總操作數。由於 map_fn 可以並行處理元素這一事實在一定程度上緩解了這一點。但是,使用map_fn 通常仍然比使用矢量化操作表示的等效轉換效率低。”
給定輸入張量,您可以嘗試以下方法:
input_tensor = tf.range([10])
# <tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>
轉換為方陣:
res = tf.repeat(tf.expand_dims(input_tensor, 0), input_tensor.shape[0], axis = 0)
# array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]], dtype=int32)>
然后在這個張量上應用 map_fn,在輸入中包含一個具有負值的范圍向量:
elements = tf.range(10, dtype=tf.int32) * -1
w,_ = tf.map_fn(lambda x: (tf.roll(x[0], x[1], axis=0), x[1]), (res, elements), dtype=(tf.int32, tf.int32))
這會將元素排(左)為:
#<tf.Tensor: shape=(10, 10), dtype=int32, numpy=
#array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
# [2, 3, 4, 5, 6, 7, 8, 9, 0, 1],
# [3, 4, 5, 6, 7, 8, 9, 0, 1, 2],
# [4, 5, 6, 7, 8, 9, 0, 1, 2, 3],
# [5, 6, 7, 8, 9, 0, 1, 2, 3, 4],
# [6, 7, 8, 9, 0, 1, 2, 3, 4, 5],
# [7, 8, 9, 0, 1, 2, 3, 4, 5, 6],
# [8, 9, 0, 1, 2, 3, 4, 5, 6, 7],
# [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]], dtype=int32)>
最后,使用張量切片獲取盡可能多的元素,例如:
window = 8
tf.slice(w, [0, 0], [(w.shape[0] - window) + 1, window])
給出:
#<tf.Tensor: shape=(3, 8), dtype=int32, numpy=
#array([[0, 1, 2, 3, 4, 5, 6, 7],
# [1, 2, 3, 4, 5, 6, 7, 8],
# [2, 3, 4, 5, 6, 7, 8, 9]], dtype=int32)>
對於 window = 4
window = 4
tf.slice(w, [0, 0], [(w.shape[0] - window) + 1, window])
給出:
#array([[0, 1, 2, 3],
# [1, 2, 3, 4],
# [2, 3, 4, 5],
# [3, 4, 5, 6],
# [4, 5, 6, 7],
# [5, 6, 7, 8],
# [6, 7, 8, 9]], dtype=int32)>
嘗試。 將其轉換成 tf 圖,看看它是否比普通的 python 循環具有更好的性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.