如何训练Keras网络学习识别特定3x3像素角点的目标权重
如何训练Keras网络学习特定角点检测权重?
问题背景
为实现Keras从矩形二值图中检测角点,将问题简化为3x3像素数组的分类任务,目标检测的左上角角点像素模板为:
[ [0, 0, 0], [0, 1, 1], [0, 1, 1] ]
数据集生成
以下代码生成所有可能的3x3二值样本(共512个),仅匹配模板的样本标记为正样本(y=1),其余为负样本(y=0):
def getData(): x = [] y = [] template = numpy.array([[ 0, 0, 0], [0, 1, 1], [0, 1, 1] ]) num = [0, 0, 0, 0, 0, 0, 0, 0, 0] for i in range(2**9): n = numpy.array( num ).reshape((3, 3)) x.append( n ) if numpy.all( n == template ): y.append(1) else: y.append(0) s = 0 j = 0 while s == 0: if num[j] == 0: num[j] = 1 s = 1 else: num[j] = 0 j += 1 if j == len(num): print(num) break return numpy.array(x), numpy.array(y)
模型结构
构建了包含两层Conv2D的简单分类模型:
def createModel(): inp = keras.layers.Input((3, 3, 1)) cnn = keras.layers.Conv2D( 1, (3, 3), activation = None, use_bias=True)(inp) cnn = keras.layers.Conv2D( 1, (1, 1), activation = "hard_sigmoid")(cnn) return keras.models.Model(inputs = [inp], outputs=[cnn])
手动权重验证
手动设置权重后,模型能达到极低损失(9.3703e-04)并正确预测目标样本:
dw = numpy.array([ -100, -100, -100, -100, 10, 10, -100, 10, 10]).reshape((3, 3, 1, 1)) bw = numpy.array([ -35 ]) ow = numpy.array([ 1 ]).reshape((1, 1, 1, 1)) obw = numpy.array([0]) mdl.set_weights( [dw, bw, ow, obw] ) mdl.compile( loss ="mse", optimizer=keras.optimizers.Adam(learning_rate=1e-7) ) mdl.evaluate(x, y)
训练困境
常规训练流程下,模型始终收敛到全0输出,原因是样本极端不平衡(512个样本中仅1个正样本):
mdl = createModel() x, y = getData() mdl.compile( loss ="mse", optimizer=keras.optimizers.Adam(learning_rate=1e-2) ) mdl.fit(x, y, epochs=100, verbose=2)
已尝试但效果不佳的方法
- 用正确权重初始化模型,损失收敛到0.0038但未完全学到目标权重;
- 使用加权损失仅改变输出均值,未解决分类准确性问题;
- 增加正样本平衡数据集,仅改变输出均值,模型仍无法正确区分目标样本。
解决方案建议
1. 更换损失函数并设置类别权重
MSE不适合极端不平衡的分类任务,改用二元交叉熵(Binary Crossentropy),同时为正样本设置高权重,让模型重视正样本的错误:
def createModel(): inp = keras.layers.Input((3, 3, 1)) cnn = keras.layers.Conv2D(1, (3, 3), activation=None, use_bias=True)(inp) # 替换hard_sigmoid为sigmoid,获得更平滑的梯度 cnn = keras.layers.Conv2D(1, (1, 1), activation="sigmoid")(cnn) return keras.models.Model(inputs=[inp], outputs=[cnn]) mdl = createModel() x, y = getData() # 编译时使用二元交叉熵 mdl.compile(loss="binary_crossentropy", optimizer=keras.optimizers.Adam(learning_rate=1e-4), metrics=["accuracy"]) # 正样本权重设为511,平衡正负样本的损失贡献 class_weight = {0: 1, 1: 511} mdl.fit(x, y, epochs=500, batch_size=32, verbose=2, class_weight=class_weight)
2. 初始化权重接近目标值
从接近手动设置的权重开始训练,避免模型陷入全0的局部最优:
# 初始化权重为目标值的缩小版,减少训练难度 initial_dw = numpy.array([-10, -10, -10, -10, 1, 1, -10, 1, 1]).reshape((3,3,1,1)) initial_bw = numpy.array([-3.5]) initial_ow = numpy.array([1]).reshape((1,1,1,1)) initial_obw = numpy.array([0]) mdl.set_weights([initial_dw, initial_bw, initial_ow, initial_obw])
3. 简化模型结构(可选)
1x1卷积在这里仅做线性缩放,可合并到3x3卷积中,简化模型:
def createModel(): inp = keras.layers.Input((3, 3, 1)) # 直接在3x3卷积后接sigmoid,去掉冗余的1x1卷积 cnn = keras.layers.Conv2D(1, (3, 3), activation="sigmoid", use_bias=True)(inp) return keras.models.Model(inputs=[inp], outputs=[cnn])
4. 调整训练策略
- 降低初始学习率(如1e-4),避免权重震荡;
- 增加训练轮次(如500-1000轮),让模型有足够时间收敛到目标权重;
- 使用小批量训练(如batch_size=8或16),让优化器更频繁地更新权重。
内容的提问来源于stack exchange,提问作者matt
相关产品推荐
相关产品推荐

