使用 image_dataset_from_directory 时是否可以将张量流数据集拆分为训练、验证和测试数据集?
Is it possible to split a tensorflow dataset into train, validation AND test datasets when using image_dataset_from_directory?
我正在使用 tf.keras.utils.image_dataset_from_directory
加载包含 4575 张图像的数据集。虽然此函数允许将数据拆分为两个子集(使用 validation_split
参数),但我想将其拆分为训练、测试和验证子集。
我尝试使用 dataset.skip()
和 dataset.take()
进一步拆分其中一个结果子集,但是这些函数 return a SkipDataset
和 TakeDataset
分别(顺便说一句,与 the documentation 相反,声称这些功能 return 和 Dataset
)。这会导致拟合模型时出现问题 - 在验证集上计算的指标 (val_loss、val_accuracy) 从模型历史记录中消失。
所以,我的问题是:有没有办法将一个Dataset
拆分成三个子集进行训练、验证和测试,使这三个子集也都是Dataset
对象?
用于加载数据的代码
def load_data_tf(data_path: str, img_shape=(256,256), batch_size: int=8):
train_ds = tf.keras.utils.image_dataset_from_directory(
data_path,
validation_split=0.2,
subset="training",
label_mode='categorical',
seed=123,
image_size=img_shape,
batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory(
data_path,
validation_split=0.3,
subset="validation",
label_mode='categorical',
seed=123,
image_size=img_shape,
batch_size=batch_size)
return train_ds, val_ds
train_dataset, test_val_ds = load_data_tf('data_folder', img_shape = (256,256), batch_size=8)
test_dataset = test_val_ds.take(686)
val_dataset = test_val_ds.skip(686)
模型编译与拟合
model.compile(optimizer='sgd',
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
metrics=['accuracy'])
history = model.fit(train_dataset, epochs=50, validation_data=val_dataset, verbose=1)
当使用正常的Dataset
时,val_accuracy
和val_loss
出现在历史模型中:
但是当使用 SkipDataset
时,它们不是:
问题是当您执行 test_val_ds.take(686)
和 test_val_ds.skip(686)
时,您并不是在获取和跳过样本,而是实际上是分批处理。尝试 运行 print(val_dataset.cardinality())
,您将看到您实际保留了多少批次用于验证。我猜 val_dataset
是空的,因为您没有 686 批次进行验证。这是一个工作示例:
import tensorflow as tf
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
batch_size = 32
train_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(180, 180),
batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(180, 180),
batch_size=batch_size)
test_dataset = val_ds.take(5)
val_ds = val_ds.skip(5)
print('Batches for testing -->', test_dataset.cardinality())
print('Batches for validating -->', val_ds.cardinality())
model = tf.keras.Sequential([
tf.keras.layers.Rescaling(1./255, input_shape=(180, 180, 3)),
tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(5)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
epochs=1
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=1
)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
Found 3670 files belonging to 5 classes.
Using 734 files for validation.
Batches for testing --> tf.Tensor(5, shape=(), dtype=int64)
Batches for validating --> tf.Tensor(18, shape=(), dtype=int64)
92/92 [==============================] - 96s 1s/step - loss: 1.3516 - accuracy: 0.4489 - val_loss: 1.1332 - val_accuracy: 0.5645
在这个例子中,batch_size
为 32,可以清楚地看到验证集保留了 23 个批次。之后,5批给测试集,18批留给验证集。
我正在使用 tf.keras.utils.image_dataset_from_directory
加载包含 4575 张图像的数据集。虽然此函数允许将数据拆分为两个子集(使用 validation_split
参数),但我想将其拆分为训练、测试和验证子集。
我尝试使用 dataset.skip()
和 dataset.take()
进一步拆分其中一个结果子集,但是这些函数 return a SkipDataset
和 TakeDataset
分别(顺便说一句,与 the documentation 相反,声称这些功能 return 和 Dataset
)。这会导致拟合模型时出现问题 - 在验证集上计算的指标 (val_loss、val_accuracy) 从模型历史记录中消失。
所以,我的问题是:有没有办法将一个Dataset
拆分成三个子集进行训练、验证和测试,使这三个子集也都是Dataset
对象?
用于加载数据的代码
def load_data_tf(data_path: str, img_shape=(256,256), batch_size: int=8):
train_ds = tf.keras.utils.image_dataset_from_directory(
data_path,
validation_split=0.2,
subset="training",
label_mode='categorical',
seed=123,
image_size=img_shape,
batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory(
data_path,
validation_split=0.3,
subset="validation",
label_mode='categorical',
seed=123,
image_size=img_shape,
batch_size=batch_size)
return train_ds, val_ds
train_dataset, test_val_ds = load_data_tf('data_folder', img_shape = (256,256), batch_size=8)
test_dataset = test_val_ds.take(686)
val_dataset = test_val_ds.skip(686)
模型编译与拟合
model.compile(optimizer='sgd',
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
metrics=['accuracy'])
history = model.fit(train_dataset, epochs=50, validation_data=val_dataset, verbose=1)
当使用正常的Dataset
时,val_accuracy
和val_loss
出现在历史模型中:
但是当使用 SkipDataset
时,它们不是:
问题是当您执行 test_val_ds.take(686)
和 test_val_ds.skip(686)
时,您并不是在获取和跳过样本,而是实际上是分批处理。尝试 运行 print(val_dataset.cardinality())
,您将看到您实际保留了多少批次用于验证。我猜 val_dataset
是空的,因为您没有 686 批次进行验证。这是一个工作示例:
import tensorflow as tf
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
batch_size = 32
train_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(180, 180),
batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(180, 180),
batch_size=batch_size)
test_dataset = val_ds.take(5)
val_ds = val_ds.skip(5)
print('Batches for testing -->', test_dataset.cardinality())
print('Batches for validating -->', val_ds.cardinality())
model = tf.keras.Sequential([
tf.keras.layers.Rescaling(1./255, input_shape=(180, 180, 3)),
tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(5)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
epochs=1
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=1
)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
Found 3670 files belonging to 5 classes.
Using 734 files for validation.
Batches for testing --> tf.Tensor(5, shape=(), dtype=int64)
Batches for validating --> tf.Tensor(18, shape=(), dtype=int64)
92/92 [==============================] - 96s 1s/step - loss: 1.3516 - accuracy: 0.4489 - val_loss: 1.1332 - val_accuracy: 0.5645
在这个例子中,batch_size
为 32,可以清楚地看到验证集保留了 23 个批次。之后,5批给测试集,18批留给验证集。