使用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的输入逻辑和你当前的实现完全不匹配:
- 该Loss不需要手动划分锚点/正例/负例,它会在每个batch内自动根据标签挖掘难负例,输入只需要**(所有样本的embedding, 所有样本的单值标签)**;
- 你手动构造了三元组输入和三元组标签,导致模型输出的embedding张量与Loss期望的输入形状冲突,同时独热编码的标签也不符合Loss要求的单值格式。
具体修正步骤
重构数据集
取消手动划分三元组,直接将所有训练数据和转成单值的标签打包成数据集:# 替换原数据集构造代码 # 将独热编码标签转为单整数标签(形状从(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)简化模型结构
不需要三元输入的Siamese模型,直接使用单个输入的embedding模型:# 替换原模型初始化代码 model = create_model([287,])调整编译与训练逻辑
直接用新的数据集训练即可:model.compile(optimizer=tf.keras.optimizers.Adam(0.001), loss=tfa.losses.TripletSemiHardLoss()) history = model.fit(train_dataset, epochs=1)可选:添加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
相关产品推荐
相关产品推荐

