从python列表创建动态形状的张量以馈入tensorflow RNN

时间:2019-06-14 17:15:53

标签: python numpy tensorflow keras

我正在创建一个端到端语音识别体系结构,其中的数据是分段频谱图的列表。我的数据的形状为(batch_size, timesteps, 8, 65, 1),其中batch_size是固定的,但是timesteps是变化的。我不知道如何将这些数据放入具有适当形状的张量中以馈入模型。这是一段显示我的问题的代码:

import numpy as np
import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.layers import Conv2D, MaxPool2D, Dense, Dropout, Flatten, TimeDistributed
from tensorflow.keras.layers import SimpleRNN, LSTM
from tensorflow.keras import Input, layers
from tensorflow.keras import backend as K

segment_width = 8
segment_height = 65
segment_channels = 1

batch_size = 4

segment_lengths = [28, 33, 67, 43]
label_lengths = [16, 18, 42, 32]

TARGET_LABELS = np.arange(35)

# Generating data
X = [np.random.uniform(0,1, size=(segment_lengths[k], segment_width, segment_height, segment_channels))
     for k in range(batch_size)]

y = [np.random.choice(TARGET_LABELS, size=label_lengths[k]) for k in range(batch_size)]

# Model definition
input_segments_data = tf.keras.Input(name='input_segments_data', shape=(None, segment_width, segment_height, segment_channels),
                               dtype='float32')
input_segment_lengths = tf.keras.Input(name='input_segment_lengths', shape=[1], dtype='int64')
input_label_lengths = tf.keras.Input(name='input_label_lengths', shape=[1], dtype='int64')
# More complex architecture comes here
outputs = Flatten()(input_segments_data)

model = tf.keras.Model(inputs=[input_segments_data, input_segment_lengths, input_label_lengths], outputs = outputs)

def dummy_loss(y_true, y_pred):
  return y_pred

model.compile(optimizer="Adam", loss=dummy_loss)
model.summary()

输出:

Model: "model"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_segments_data (InputLayer [(None, None, 8, 65, 0                                            
__________________________________________________________________________________________________
input_segment_lengths (InputLay [(None, 1)]          0                                            
__________________________________________________________________________________________________
input_label_lengths (InputLayer [(None, 1)]          0                                            
__________________________________________________________________________________________________
flatten (Flatten)               (None, None)         0           input_segments_data[0][0]        
==================================================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0
__________________________________________________________________________________________________

现在,当我尝试根据随机数据进行预测时:

model.predict([X, segment_lengths, segment_lengths])

我收到此错误:

ValueError: Error when checking input: expected input_segments_data to have 5 dimensions, but got array with shape (4, 1)

如何将X(是数组列表)转换为形状为(None, None, 8, 65, 1)的张量并将其馈送到模型中?我不想使用零填充!

2 个答案:

答案 0 :(得分:2)

Keras模型将numpy数组(张量)作为输入。您不能使用具有可变时间步长的张量。相反,您可以做的是使用例如pad_sequence,然后,您可以在模型中添加Masking layer,以忽略填充的值。

答案 1 :(得分:1)

这是Tensorflow和其他在张量上运行的深度学习框架的常见问题。不幸的是,除了对序列进行填充然后进行掩蔽处理外,目前还没有一种完全按照您要求的简单方法。

为此,您只需将输入数据存储在具有固定尺寸的numpy数组中,然后将其输入模型。您必须添加虚拟值来表示序列中缺少的时间步(通用值为0)。

然后,您必须在模型中添加一个Masking层,这将告诉Keras忽略具有虚拟功能的时间步。 来自the documentation

  

keras.layers.Masking(mask_value=0.0)

     

如果给定采样时间步长的所有特征均等于mask_value,则采样时间步长将在所有下游层中被屏蔽(跳过)(只要它们支持屏蔽)。

我已经修改并简化了部分代码,以使您了解其工作原理。您也可以将其调整为可变大小的标签:

# Generating data (using a dummy zero-array to store padded sequences)
X = np.zeros((batch_size, max(segment_lengths), segment_width, segment_height, segment_channels))
X_true = [np.ones((segment_lengths[k], segment_width, segment_height, segment_channels)) 
          for k in range(batch_size)]

# Populate dummy array
for i, x in enumerate(X_true): 
    X[i, -segment_lengths[i]:, ...] = x

# Model definition
input_segments_data = tf.keras.Input(name='input_segments_data', shape=(max(segment_lengths), segment_width, segment_height, segment_channels))
masked_segments_data = tf.keras.layers.Masking()(input_segments_data)

# More complex architecture comes here
outputs = tf.keras.layers.Flatten()(input_segments_data)

model = tf.keras.Model(inputs=input_segments_data, outputs = outputs)

def dummy_loss(y_true, y_pred):
  return y_pred

model.compile(optimizer="Adam", loss=dummy_loss)
model.summary()

这种方法的一个缺点是,如果您实际上拥有一个与假特征完全相同的“真实”特征(例如全零),则模型会将其掩盖。适当选择掩蔽值可避免这种情况。

一种替代方法是执行与您的操作类似的操作,但使用一批1号。但是,这可能会导致您的训练过程不稳定,因此,我会尽量避免这种情况。

最后一点,Tensorflow 2增加了对RaggedTensors的支持,filter是具有一个或多个可变尺寸的张量。当前不支持RNN,但最终可能会添加它。

希望这会有所帮助。