如何让 keras 层学习 AND 运算

问题描述 投票:0回答:1

为了让 keras 学习从矩形的二值图像中检测角点,我将问题简化为对 3x3 像素数组进行分类。左上角,像素需要看起来像这样。

[ [0, 0, 0],
  [0, 1, 1], 
  [0, 1, 1] ]

这会生成所有可能的输入形状的完整集合。

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)

我应该能够从简单的单个卷积层中找到分类器。

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])

使用这个简单的模型,我可以设置权重并获得我想要的输出。

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)

这会带来以下损失:

16/16 ────────────────────────────── 0s 1ms/步 - 损耗:9.3703e-04

如何训练网络来学习这些权重?

训练网络的基本设置是这样的:

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 的值,考虑到 512 个样本中有 1 个非零,这是合理的。

其他一些观察。

  • 使用正确的权重初始化网络,模型立即收敛到损失 0.0038,但它仍然正确预测。
  • 使用加权损失函数只会改变平均值
  • 通过包含更多正面示例来平衡数据集也会改变平均值。

这是该程序的完整版本。

#!/usr/bin/env python3
import keras
import numpy

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])


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)
            print("found")
        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)
    

mdl = createModel()
x, y = getData()

for ws in mdl.get_weights():
    print(ws.shape)
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)
mdl.fit(x, y, epochs=1000, batch_size=32, verbose=2)
t0 = numpy.array([[[ 0, 0, 0], [0, 1, 1], [0, 1, 1] ]])
t1 = numpy.array([[[ 1, 0, 0], [0, 1, 1], [0, 1, 1] ]])

print( mdl(t0) )
print( mdl(t1) )
python keras
1个回答
0
投票

为了让这个网络学习,我必须稍微改变结构。

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( 2, (1, 1), activation = "softmax")(cnn)
    op = keras.layers.Reshape((2, ))(cnn)
    return keras.models.Model(inputs = [inp], outputs=[op])

现在输出激活使用

softmax
而不是
hard_sigmoid
,重塑层使其能够处理交叉熵损失。

y 数据现在具有两个元素张量而不是单个元素。

y_i = [0, 1] #corner

然后训练

mdl.compile( loss = keras.losses.categorical_crossentropy,
    optimizer=keras.optimizers.Adam(learning_rate=1e-3)
)
mdl.evaluate(x, y)
mdl.fit(x, y, epochs=10000, batch_size=512, verbose=2)

这将学习正确的预测,尽管极端情况仍然存在,但到最后会越来越接近。

通过平衡数据集(添加更多极端情况)可以加快训练速度。

我还没有接受这个答案,因为我怀疑我犯了一个更根本的错误。这个问题看起来很简单,因为网络需要花费多少工作来学习。

© www.soinside.com 2019 - 2024. All rights reserved.