添加训练数据后Siamese Network精度停滞的原因排查
Siamese网络大数据量下精度停滞问题分析与解决
问题背景
我是机器学习新手,正在构建用于预测品牌logo相似性的Siamese网络,数据集包含约210000个品牌logo。
特征提取CNN结构
def build_cnn(inputShape, embeddingDim=48): # specify the inputs for the feature extractor network inputs = Input(shape=inputShape) # define the first set of CONV => RELU => POOL => DROPOUT layers x = Conv2D(64, (2, 2), padding="same", activation="relu")(inputs) x = MaxPooling2D(pool_size=(5, 5))(x) x = Dropout(0.3)(x) # second set of CONV => RELU => POOL => DROPOUT layers x = Conv2D(64, (2, 2), padding="same", activation="relu")(x) x = MaxPooling2D(pool_size=2)(x) x = Dropout(0.3)(x) pooledOutput = GlobalAveragePooling2D()(x) outputs = Dense(embeddingDim)(pooledOutput) # build the model model = Model(inputs, outputs) model.summary() plot_model(model, to_file=os.path.sep.join([config.BASE_OUTPUT,'model_cnn.png'])) # return the model to the calling function return model
Siamese网络结构
imgA = Input(shape=config.IMG_SHAPE) imgB = Input(shape=config.IMG_SHAPE) featureExtractor = siamese_network.build_cnn(config.IMG_SHAPE) featsA = featureExtractor(imgA) featsB = featureExtractor(imgB) distance = Lambda(euclidean_distance)([featsA, featsB]) outputs = Dense(1, activation="sigmoid")(distance) model = Model(inputs=[imgA, imgB], outputs=outputs)
训练情况
首次使用800组正样本对+800组负样本对时,模型精度和损失呈现明显学习趋势;但增加训练数据至2000组正负样本对后,精度持续停滞,即使训练20+epoch也无提升。后续尝试更换SELU、LeakyReLU激活函数,以及用10000组样本对训练,问题仍存在。训练代码:
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"]) print("[INFO] training model...") history = model.fit( [pairTrain[:, 0], pairTrain[:, 1]], labelTrain[:], validation_data=([pairTest[:, 0], pairTest[:, 1]], labelTest[:]), batch_size=10, shuffle=True, epochs=50)
可能原因
- 特征提取器能力不足:当前CNN仅包含2层卷积,结构过浅,无法捕捉logo图像中复杂的纹理、字体、形状等特征。小数据量时模型能勉强拟合有限样本的特征,但数据量增大后,样本多样性提升,简单CNN无法提取足够区分度的特征,导致精度停滞。
- 损失函数与任务不匹配:
binary_crossentropy更偏向分类任务逻辑,而Siamese网络核心是学习相似性度量,该损失无法直接优化样本对之间的距离关系,大数据量下难以有效引导模型学习。 - 样本对质量或分布问题:大数据量下可能存在正负样本对质量下降,比如正样本对包含差异较大的同品牌logo,负样本对包含过于相似的不同品牌logo,导致模型无法找到稳定的相似性规律;或者正负样本难度分布失衡,模型在小数据时能轻松区分简单样本,但大数据中混入难样本后,现有模型能力不足以学习。
- 优化器参数不合理:Adam默认学习率(0.001)在大数据量下可能偏大,导致模型参数更新震荡,无法收敛到最优解;小数据量时样本少,参数更新次数少,震荡不明显,能呈现学习趋势,但大数据下震荡加剧,精度停滞。
- 嵌入维度不足:
embeddingDim=48过小,特征空间表达能力有限,小数据时能容纳有限样本特征,但大数据量下无法区分更多不同logo的特征,导致模型无法进一步提升精度。 - 正则化与数据增强不足:仅使用Dropout正则化,在大数据量下可能不足以防止过拟合;同时缺乏图像数据增强,样本多样性不足,模型泛化能力差,无法适应更多样本。
解决方案
- 增强特征提取能力:
- 增加卷积层数,比如在现有结构后添加1-2层
Conv2D+MaxPooling2D模块,提升特征提取深度; - 采用预训练模型(如MobileNet、VGG16)作为特征提取器,通过迁移学习复用通用图像特征,大幅提升对logo特征的捕捉能力。
- 增加卷积层数,比如在现有结构后添加1-2层
- 更换适配的损失函数:
使用**对比损失(Contrastive Loss)**替代二元交叉熵,直接优化样本对的距离:
编译模型时指定该损失:def contrastive_loss(y_true, y_pred): margin = 1 square_pred = K.square(y_pred) margin_square = K.square(K.maximum(margin - y_pred, 0)) return K.mean(y_true * square_pred + (1 - y_true) * margin_square)model.compile(loss=contrastive_loss, optimizer="adam", metrics=["accuracy"]) - 优化样本对构建:
- 严格筛选正样本对:确保正样本对为同一品牌的不同变体(如不同尺寸、颜色、排版的logo);
- 构造难度适中的负样本对:加入部分视觉相似的不同品牌logo作为负样本,避免模型仅学习简单特征;
- 保持正负样本1:1的平衡比例,避免模型偏向某一类。
- 调整优化器参数:
- 降低Adam学习率,比如设置
optimizer=Adam(learning_rate=0.0001); - 添加学习率调度器,如
ReduceLROnPlateau,当验证损失停滞时自动降低学习率:from tensorflow.keras.callbacks import ReduceLROnPlateau lr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6) # 在fit中加入callbacks参数 history = model.fit(..., callbacks=[lr_scheduler])
- 降低Adam学习率,比如设置
- 增大嵌入维度:
将embeddingDim调整为128或256,给特征提供更充足的表达空间,提升模型区分不同logo的能力。 - 增强正则化与数据增强:
- 在卷积层和全连接层添加L2正则化,比如
Conv2D(64, (2,2), ..., kernel_regularizer=l2(1e-4)); - 添加图像数据增强,比如随机裁剪、翻转、亮度调整等:
from tensorflow.keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator( rotation_range=10, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True, brightness_range=[0.9, 1.1] ) # 训练时应用数据增强(需适配Siamese网络的输入格式)
- 在卷积层和全连接层添加L2正则化,比如
内容的提问来源于stack exchange,提问作者David Walser
相关产品推荐
相关产品推荐

