[PYTHON] [TensorFlow] I want to process windows with Ragged Tensor

Introduction

RaggedTensor that represents variable length data introduced in TensorFlow 2.1 or later, but if you try to write with ordinary Tensor glue, there are various things I'm addicted to it. This time, we will use window processing for signal processing. A frame with a certain time width is shifted little by little to extract a waveform that falls within the frame range.

Verification environment

Thing you want to do

Think of x as a batch and cut out a short interval waveform for each row of data. The length of the data varies. Here, the frame width is set to 2, and the cutout position is shifted by 1. [3, 1, 4, 1] is like [[3, 1], [1, 4], [4, 1]].

For the usual Tensor, there is a handy function called tf.signal.frame, but unfortunately It cannot be used forRaggedTensor``.

x = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])
print(tf.signal.frame(x, 2, 1)) # NG
# ValueError: TypeError: object of type 'RaggedTensor' has no len()
print(tf.signal.frame(x.to_tensor(), 2, 1)) #It works, but a lot of extra 0s come out
# tf.Tensor(
# [[[3 1]
#   [1 4]
#   [4 1]]
# 
#  [[0 0]
#   [0 0]
#   [0 0]]
# 
#  [[5 9]
#   [9 2]
#   [2 0]]
# 
#  [[6 0]
#   [0 0]
#   [0 0]]
# 
#  [[0 0]
#   [0 0]
#   [0 0]]], shape=(5, 3, 2), dtype=int32)

solution

Think based on x.values, which represents the values that are flattened, and the length and offset of each row from RaggedTensor.

print(x.values)        #Tensor with values
# tf.Tensor([3 1 4 1 5 9 2 6], shape=(8,), dtype=int32)
print(x.row_starts())  #Start index (offset) of each row in values
# tf.Tensor([0 4 4 7 8], shape=(5,), dtype=int64)
print(x.row_lengths()) #Length of each line
# tf.Tensor([4 0 3 1 0], shape=(5,), dtype=int64)

For each row of x, consider from which index of x.values the values should be taken (*).

--Line 0 is [0, 1], [1, 2], [2, 3] --The first line is empty --The second line is [4, 5], [5, 6] --The third line is empty --The fourth line is empty

First of all, if you make a RaggedTensor that has the first index of (*)

s = x.row_starts()
e = s + x.row_lengths() - 1
r = tf.ragged.range(s, e)
print(r)
# <tf.RaggedTensor [[0, 1, 2], [], [4, 5], [], []]>

In addition, you can combine the one-advanced indexes to see where in x.values you should get the values for the expected result after windowing. The results correspond to the previous bullet points (*).

ind = tf.stack([r, r+1], axis=2)
print(ind)
# <tf.RaggedTensor [[[0, 1], [1, 2], [2, 3]], [], [[4, 5], [5, 6]], [], []]>

After that, you can use tf.gather () to get the values from x.values based on the index entered in ```ind``.

ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1], [1, 4], [4, 1]], [], [[5, 9], [9, 2]], [], []]>

When the frame length is 3 or more

The way to make ʻe`` and ʻind is slightly different, but the general idea is the same. Broadcast is used to create `ʻind. For that, we add a dimension of length 1 at the end as r [:,:, tf.newaxis].

len_frame = 3
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1, 4], [1, 4, 1]], [], [[5, 9, 2]], [], []]>

Of course, it can be used even when len_frame = 2.

When the frameshift is 2 or more

It is OK if you change the step size of r.

len_frame = 2
shift_frame = 2
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e, shift_frame)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1], [4, 1]], [], [[5, 9]], [], []]>

You can also use shift_frame = 1.

If the sample is multidimensional

For example, in stereo audio, the L and R values are stored in pairs.

x = tf.ragged.constant([[[3, 2], [1, 7], [4, 1], [1, 8]], [], [[5, 2], [9, 8], [2, 1]], [[6, 8]], []])

In fact, it works in exactly the same way as before.

len_frame = 2
shift_frame = 1
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e, shift_frame)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[[3, 2], [1, 7]], [[1, 7], [4, 1]], [[4, 1], [1, 8]]], [], [[[5, 2], [9, 8]], [[9, 8], [2, 1]]], [], []]>

The number of dimensions has increased so much that I can't tell if it fits just by looking at it, but it should be okay ...

Recommended Posts

[TensorFlow] I want to process windows with Ragged Tensor
[TensorFlow] I want to master the indexing for Ragged Tensor
I want to do ○○ with Pandas
I want to debug with Python
I want to detect objects with OpenCV
I tried to implement Autoencoder with TensorFlow
I want to blog with Jupyter Notebook
I want to pip install with PythonAnywhere
I want to analyze logs with Python
I want to analyze songs with Spotify API 2
I want to mock datetime.datetime.now () even with pytest!
I want to knock 100 data sciences with Colaboratory
I want to make a game with Python
I want to be an OREMO with setParam!
I want to analyze songs with Spotify API 1
I want to use Temporary Directory with Python2
I don't want to use -inf with np.log
#Unresolved I want to compile gobject-introspection with Python3
I want to use ip vrf with SONiC
I want to solve APG4b with Python (Chapter 2)
I want to do pyenv + pipenv on Windows
I want to start over with Django's Migrate
[I want to classify images using Tensorflow] (2) Let's classify images
I want to write to a file with Python
I want to convert an image to WebP with lollipop
I want to detect unauthorized login to facebook with Jubatus (1)
I want to transition with a button in flask
I want to use self in Backpropagation (tf.custom_gradient) (tensorflow)
I want to climb a mountain with reinforcement learning
How to share folders with Docker and Windows with tensorflow
I want to inherit to the back with python dataclass
I want to work with a robot in python.
I want to split a character string with hiragana
I want to AWS Lambda with Python on Mac!
I want to manually create a legend with matplotlib
[ML Ops] I want to do multi-project with Python
I'm a windows user but want to run tensorflow
I tried to implement Grad-CAM with keras and tensorflow
I want to run a quantum computer with Python
I tried to find an alternating series with tensorflow
I want to bind a local variable with lambda
I want to be able to analyze data with Python (Part 3)
I want to specify another version of Python with pyvenv
I want to be able to analyze data with Python (Part 1)
I want to make a blog editor with django admin
I want to start a jupyter environment with one command
[NetworkX] I want to search for nodes with specific attributes
I want to make a click macro with pyautogui (desire)
I want to use only the normalization process of SudachiPy
I want to be able to analyze data with Python (Part 4)
For those who want to start machine learning with TensorFlow2
I want to color black-and-white photos of memories with GAN
I want to be able to analyze data with Python (Part 2)
I want to make a click macro with pyautogui (outlook)
[Python] I want to use the -h option with argparse
I want to use a virtual environment with jupyter notebook!
I want to install a package from requirements.txt with poetry
[Visualization] I want to draw a beautiful graph with Plotly
I want to terminate python's multiprocessing Pool with ctrl + c (KeyboardInterrupt)
I want to use a wildcard that I want to shell with Python remove
I want to know the weather with LINE bot feat.Heroku + Python