如何通过 keras 正确使用张量流数据集进行多个输入层

Jon*_*ker 1 python keras tensorflow tensorflow-datasets

我有多个输入层(20 个输入层),我想使用 atf.dataset来为模型提供数据。batch_size 是 16。不幸的model.fit(train_dataset, epochs=5)是抛出以下错误:

ValueError:检查模型输入时出错:传递给模型的 numpy 数组列表不是模型预期的大小。对于输入 ['input_2', ... , 'input_21'] 预计会看到 20 个数组,但得到以下 1 个数组的列表: [<tf.Tensor 'args_0:0' shape=(None, 20 , 512, 512, 3) dtype=int32>]...

我认为 keras 想要一个像(20,None,512,512,3)这样的形状。有人对这个问题有想法,或者如何为具有多个输入层的模型正确使用 tf.datasets 吗?

def read_tfrecord(bin_data):
    for i in feature_map_dict:
        label_seq[i] = tf_input_feature_selector(feature_map_dict[i])
    img_seq = {'images': tf.io.FixedLenSequenceFeature([], dtype=tf.string)}
    cont, seq = tf.io.parse_single_sequence_example(serialized=bin_data, context_features=label_seq, sequence_features=img_seq)
    image_raw = seq['images']
    images = decode_image_raw(image_raw)    
    images = tf.reshape(images, [20,512,512,3])
    images = preprocess_input(images)
    label = cont["label"]
    return images, label

def get_dataset(tfrecord_path):
    dataset = tf.data.TFRecordDataset(filenames=tfrecord_path)
    dataset = dataset.map(read_tfrecord)
    dataset = dataset.prefetch(buffer_size=AUTOTUNE)
    dataset = dataset.batch(BATCH_SIZE)
    return dataset

def create_model():
    nets =[]
    inputs=[]
    # Set up base model
    base_ResNet50 = ResNet50(weights='imagenet', include_top= False, input_shape=(512, 512, 3))    
    for images_idx in list(range(0,20)):
        x = Input(shape=(512,512,3))
        inputs.append(x)
        x = base_ResNet50(x)
        nets.append(x)
    maxpooling = tf.reduce_max(nets, [0])
    flatten = Flatten()(maxpooling)
    dense_1 = Dense(10,activation='sigmoid')(flatten)
    predictions = Dense(1,activation='sigmoid')(dense_1)
    model = Model(inputs=inputs, outputs=predictions)
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model
Run Code Online (Sandbox Code Playgroud)

提前致谢。

通过对 Niteya 的想法进行小幅修改,测试玩具模型即可运行训练。伟大的!

但我仍然对这个解决方案不满意,因为所有 20 个图像都属于一个对象,到目前为止我理解这个解决方案,我必须创建 21 个 tfrecord。这样,一个对象的信息就会分布在这些文件中。我想要一种更简单的解决方案,其中一个对象的所有信息都只在一个 tfrecord 中。

这个测试玩具模型有效!

import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.layers import Input, Flatten, Dense
from tensorflow.keras.models import Model

x_1 = Input(shape=(100,100,3))
x_2 = Input(shape=(100,100,3))
inputs = [x_1,x_2]
flatten_1 = Flatten()(x_1)
flatten_2 = Flatten()(x_2)
dense_1 = Dense(50,activation='sigmoid')
d1_1 = dense_1(flatten_1)
d1_2 = dense_1(flatten_2)
nets =[d1_1,d1_2]
maxpooling = tf.reduce_max(nets, [0])
d2 = Dense(10,activation='sigmoid')(maxpooling)
predictions = Dense(1,activation='sigmoid')(d2)
model = Model(inputs=inputs, outputs=predictions)

model.compile(loss='binary_crossentropy', optimizer='adam',
        metrics=['accuracy'])

for layer in model.layers:
    print(layer.name)

input_d = tf.data.Dataset.zip(tuple(tf.data.Dataset.from_tensors(tf.random.normal([16,100,100,3])) for i in range(2))) 
output = tf.data.Dataset.from_tensors(tf.ones(16))
dataset = tf.data.Dataset.zip((input_d, output))

model.fit(dataset,epochs=5)
Run Code Online (Sandbox Code Playgroud)

使用 Niteya 的第二个想法和函数 tf.split 是一个很好的解决方案。尼特亚,非常感谢你。

inputs = Input(shape=(20,512,512,3))
for x in tf.split(inputs,num_or_size_splits=20, axis=1):
        x = tf.reshape(x,[-1,512,512,3])
        x = base_ResNet50(x)
        nets.append(x)```  
and 
Run Code Online (Sandbox Code Playgroud)

BATCH_SIZE = 1 model.fit(train_dataset,steps_per_epoch = 10,epochs = 5)

Nit*_*hah 6

您考虑过使用tf.data.Dataset.zip吗?您的模型需要输入 20 个不同的输入,因此将它们压缩在一起,然后将该数据集与输出一起压缩,输出也需要压缩。

我正在使用随机输入,但您应该从中获取方法。

    input_d = tf.data.Dataset.zip(tuple(tf.data.Dataset.from_tensors(tf.random.normal([16, 512,512,3])) for i in range(20))) 
    output = tf.data.Dataset.from_tensors(tf.ones(16))
    dataset = tf.data.Dataset.zip((input_d, output))
Run Code Online (Sandbox Code Playgroud)

https://www.tensorflow.org/api_docs/python/tf/data/Dataset#zip

编辑:使用 split,可以完成类似的事情。传递整个数据集,然后分割它(您可能需要使用轴)。

    for i in tf.split(tf_record_Input, 20):
        x = base_ResNet50(i)
        nets.append(x)
Run Code Online (Sandbox Code Playgroud)