Нахождение правильной формы для tf.данных.Набор данных, поступающий в LSTM с маскировкой

#python #tensorflow #machine-learning #keras

Вопрос:

Я выполняю задачу классификации временных рядов, и у меня возникают проблемы с поиском правильного способа использования tf.data.Dataset . Я могу создать рабочую модель, используя массивы numpy, как в приведенном ниже коде (данные уже предварительно заполнены нулями до максимальной длины 180).:

 tf_data.shape, labels.shape
> ((225970, 180, 1), (225970,))
 

Таким образом, у меня есть 225970 экземпляров 180 временных шагов с 1 функцией.
И я могу подогнать модель следующим образом. Это прекрасно работает и создает соответствующие выходные данные/прогнозы:

 
model = keras.Sequential(
    [
         layers.Masking(mask_value=0, input_shape=(180,1)),
         layers.LSTM(16),
         layers.Dense(1, activation='sigmoid')
    ]
)

model.compile(
    optimizer='adam',
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=['accuracy']
)

model.fit(tf_data,  labels, epochs=5)
 

Однако, когда я пытаюсь выполнить следующее, используя tf.data.Dataset.from_tensors :

 tf_dataset = tf.data.Dataset.from_tensors((tf_data, labels.astype(int)))

tf_dataset = tf_dataset.shuffle(buffer_size=1024).batch(64)

model_v1 = keras.Sequential(
    [
        layers.Input(shape=(180,1), batch_size=64),
        layers.Masking(mask_value=0),
        layers.LSTM(16),
        layers.Dense(1, activation='sigmoid')
    ]
)
model_v2 = keras.Sequential(
    [
        layers.Masking(mask_value=0, shape=(180,1), batch_size=64),
        layers.LSTM(16),
        layers.Dense(1, activation='sigmoid')
    ]
)

<model_v1 or model_v2>.compile(
    optimizer='adam',
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=['accuracy']
)

<model_v1 or model_v2>.fit(tf_dataset, epochs=10, steps_per_epoch=30)
 

Я сталкиваюсь с ошибками

 model_v1 - ValueError: Error when checking input: expected input_48 to have 3 dimensions, but got array with shape (None, 225970, 180, 1)
model_v2 - ValueError: Error when checking input: expected masking_70_input to have 3 dimensions, but got array with shape (None, 225970, 180, 1)
 

Может ли кто-нибудь объяснить, что мне нужно сделать с моим набором данных tensorflow или с моей моделью, чтобы убедиться, что он будет работать с tf.data.Dataset массивом numpy, а не только с ним?

Ответ №1:

Вместо этого вы должны использовать tf.data.Dataset.from_tensor_slices ,

 tf_dataset = tf.data.Dataset.from_tensor_slices((tf_data, labels.astype(int)))
 

В соответствии с официальной документацией метода tf.data.Dataset.from_tensors ,

from_tensors создает набор данных, содержащий только один элемент. Чтобы разделить входной тензор на несколько элементов, используйте from_tensor_slices вместо этого.

В то время как официальные документы для tf.data.Dataset.from_tensor_slices говорит,

Данные тензоры разрезаны по их первому измерению. Эта операция сохраняет структуру входных тензоров, удаляя первое измерение каждого тензора и используя его в качестве измерения набора данных. Все входные тензоры должны иметь одинаковый размер в своих первых измерениях.

*.from_tensor_slices Метод разрезает входной тензор и рассматривает данный массив ( тензор в нашем случае ) как 225970 экземпляров данных. Это позволяет вызывать такие методы, как *.shuffle и *.batch() которые перемешивают и пакуют экземпляры данных соответственно.

Мы можем понять это на примере. Сначала давайте сгенерируем несколько фиктивных экземпляров данных.

 x = np.random.rand( 2500 , 180 , 1 )
y = np.random.rand( 2500 , 1 )
 

С *.from_tensors ,

 tensor_ds = tf.data.Dataset.from_tensors( ( x , y ) )
for sample in tensor_ds.take( 1 ):
    print( sample[ 0 ].shape )
    print( sample[ 1 ].shape )
 

На выходе получается,

 (2500, 180, 1)
(2500, 1)
 

И с *.from_tensor_slices ,

 tensor_ds = tf.data.Dataset.from_tensor_slices( ( x , y ) )
for sample in tensor_ds.take( 1 ):
    print( sample[ 0 ].shape )
    print( sample[ 1 ].shape )
 

На выходе получается,

 (180, 1)
(1,)
 

Комментарии:

1. Спасибо. Это сработало и было очень хорошим объяснением.