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

如何训练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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:45:56