我想实现内置的TensorFlow插件版本的三元组损失,并参考此教程来应用于孪生网络,但似乎始终无法正确实现。每当我调整代码时,总会出现新的错误,目前的错误是
TypeError: Could not build a TypeSpec for <KerasTensor: shape=(3, None, 256) dtype=float32 (created by layer 'tf.math.l2_normalize_4')> with type KerasTensor.
请注意,这只是一个简化的示例实现,目的是为了理解如何实现三元组损失。我并不期望模型实际能学到什么。
代码如下:
!pip install -U tensorflow-addons
import ioimport numpy as npimport tensorflow as tfimport tensorflow_addons as tfafrom tensorflow.keras.datasets import fashion_mnist# 传递给模型的虚拟数据(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()train_data = [x_train[:20000],x_train[20000:40000],x_train[40000:]]train_labels = [y_train[:20000],y_train[20000:40000],y_train[40000:]] train_data = tf.convert_to_tensor(train_data)train_labels = tf.convert_to_tensor(train_labels)#train_data = np.asarray(train_data)#train_labels = np.asarray(train_labels)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', input_shape=(28,28,1))(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) # 最后的全连接层不使用激活函数 #x = tf.keras.layers.Lambda(lambda y: tf.math.l2_normalize(x, axis=1))(x) model = tf.keras.Model(inp,x) return modeldef 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] outputs = [encoded_anchor, encoded_positive, encoded_negative] #x = tf.keras.layers.Lambda(lambda x: tf.math.l2_normalize(outputs, axis=1))(outputs) # 将输入与输出连接 siamese_triplet = tf.keras.Model(inputs=inputs,outputs=outputs) # 返回模型 return embedding_model, siamese_tripletemb_mod, model = get_siamese_model([28,28,1])# 编译模型model.compile( optimizer=tf.keras.optimizers.Adam(0.001), loss=tfa.losses.TripletSemiHardLoss())# 训练网络#train_dataset = tf.convert_to_tensor(train_dataset)history = model.fit( train_data, epochs=5)
回答:
我不确定你到底想做什么,但使用tfa.losses.TripletSemiHardLoss()
时,你还需要将标签纳入你的训练数据集。这里是一个工作示例:
import ioimport numpy as npimport tensorflow as tfimport tensorflow_addons as tfafrom tensorflow.keras.datasets import fashion_mnist# 传递给模型的虚拟数据(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()train_data = tf.data.Dataset.zip((tf.data.Dataset.from_tensor_slices(x_train[:20000]), tf.data.Dataset.from_tensor_slices(x_train[20000:40000]), tf.data.Dataset.from_tensor_slices(x_train[40000:])))train_labels = tf.data.Dataset.zip((tf.data.Dataset.from_tensor_slices(y_train[:20000]), tf.data.Dataset.from_tensor_slices(y_train[20000:40000]), tf.data.Dataset.from_tensor_slices(y_train[40000:])))dataset = tf.data.Dataset.zip((train_data, train_labels)).batch(32) 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', input_shape=(28,28,1))(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) # 最后的全连接层不使用激活函数 #x = tf.keras.layers.Lambda(lambda y: tf.math.l2_normalize(x, axis=1))(x) model = tf.keras.Model(inp,x) return modeldef 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] outputs = [encoded_anchor, encoded_positive, encoded_negative] #x = tf.keras.layers.Lambda(lambda x: tf.math.l2_normalize(outputs, axis=1))(outputs) # 将输入与输出连接 siamese_triplet = tf.keras.Model(inputs=inputs,outputs=outputs) # 返回模型 return embedding_model, siamese_tripletemb_mod, model = get_siamese_model([28,28,1])# 编译模型model.compile( optimizer=tf.keras.optimizers.Adam(0.001), loss=tfa.losses.TripletSemiHardLoss())# 训练网络history = model.fit( dataset, epochs=1)