我正在使用tf.keras API来构建CNN模型,并使用tf.Dataset API来为模型创建输入管道。 tf.keras.datasets
中的mnist数据集用于测试并通过执行以下代码在内存中进行准备:
(train_images,train_labels),(test_images,test_labels) = tf.keras.datasets.mnist.load_data()
以及一些与我的keras模型兼容的预处理:
Train_images = np.expand_dims(train_images,3).astype('float')/255.0
Test_images = np.expand_dims(test_images,3).astype('float')/255.0
Train_labels = tf.keras.utils.to_categorical(train_labels)
Test_labels = tf.keras.utils.to_categorical(test_labels)
那些数据作为数组存储在内存中,有两个选项可用于创建数据集对象。第一个只是使用tf.data.Dataset.from_tensor_slices
:
image = tf.data.Dataset.from_tensor_slices((Train_images,Train_labels))
并将此结果对象输入到model.fit():
model.fit(x=image,steps_per_epoch=1000)
或通过以下方式输入此数据集的迭代器:
iterator = image.make_one_shot_iterator()
model.fit(x=iterator,steps_per_epoch=1000)
这两个选项都可以正常工作,因为使用内存中的数据创建了名为image的数据集。但是,根据此处的Importing Data,我们可能希望避免这样做,因为它会多次复制数据并占用内存。因此,另一种选择是基于tf.placeholder
和可初始化的迭代器创建这样的数据集对象:
X = tf.placeholder(tf.float32,shape = [60000,28,28,1])
Y = tf.placeholder(tf.float32,shape = [60000,10])
image2 = tf.data.Dataset.from_tensor_slices((X,Y))
iterator2 = image.make_initializable_iterator()
with tf.Session() as sess:
sess.run(iterator2.initializer,feed_dict={X:Train_images,Y:Train_labels}
sess.run(iterator2.get_next())
当使用tf.Session()
并向内存中的数据馈送时,这种迭代器可以很好地工作,并且可以避免数据的多个副本。但是我找不到让它与keras.model.fit()
一起工作的方法,因为您不能真正调用iterator.initializer
或在此处输入任何数据。有没有办法使用这种迭代器?
答案 0 :(得分:1)
我不认为keras会正式支持传递可初始化的迭代器的情况,正如您所指出的那样,没有地方提供占位符和值映射。
不过,可以使用keras callbacks解决该问题:
import tensorflow as tf
import numpy as np
import pandas as pd
# Make sure only tensorflow.keras is imported, don't mix with keras
from tensorflow.keras import layers
import tensorflow.keras.backend as K
# example data
x_values = np.random.randn(200, 100).astype(np.float32)
y_labels = np.random.randint(low=0, high=9, size=200)
graph = tf.Graph()
with graph.as_default():
# make datasets from placeholders as in https://www.tensorflow.org/guide/datasets#reading_input_data
# X:
features_placeholder = tf.placeholder(tf.float32, x_values.shape, name='features')
dataset_x = tf.data.Dataset.from_tensor_slices({'x': features_placeholder})
# Y:
labels_placeholder = tf.placeholder(tf.float32, [None], name='labels')
dataset_y = tf.data.Dataset.from_tensor_slices({'y': labels_placeholder})
# compose datasets to make X-Y pairs for training
dataset0 = tf.data.Dataset.zip((dataset_x, dataset_y))
dataset0 = dataset0.batch(16).repeat()
# build model with keras
inputs = tf.keras.Input(name='x', shape=(x_values.shape[1],))
mlp1 = layers.Dense(16, name='mlp-1', activation='relu')
mlp1_out = mlp1(inputs)
output = layers.Dense(1, name='y', activation='linear')
output_out = output(mlp1_out)
model = tf.keras.Model(inputs=inputs, outputs=output_out)
# The compile step specifies the training configuration.
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001), loss='mse', metrics=['mse'])
iterator = dataset0.make_initializable_iterator()
feed_dict = { labels_placeholder: y_labels, features_placeholder: x_values }
class InitIteratorCallback(tf.keras.callbacks.Callback):
"""
Ensures that placeholders in dataset are initialized before each epoch begins
"""
def on_epoch_begin(self, epoch, logs=None):
sess = K.get_session()
sess.run(iterator.initializer, feed_dict=feed_dict)
model.fit(iterator, callbacks=[InitIteratorCallback()],
epochs=10, steps_per_epoch=300)