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

实现TensorFlow Triplet Loss时出现KerasTensor类型错误如何解决?

报错核心原因及修复方案

错误触发的三个关键问题

  • 数据格式不符合要求:你将三元组输入拼接为维度(3, N, 28, 28)的整体张量,但Keras多输入模型要求输入为列表格式,每个元素对应一个输入分支的样本张量,且FashionMNIST原始数据缺少灰度图所需的通道维度
  • TripletSemiHardLoss要求传入标签计算正负样本对,且要求输入的嵌入向量必须做L2归一化,你注释了归一化逻辑且原有代码写法存在错误
  • 训练时没有传入标签参数,损失函数无法计算半困难三元组

修复后可运行代码

!pip install -U tensorflow-addons
import io
import numpy as np
import tensorflow as tf
import tensorflow_addons as tfa
from tensorflow.keras.datasets import fashion_mnist

# 加载并预处理数据:增加通道维度,归一化到0-1
(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()
x_train = x_train.astype("float32") / 255.0
x_train = np.expand_dims(x_train, axis=-1) # 增加通道维度,变成(60000,28,28,1)

# 拆分三元组输入,保持列表格式,不要转成整体张量
anchor_data = x_train[:20000]
positive_data = x_train[20000:40000]
negative_data = x_train[40000:]
train_labels = y_train[:20000] # 取anchor对应的标签即可,损失函数只需要anchor的标签计算匹配关系

def create_model(input_shape):
  inp = tf.keras.layers.Input(shape=input_shape)
  x = tf.keras.layers.Conv2D(filters=64, kernel_size=2, padding='same', activation='relu')(inp)
  x = tf.keras.layers.MaxPooling2D(pool_size=2)(x)
  x = tf.keras.layers.Dropout(0.3)(x)
  x = tf.keras.layers.Conv2D(filters=32, kernel_size=2, padding='same', activation='relu')(x)
  x = tf.keras.layers.MaxPooling2D(pool_size=2)(x)
  x = tf.keras.layers.Dropout(0.3)(x)
  x = tf.keras.layers.Flatten()(x)
  x = tf.keras.layers.Dense(256, 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

def get_siamese_model(input_shape):
    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")
    
    embedding_model = create_model(input_shape)
    
    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]
    # 适配tfa内置损失的输入要求,仅返回anchor的嵌入向量即可完成损失计算
    outputs = encoded_anchor
    siamese_triplet = tf.keras.Model(inputs=inputs,outputs=outputs)
    
    return embedding_model, siamese_triplet

emb_mod, model = get_siamese_model([28,28,1])

# 编译模型
model.compile(
    optimizer=tf.keras.optimizers.Adam(0.001),
    loss=tfa.losses.TripletSemiHardLoss())

# 训练网络,输入为三元组列表,y对应anchor的标签
history = model.fit(
    [anchor_data, positive_data, negative_data],
    y = train_labels,
    batch_size=32,
    epochs=5)

关键修改说明

  • 给输入数据增加了通道维度,并且做了0-1归一化,符合卷积层输入要求
  • 修复了L2归一化的实现逻辑,将归一化层放在嵌入模型的输出端
  • 调整了孪生网络的输出,仅返回anchor的嵌入向量,适配tfa内置TripletSemiHardLoss的输入要求
  • 训练时传入了anchor对应的标签,满足损失函数的计算条件
  • 不再将三个输入拼接为整体张量,保持列表格式匹配模型的多输入要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:15:04