You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tf.data.Dataset传入seq2seq模型fit时的格式错误解决请求

构建Seq2Seq模型的数据集格式问题

问题背景

我正在基于词嵌入相关内容构建Seq2Seq模型,输入为context、question、answer的拼接序列,输出为answer序列,采用Keras函数式API搭建,但在数据集格式适配中反复出现错误。

尝试过程及错误

第一次尝试:分数据集传入fit_generator

代码:

train_cont_ds = tf.data.Dataset.from_tensor_slices(train["clean_context"].values)
train_q_ds = tf.data.Dataset.from_tensor_slices(train["clean_question"].values)
train_a_ds = tf.data.Dataset.from_tensor_slices(train["clean_answer"].values)

# 文本向量化步骤省略

c_input = Input(shape=(1,))
q_input = Input(shape=(1,))
a_input = Input(shape=(1,))

c_vec = context_vec_layer(c_input)
q_vec = q_vec_layer(q_input)
a_vec = a_vec_layer(a_input)

c_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(c_vec)
q_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(q_vec)
a_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(a_vec)

c_pool = GlobalAveragePooling1D()(c_emb)
q_pool = GlobalAveragePooling1D()(q_emb)
a_pool = GlobalAveragePooling1D()(a_emb)

concat = concatenate([c_pool,q_pool,a_pool])
    
Y_pred = Dense(QUES_LEN, activation='relu')(concat)
model = Model(inputs = [c_input,q_input,a_input], outputs = Y_pred)

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.summary()
model.fit_generator(
     [train_cont_ds,train_q_ds,train_a_ds],
     train_a_ds, validation_data=(
     [cv_cont_ds,cv_q_ds,cv_a_ds],
     cv_a_ds), verbose=1,epochs=epochs, callbacks=[tensorboard_callback, cp_callback])

错误:

ValueError: Failed to find data adapter that can handle input: (<class 'list'> containing values of types {"<class 'tensorflow.python.data.ops.dataset_ops.BatchDataset'>"}), <class 'NoneType'>

第二次尝试:封装输入为元组

代码:

train_ds = tf.data.Dataset.from_tensor_slices(((train["clean_context"].values, train["clean_question"].values, train["clean_answer"].values),  train["clean_answer"].values))
train_ds = train_ds.batch(batch_size)
cv_ds = tf.data.Dataset.from_tensor_slices(((cv["clean_context"].values, cv["clean_question"].values, cv["clean_answer"].values),  cv["clean_answer"].values))
cv_ds = train_ds.batch(batch_size)
dev_ds = tf.data.Dataset.from_tensor_slices(((dev["clean_context"].values, dev["clean_question"].values, dev["clean_answer"].values),  dev["clean_answer"].values))
dev_ds = train_ds.batch(batch_size)

错误:文本向量化层适配失败。

第三次尝试:拼接数据集并转迭代器

代码:

train_cont_ds = tf.data.Dataset.from_tensor_slices(train["clean_context"].values)
train_q_ds = tf.data.Dataset.from_tensor_slices(train["clean_question"].values)
train_a_ds = tf.data.Dataset.from_tensor_slices(train["clean_answer"].values)
train_a_ds = train_a_ds.batch(batch_size)

train_ds = train_cont_ds.concatenate(train_q_ds).concatenate(train_a_ds)
train_ds = train_ds.batch(batch_size)

cv_cont_ds = tf.data.Dataset.from_tensor_slices(cv["clean_context"].values)
cv_q_ds = tf.data.Dataset.from_tensor_slices(cv["clean_question"].values)
cv_a_ds = tf.data.Dataset.from_tensor_slices(cv["clean_answer"].values)
cv_a_ds = cv_a_ds.batch(batch_size)

cv_ds = cv_cont_ds.concatenate(cv_q_ds).concatenate(cv_a_ds)
cv_ds = cv_ds.batch(batch_size)

dev_cont_ds = tf.data.Dataset.from_tensor_slices(dev["clean_context"].values)
dev_q_ds = tf.data.Dataset.from_tensor_slices(dev["clean_question"].values)
dev_a_ds = tf.data.Dataset.from_tensor_slices(dev["clean_answer"].values)
dev_a_ds = dev_a_ds.batch(batch_size)

dev_ds= dev_cont_ds.concatenate(dev_q_ds).concatenate(dev_a_ds)
dev_ds = train_ds.batch(batch_size)

hist = model.fit(
     [train_ds.as_numpy_iterator()], train_a_ds.as_numpy_iterator(),
            validation_data=(
            [cv_ds.as_numpy_iterator()], cv_a_ds.as_numpy_iterator()),
            verbose=1,epochs=epochs, callbacks=[tensorboard_callback])

错误:

ValueError: Failed to find data adapter that can handle input: (<class 'list'> containing values of types {"<class 'tensorflow.python.data.ops.dataset_ops._NumpyIterator'>"}), <class 'tensorflow.python.data.ops.dataset_ops._NumpyIterator'>

第四次尝试:用生成器封装数据集

代码:

def gen():
    for element in zip(train_ds,train_a_ds):
        yield element
ds = tf.data.Dataset.from_generator(gen,output_types=tf.dtypes.float32)

def v_gen():
    for element in zip(cv_ds,cv_a_ds):
        yield element
v_ds = tf.data.Dataset.from_generator(v_gen,output_types=tf.dtypes.float32)

hist = model.fit_generator(
     ds,validation_data=(v_ds),
     verbose=1,epochs=epochs, callbacks=[tensorboard_callback])

错误:

ValueError: Target data is missing. Your model was compiled with loss=<keras.losses.BinaryCrossentropy object at 0x00000139D15BA610>, and therefore expects target data to be provided in `fit()`.

正确的数据集格式及解决方案

核心问题

所有错误的根源是输入数据结构与模型Input层不匹配,且tf.data.Dataset没有正确封装输入-标签对。多输入模型要求输入必须是与Input层一一对应的张量集合,标签单独作为目标。

步骤1:正确适配文本向量化层

文本向量化层需要先适配训练数据,确保能将文本转为固定长度的整数序列:

# 定义三个文本向量化层,分别对应context、question、answer的序列长度
CONTEXT_LEN = 200  # 根据你的数据调整
QUESTION_LEN = 50
ANSWER_LEN = 30

context_vec_layer = tf.keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE, 
    output_sequence_length=CONTEXT_LEN
)
q_vec_layer = tf.keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE, 
    output_sequence_length=QUESTION_LEN
)
a_vec_layer = tf.keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE, 
    output_sequence_length=ANSWER_LEN
)

# 适配训练数据
context_vec_layer.adapt(train["clean_context"].values)
q_vec_layer.adapt(train["clean_question"].values)
a_vec_layer.adapt(train["clean_answer"].values)

步骤2:构建符合要求的tf.data.Dataset

将多个输入封装为元组,标签作为元组的第二部分,同时在Dataset中完成向量化预处理:

# 构建训练集:(输入元组, 标签)
train_ds = tf.data.Dataset.from_tensor_slices(
    (
        (train["clean_context"].values, train["clean_question"].values, train["clean_answer"].values),
        train["clean_answer"].values
    )
)

# 构建验证集
cv_ds = tf.data.Dataset.from_tensor_slices(
    (
        (cv["clean_context"].values, cv["clean_question"].values, cv["clean_answer"].values),
        cv["clean_answer"].values
    )
)

# 定义预处理函数:将文本转为向量
def preprocess(inputs, labels):
    c_text, q_text, a_text = inputs
    c_vec = context_vec_layer(c_text)
    q_vec = q_vec_layer(q_text)
    a_vec = a_vec_layer(a_text)
    return (c_vec, q_vec, a_vec), labels

# 应用预处理、批量、预取优化
train_ds = train_ds.batch(batch_size).map(preprocess, num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)
cv_ds = cv_ds.batch(batch_size).map(preprocess, num_parallel_calls=tf.data.AUTOTUNE).prefetch(tf.data.AUTOTUNE)

步骤3:修正模型Input层形状

向量化后的输入是固定长度的序列,所以Input层的shape应该对应序列长度,而非(1,):

c_input = Input(shape=(CONTEXT_LEN,))
q_input = Input(shape=(QUESTION_LEN,))
a_input = Input(shape=(ANSWER_LEN,))

# 后续嵌入、池化、拼接逻辑不变
c_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(c_input)
q_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(q_input)
a_emb = Embedding(VOCAB_SIZE, GLOVE, weights=[embedding_matrix], trainable=False, mask_zero=True)(a_input)

c_pool = GlobalAveragePooling1D()(c_emb)
q_pool = GlobalAveragePooling1D()(q_emb)
a_pool = GlobalAveragePooling1D()(a_emb)

concat = concatenate([c_pool, q_pool, a_pool])

# 注意:Seq2Seq任务若为生成序列,建议输出改为词汇表大小,用SparseCategoricalCrossentropy损失
Y_pred = Dense(VOCAB_SIZE, activation='softmax')(concat)
model = Model(inputs=[c_input, q_input, a_input], outputs=Y_pred)

# 修正损失函数
model.compile(
    optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(),
    metrics=['accuracy']
)

步骤4:正确调用模型训练

此时Dataset格式完全匹配模型输入,直接传入fit即可:

model.fit(
    train_ds,
    validation_data=cv_ds,
    epochs=epochs,
    callbacks=[tensorboard_callback, cp_callback]
)

内容的提问来源于stack exchange,提问作者Manal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:27:05