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

Keras多输入模型训练报错:非符号张量输入问题求解

问题:Keras训练时如何引入全局固定的输入向量组?

我想要训练一个Keras模型,其输入为尺寸(20, 300)的向量。但需在每个训练步骤中输入一组对所有样本均固定的向量组。以下是我的尝试代码:

def create_model(num_filters=64, embedding_dim=300, seq_len=20):
    # input1 Shape (?,20,300)
    input1 = Input(shape=(seq_len,embedding_dim,), dtype='float32') # Input1 taken from the model input
    # input2 Shape (5,20,300)
    input2=get_input2() # Input2: taken from outside the model
    # CNN Encoding of Input 1
    convs = []
    filter_sizes = [1,2,3]
    for fsz in filter_sizes:
        x = Conv1D(num_filters, fsz, activation='relu',padding='same')(input1)
        x = MaxPooling1D()(x)
        convs.append(x)
    output1 = Concatenate(axis=-1)(convs)
    output1 = Flatten()(output1)
    # CNN Encoding of Input 2
    convs1 = []
    filter_sizes = [1,2,3]
    for fsz in filter_sizes:
        x1 = Conv1D(num_filters, fsz, activation='relu',padding='same')(input2)
        x1 = MaxPooling1D()(x1)
        convs1.append(x1)
    output2 = Concatenate(axis=-1)(convs1)
    output2 = Flatten()(output2)

然而该实现抛出值错误:

ValueError: Layer conv1d_60 was called with an input that isn't a symbolic tensor. Received type: .

请问在Keras中应如何正确实现该需求?


解决方案

这个问题我之前也碰到过,本质是没搞清楚Keras构建计算图时对输入的要求——你直接用get_input2()拿到的是普通张量/数组,不是Keras需要的符号张量,所以无法被Conv1D这类层处理。下面给你两种可行的解决思路,按需选择:

方案1:把固定向量组设为模型的第二个输入

这是最直观的方式,把全局固定的向量组也定义成模型的输入,训练时每次batch都重复传入它就行(因为对所有样本都一样)。

修改后的模型代码:

def create_model(num_filters=64, embedding_dim=300, seq_len=20):
    # 输入1:每个样本的特征向量,shape (?,20,300)
    input1 = Input(shape=(seq_len, embedding_dim,), dtype='float32')
    # 输入2:全局固定的向量组,shape (5,20,300),作为模型的输入
    input2 = Input(shape=(5, seq_len, embedding_dim,), dtype='float32')
    
    # 编码input1的CNN模块
    convs = []
    filter_sizes = [1,2,3]
    for fsz in filter_sizes:
        x = Conv1D(num_filters, fsz, activation='relu', padding='same')(input1)
        x = MaxPooling1D()(x)
        convs.append(x)
    output1 = Concatenate(axis=-1)(convs)
    output1 = Flatten()(output1)
    
    # 编码input2的CNN模块
    convs1 = []
    for fsz in filter_sizes:
        x1 = Conv1D(num_filters, fsz, activation='relu', padding='same')(input2)
        x1 = MaxPooling1D()(x1)
        convs1.append(x1)
    output2 = Concatenate(axis=-1)(convs1)
    output2 = Flatten()(output2)
    
    # 这里可以继续添加后续逻辑,比如合并两个编码结果后做分类/回归
    combined = Concatenate(axis=-1)([output1, output2])
    final_output = Dense(1, activation='sigmoid')(combined)
    
    # 创建包含两个输入的模型
    model = Model(inputs=[input1, input2], outputs=final_output)
    return model

训练时的调用方式:

# 获取全局固定的向量组
fixed_input2 = get_input2()  # shape (5,20,300)
# 假设你的训练数据是x_train (n_samples,20,300),y_train是对应的标签
model = create_model()
model.compile(optimizer='adam', loss='binary_crossentropy')

# 训练时,给input2重复生成和batch匹配的副本
model.fit(
    x=[x_train, np.repeat(fixed_input2[np.newaxis, ...], x_train.shape[0], axis=0)],
    y=y_train,
    epochs=10,
    batch_size=32
)

方案2:把固定向量组作为模型内部的常量

如果不想把它作为外部输入,而是让它成为模型的一部分(不可训练的常量),可以用tf.constant把它转为符号张量,直接嵌入模型:

import tensorflow as tf

def create_model(num_filters=64, embedding_dim=300, seq_len=20):
    # 获取固定向量组并转为符号常量
    fixed_input2_data = get_input2()
    input2 = tf.constant(fixed_input2_data, dtype='float32')
    
    # 输入1:样本特征
    input1 = Input(shape=(seq_len, embedding_dim,), dtype='float32')
    
    # 编码input1的模块
    convs = []
    filter_sizes = [1,2,3]
    for fsz in filter_sizes:
        x = Conv1D(num_filters, fsz, activation='relu', padding='same')(input1)
        x = MaxPooling1D()(x)
        convs.append(x)
    output1 = Concatenate(axis=-1)(convs)
    output1 = Flatten()(output1)
    
    # 编码input2的模块(用常量作为输入)
    convs1 = []
    for fsz in filter_sizes:
        x1 = Conv1D(num_filters, fsz, activation='relu', padding='same')(input2)
        x1 = MaxPooling1D()(x1)
        convs1.append(x1)
    output2 = Concatenate(axis=-1)(convs1)
    output2 = Flatten()(output2)
    
    # 后续逻辑示例
    combined = Concatenate(axis=-1)([output1, output2])
    final_output = Dense(1, activation='sigmoid')(combined)
    
    model = Model(inputs=input1, outputs=final_output)
    return model

这种方式的好处是训练时只需要传input1的数据就行,不用管input2,但它只适合向量组完全固定、训练过程中不会变化的场景。

原代码报错的原因

你原代码里input2=get_input2()拿到的是普通的NumPy数组或非符号张量,而Keras的层(比如Conv1D)要求输入必须是符号张量——也就是由Input层创建,或者其他层输出的张量,这样Keras才能构建可微分的计算图,实现反向传播训练。直接传入普通张量会导致Keras无法追踪计算过程,所以抛出了那个错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:03:12