Tensorflow 2中的fit方法中使用Dataset和ndarray有什么区别?

Zho*_*_11 11 keras tensorflow

作为 TF 的新手,我对 BatchDataset 在训练模型中的使用感到有点困惑。

让我们以 MNIST 为例。在这个分类任务中,我们可以加载数据并将x_trian、y_train的ndarray直接输入到模型中。

mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

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

model.fit(x_train,y_train, epochs=5)

Run Code Online (Sandbox Code Playgroud)

训练结果为:

Epoch 1/5
2021-02-17 15:43:02.621749: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library cublas64_10.dll
   1/1875 [..............................] - ETA: 0s - loss: 2.2977 - accuracy: 0.0938WARNING:tensorflow:Callbacks method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0000s vs `on_train_batch_end` time: 0.0010s). Check your callbacks.
1875/1875 [==============================] - 2s 1ms/step - loss: 0.3047 - accuracy: 0.9117
Epoch 2/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.1473 - accuracy: 0.9569
Epoch 3/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.1097 - accuracy: 0.9673
Epoch 4/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0905 - accuracy: 0.9724
Epoch 5/5
1875/1875 [==============================] - 2s 1ms/step - loss: 0.0759 - accuracy: 0.9764
Run Code Online (Sandbox Code Playgroud)

我们还可以使用 tf.data.Dataset.from_tensor_slices 生成 BatchDataset 并将其输入到 fit 函数中。

mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

train_ds = tf.data.Dataset.from_tensor_slices(
    (x_train, y_train)).shuffle(10000).batch(32)

test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

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

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

训练过程的结果如下。

Epoch 1/5
2021-02-17 15:30:34.698718: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library cublas64_10.dll
1875/1875 [==============================] - 3s 1ms/step - loss: 0.2969 - accuracy: 0.9140
Epoch 2/5
1875/1875 [==============================] - 3s 1ms/step - loss: 0.1462 - accuracy: 0.9566
Epoch 3/5
1875/1875 [==============================] - 3s 1ms/step - loss: 0.1087 - accuracy: 0.9669
Epoch 4/5
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0881 - accuracy: 0.9730
Epoch 5/5
1875/1875 [==============================] - 3s 1ms/step - loss: 0.0765 - accuracy: 0.9759
Run Code Online (Sandbox Code Playgroud)

通过2种方法都可以成功训练模型,但是它们之间有什么区别吗?使用数据集进行训练是否有一些额外的优势?如果在这种情况下两种方法没有区别,那么生成训练数据集的典型用法是什么以及何时应该使用此方法?

谢谢。

M.I*_*nat 8

当我们使用Model.fit(x=None, y=None, ...- 时,我们可以将训练对参数作为纯numpy数组 or keras.utils.Sequenceor传递tf.data

当我们如下使用时,我们将每个训练对 (xy) 作为直接 numpy 数组分别传递给函数fit

# data 
(x_train, y_train), (_, _) = tf.keras.datasets.mnist.load_data()

# fit
model.fit(x = x_train, y = y_train, ... 

# check
print(x_train.shape, y_train.shape)
print(type(x_train), type(y_train))

# (60000, 28, 28) (60000,)
# <class 'numpy.ndarray'> <class 'numpy.ndarray'>
Run Code Online (Sandbox Code Playgroud)

另一方面,tf.data我们Sequence将训练对作为元组的形状传递,并且数据类型仍然是ndarray。根据医生的说法

  • 一个tf.data数据集。inputs应该返回 ( , targets)的元组
  • 生成器或keras.utils.Sequence返回 ( inputs, targets)

IE

# data
train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(2)

# check
next(iter(train_ds))

(<tf.Tensor: shape=(2, 28, 28), dtype=uint8, numpy= array([[[...], [[...]]], dtype=uint8)>,
 <tf.Tensor: shape=(2,), dtype=uint8, numpy=array([7, 8], dtype=uint8)>)
Run Code Online (Sandbox Code Playgroud)

这就是为什么 ifxtf.datagenerator、 或keras.utils.Sequence实例,y不应被指定(因为目标将从 获得x)。

# fit 
model.fit(train_ds, ...
Run Code Online (Sandbox Code Playgroud)

在这三种方法中,tf.data数据管道是最有效的方法,其次是generator. 当数据集足够小时,主要选择第一种方法(x和)。y但是当数据集变得足够大时,您就会考虑tf.datagenerator高效的输入管道。所以这些的选择完全取决于。

来自 Keras 的帖子

  • NumPy 数组,就像 Scikit-Learn 和许多其他基于 Python 的库一样。如果您的数据适合内存,那么这是一个不错的选择。

  • TensorFlow 数据集对象。这是一个高性能选项,更适合不适合内存的数据集以及从磁盘或分布式文件系统流式传输的数据集。

  • 生成批量数据的Python 生成器(例如 keras.utils.Sequence 类的自定义子类)。