簡體   English   中英

在 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM