Dataset.from_generator не может реплицировать функциональность пустых массивов в качестве входных данных для 1D Convnet - PullRequest
0 голосов
/ 05 октября 2019

Я подаю много временных рядов длиной 100 и 3 функции в 1D Convnet. У меня их слишком много, чтобы использовать пустые массивы, поэтому мне нужно использовать Dataset.from_generator ().

Проблема в том, что, когда я тренирую модель в наборе данных, она выдает ошибку:

expected conv1d_input to have 3 dimensions, but got array with shape (100, 3)

Код ниже демонстрирует проблему. Генератор создает каждый элемент в виде ожидаемого (100,3) массива. Почему модель не распознает выходной сигнал генератора как действительный?

Большое спасибо за любую помощь. Джулиан

import numpy as np
import tensorflow as tf
def create_timeseries_element():
    # returns a random time series of 100 intervals, each with 3 features,
    # and a random one-hot array of 5 entries
    data = np.random.rand(100,3)
    label = np.eye(5, dtype='int')[np.random.choice(5)]
    return data, label

def data_generator():
    d, l = create_timeseries_element()
    yield (d, l)

model = tf.keras.models.Sequential([
    tf.keras.layers.Conv1D(128, 9, activation='relu', input_shape=(100, 3)),
    tf.keras.layers.Conv1D(128, 9, activation='relu'),
    tf.keras.layers.MaxPooling1D(2),
    tf.keras.layers.Conv1D(256, 5, activation='relu'),
    tf.keras.layers.Conv1D(256, 5, activation='relu'),
    tf.keras.layers.GlobalAveragePooling1D(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(5, activation='softmax')])
model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

x_train = []
y_train = []
for _ in range(1000):
    d, l = create_timeseries_element()
    x_train.append(d)
    y_train.append(l)
x_train = np.array(x_train)
y_train = np.array(y_train)

# train model with numpy arrays - this works
model.fit(x=x_train, y=y_train)

ds = tf.data.Dataset.from_generator(data_generator, output_types=(tf.float32, tf.int32),
                                      output_shapes=(tf.TensorShape([100, 3]), tf.TensorShape([5])))
# train model with dataset - this fails
model.fit(ds)

1 Ответ

0 голосов
/ 05 октября 2019

Модель ожидает партию / список образцов. Вы можете сделать это, просто установив пакетное свойство при создании набора данных следующим образом:

ds = tf.data.Dataset.from_generator(data_generator, output_types=(tf.float32, tf.int32),
                                      output_shapes=(tf.TensorShape([100, 3]), tf.TensorShape([5])))
ds = ds.batch(16)

Вы также можете сделать это другим способом при подготовке образца. Таким образом, вам нужно расширить измерение выборки, чтобы образец работал как пакет (вы также можете передать список выборок), и вам нужно сделать следующие изменения в вашем output_shapes наборе данных и create_timeseries_element function

def create_timeseries_element():
    # returns a random time series of 100 intervals, each with 3 features,
    # and a random one-hot array of 5 entries
    # Expand dimensions to create a batch of single sample
    data = np.expand_dims(np.random.rand(100, 3), axis=0)
    label = np.expand_dims(np.eye(5, dtype='int')[np.random.choice(5)], axis=0)
    return data, label

ds = tf.data.Dataset.from_generator(data_generator, output_types=(tf.float32, tf.int32), output_shapes=(tf.TensorShape([None, 100, 3]), tf.TensorShape([None, 5])))

Вышеуказанные изменения предоставят только одну партию (образец для первого решения) для каждой эпохи вашего набора данных. Вы можете сгенерировать столько пакетов (выборок для первого решения), сколько захотите (например, 25), передав параметр в функцию data_generator, пока вы определяете свой набор данных следующим образом:

def data_generator(count=1):
    for _ in range(count):
        d, l = create_timeseries_element()
        yield (d, l)

ds = tf.data.Dataset.from_generator(data_generator, args=[25], output_types=(tf.float32, tf.int32), output_shapes=(tf.TensorShape([None, 100, 3]), tf.TensorShape([None, 5])))
...