请评标。我正在尝试连接两个输入,一个用于图像,一个用于文本。
我不是专家,而且我是功能性API的新手,所以我很难在这里发现问题。
在下面的代码中,我确认我可以训练text_features和image_features模型,但是当我尝试训练端到端模型时,它会检索错误:
ValueError: Failed to find data adapter that can handle input: (<class 'dict'> containing {"<class 'str'>"} keys and {"<class 'tensorflow.python.data.ops.dataset_ops.PrefetchDataset'>"} values), <class 'NoneType'>
我可以想象我正面临一个相当基本的问题,但问题是我找不到一个同时使用图像和文本的简单例子,所以我看不出它在哪里。
我将复制我使用的整个代码,并尝试对每一步进行注释,因此这不会成为一个一般的调试问题。
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
import re
import string
首先,我为文本和图像数据集定义了一个通用的批大小和种子。我的图片和文本文件都保存在一个单独的25个文件夹中。
假设文件夹1有一个名为sample_1.png的文件。它还有一个名为sample_1.txt的文件,该文件对应于与所述图像关联的文本,存储为单个字符串(使用json)。
batch_size = 32
seed = 42
然后,加载文本数据。在这里,我尝试遵循这个例子:没有循环层的基本文本分类。唯一的区别是我的输出不是二进制的。
raw_text_train_ds =tf.keras.utils.text_dataset_from_directory(
'NEURAL',
batch_size=batch_size,
validation_split=0.2,
subset='training',
seed=seed)
raw_text_val_ds = tf.keras.utils.text_dataset_from_directory(
'NEURAL',
batch_size=batch_size,
validation_split=0.2,
subset='validation',
seed=seed)
我遵循参考示例的处理步骤,只是我之前已经处理了我的文本中的标点符号和类似的东西。
max_features = 7000
sequence_length = 250
vectorize_layer = layers.TextVectorization(
max_tokens=max_features,
output_mode='int',
output_sequence_length=sequence_length)
train_text = raw_text_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(train_text)
def vectorize_text(text, label):
text = tf.expand_dims(text, -1)
return vectorize_layer(text), label
text_train_ds = raw_text_train_ds.map(vectorize_text)
text_val_ds = raw_text_val_ds.map(vectorize_text)
在应用上述示例的AUTOTUNE部分之前,我上传了图像数据集,尝试遵循以下示例:使用增强层进行图像分类
img_height = 180
img_width = 180
img_train_ds = tf.keras.utils.image_dataset_from_directory(
'NEURAL',
validation_split=0.2,
subset="training",
seed=seed,
image_size=(img_height, img_width),
batch_size=batch_size)
img_val_ds = tf.keras.utils.image_dataset_from_directory(
'NEURAL',
validation_split=0.2,
subset="validation",
seed=seed,
image_size=(img_height, img_width),
batch_size=batch_size)
我想知道应用下面的数据增强层是否会导致某种不匹配,但我不这么认为。再一次,我很确定我的错误是最基本的。
data_augmentation = keras.Sequential(
[
layers.RandomRotation(0.04,
input_shape=(img_height,
img_width,
3)),
layers.RandomZoom(0.1),
]
)
由于两个引用的示例都建议应用以下AUTOTUNING,因此我同时对两个数据集执行此操作。
AUTOTUNE = tf.data.AUTOTUNE
text_train_ds = text_train_ds.cache().prefetch(buffer_size=AUTOTUNE)
text_val_ds = text_val_ds.cache().prefetch(buffer_size=AUTOTUNE)
# test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)
img_train_ds = img_train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
img_val_ds = img_val_ds.cache().prefetch(buffer_size=AUTOTUNE)
在这里,我定义了两个模型,正如它们在我试图遵循的示例中定义的那样,但我试图使它们适应API方法。
num_classes = 25
text_input = keras.Input(shape=(None,), name="text")
text_features = layers.Embedding(max_features+1, 16)(text_input)
text_features = layers.Dropout(0.2)(text_features)
text_features = layers.GlobalAveragePooling1D()(text_features)
text_features = layers.Dropout(0.2)(text_features)
text_features = layers.Dense(32)(text_features)
text_features = keras.Model(text_input,text_features)
image_input = keras.Input(shape=(180, 180, 3),name="image")
image_features=data_augmentation(image_input)
image_features=layers.Rescaling(1./255)(image_features)
image_features=layers.Conv2D(16, 3, padding='same', activation='relu')(image_features)
image_features=layers.MaxPooling2D()(image_features)
image_features=layers.Conv2D(32, 3, padding='same', activation='relu')(image_features)
image_features= layers.MaxPooling2D()(image_features)
image_features=layers.Conv2D(64, 3, padding='same', activation='relu')(image_features)
image_features=layers.MaxPooling2D()(image_features)
image_features=layers.Dropout(0.2)(image_features)
image_features=layers.Flatten()(image_features)
image_features=layers.Dense(128, activation='relu')(image_features)
image_features=layers.Dense(32, activation='relu')(image_features)
image_features=keras.Model(image_input,image_features)
x = layers.concatenate([text_features.output, image_features.output])
category_pred = layers.Dense(num_classes, name="classes")(x)
model = keras.Model(
inputs=[text_input, image_input],
outputs=[category_pred],)
我尝试了不同的损失、参数和优化器,只是为了尝试解决问题。
我觉得这可能是一个语义问题,因为错误表明(记住,不是这里的专家)模型不理解我试图引入的输入。但这是我研究的例子中输入的引入方式,所以我迷路了。
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
epochs = 1
checkpoint_path = "training_3_test_ojo/cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)
model.fit(
{'image':img_train_ds,
'text':text_train_ds,
},
epochs=epochs,
batch_size=32,)
问题可能是我天真地认为我可以独立加载我的两个数据集,并期望我的模型会找到连接它们的方法。
我没有指定训练的预期输出,再次假设模型将从输入中提取它。但我试着详细说明它,但它没有任何区别。我也会认为这是我代码的问题。不指定预期输出适用于我使用的"图像分类"示例,但我确实意识到它不一定适用于具有多个输入的模型。
我将感谢任何解决方案,指导或参考。
根据fit()
的文档,如果要传递一个字典,键需要指向一个数组或张量。您正在使用tensorflow.python.data.ops.dataset_ops.PrefetchDataset
,它不能与dict一起工作。