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

使用TripletSemiHardLoss遇形状不匹配错误的技术求助

问题:TripletSemiHardLoss训练时的形状不匹配错误

我正在实现一个用TripletSemiHardLoss做相似度排序的场景,训练数据是带分类标签的分类变量,已完成数据导入、独热编码、锚点/正例/负例划分、模型构建和训练代码编写,但运行时出现形状不匹配错误,排查后确定是层形状问题,但找不到明确修改方向。输入独热编码后形状为[287,],标签形状为[52,]。


训练代码

def learn_ranking_loss(settings):
    training_data, label_columns, label_dict, features_dict, losses, loss_weights = data_handling.training_data_labeling(
        ['Diagnosis'], settings["CONFIGURATION_FILE_PATH"], binary_features=settings["BINARY_FEATURES"],
        ignore=['Runtime', 'Consistency check'])
    train_x, test_x, train_labels, test_labels, input_neuron_list, output_neuron_list = data_preprocessing.data_preprocessing_learning(
        training_data, label_columns)

    training_data = tf.data.Dataset.zip(
        (tf.data.Dataset.from_tensor_slices(train_x[:(round(len(train_x) / 3))]),
         tf.data.Dataset.from_tensor_slices(
             train_x[(round(len(train_x) / 3)):(round(len(train_x) / 3) * 2)]),
         tf.data.Dataset.from_tensor_slices(
             train_x[(round(len(train_x) / 3) * 2):])))
    train_labels = tf.data.Dataset.zip(
        (tf.data.Dataset.from_tensor_slices(train_labels[0][:(round(len(train_labels[0]) / 3))]),
         tf.data.Dataset.from_tensor_slices(
             train_labels[0][(round(len(train_labels[0]) / 3)):(round(len(train_labels[0]) / 3) * 2)]),
         tf.data.Dataset.from_tensor_slices(
             train_labels[0][(round(len(train_labels[0]) / 3) * 2):])))

    dataset = tf.data.Dataset.zip((training_data, train_labels)).batch(32)

    emb_mod, model = get_siamese_model([287, ])

    # Compile the model
    model.compile(
        optimizer=tf.keras.optimizers.Adam(0.001),
        loss=tfa.losses.TripletSemiHardLoss())

    # Train the network
    history = model.fit(
        dataset,
        epochs=1)
    return

模型构建代码

def create_model(input_shape):
    inp = tf.keras.layers.Input(shape=input_shape)
    x = tf.keras.layers.Dense(287, activation='relu')(inp)
    x = tf.keras.layers.Dense(287, activation='relu')(x)
    x = tf.keras.layers.Dense(52, activation=None)(x)
    # x = tf.keras.layers.Lambda(lambda y: tf.math.l2_normalize(x, axis=1))(x)
    model = tf.keras.Model(inp, x)
    return model


def get_siamese_model(input_shape):

    # Define the tensors for the triplet of input images
    anchor_input = tf.keras.layers.Input(input_shape, name="anchor_input")
    positive_input = tf.keras.layers.Input(input_shape, name="positive_input")
    negative_input = tf.keras.layers.Input(input_shape, name="negative_input")

    # Convolutional Neural Network (same from earlier)
    embedding_model = create_model(input_shape)

    # Generate the embedding outputs
    encoded_anchor = embedding_model(anchor_input)
    encoded_positive = embedding_model(positive_input)
    encoded_negative = embedding_model(negative_input)

    inputs = [anchor_input, positive_input, negative_input]
    outputs = [encoded_anchor, encoded_positive, encoded_negative]
    # x = tf.keras.layers.Lambda(lambda x: tf.math.l2_normalize(outputs, axis=1))(outputs)

    # Connect the inputs with the outputs
    siamese_triplet = tf.keras.Model(inputs=inputs, outputs=outputs)

    # return the model
    return embedding_model, siamese_triplet

错误日志

Traceback (most recent call last):
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\ranking_loss.py", line 94, in <module>
    learn_ranking_loss(settings_dict)
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\ranking_loss.py", line 74, in learn_ranking_loss
    history = model.fit(
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\keras\engine\training.py", line 1189, in fit
    tmp_logs = self.train_function(iterator)
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\def_function.py", line 885, in __call__
    result = self._call(*args, **kwds)
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\def_function.py", line 950, in _call
    return self._stateless_fn(*args, **kwds)
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\function.py", line 3039, in __call__
    return graph_function._call_flat(
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\function.py", line 1963, in _call_flat
    return self._build_call_outputs(self._inference_function.call(
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\function.py", line 591, in call
    outputs = execute.execute(
  File "C:\Users\mathi\Documents\Studium\Promotion\ConLearn\Python interpreter\lib\site-packages\tensorflow\python\eager\execute.py", line 59, in quick_execute
    tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
tensorflow.python.framework.errors_impl.InvalidArgumentError:  Input to reshape is a tensor with 1664 values, but the requested shape has 32
     [[{{node TripletSemiHardLoss/PartitionedCall/Reshape}}]] [Op:__inference_train_function_1666]

Function call stack:
train_function


Process finished with exit code 1

问题根源与修正方案

核心问题

TripletSemiHardLoss的输入逻辑和你当前的实现完全不匹配:

  1. 该Loss不需要手动划分锚点/正例/负例,它会在每个batch内自动根据标签挖掘难负例,输入只需要**(所有样本的embedding, 所有样本的单值标签)**;
  2. 你手动构造了三元组输入和三元组标签,导致模型输出的embedding张量与Loss期望的输入形状冲突,同时独热编码的标签也不符合Loss要求的单值格式。

具体修正步骤

  1. 重构数据集
    取消手动划分三元组,直接将所有训练数据和转成单值的标签打包成数据集:

    # 替换原数据集构造代码
    # 将独热编码标签转为单整数标签(形状从(batch_size,52)变为(batch_size,))
    train_single_labels = tf.argmax(train_labels[0], axis=1)
    train_dataset = tf.data.Dataset.from_tensor_slices((train_x, train_single_labels)).batch(32)
    
  2. 简化模型结构
    不需要三元输入的Siamese模型,直接使用单个输入的embedding模型:

    # 替换原模型初始化代码
    model = create_model([287,])
    
  3. 调整编译与训练逻辑
    直接用新的数据集训练即可:

    model.compile(optimizer=tf.keras.optimizers.Adam(0.001), loss=tfa.losses.TripletSemiHardLoss())
    history = model.fit(train_dataset, epochs=1)
    
  4. 可选:添加L2归一化
    Triplet Loss通常需要对embedding做L2归一化,打开你注释掉的Lambda层:

    def create_model(input_shape):
        inp = tf.keras.layers.Input(shape=input_shape)
        x = tf.keras.layers.Dense(287, activation='relu')(inp)
        x = tf.keras.layers.Dense(287, activation='relu')(x)
        x = tf.keras.layers.Dense(52, activation=None)(x)
        # 打开L2归一化层
        x = tf.keras.layers.Lambda(lambda y: tf.math.l2_normalize(y, axis=1))(x)
        model = tf.keras.Model(inp, x)
        return model
    

错误原因解释

你之前的代码中,模型输出三个embedding张量(每个形状(32,52)),同时标签是三元组的独热编码(每个形状(32,52))。TripletSemiHardLoss尝试将标签reshape为(32,)的单值格式时,发现标签张量总元素数为32*52=1664,与目标形状32不匹配,因此抛出错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:52:02