Keras矩阵乘法用于获取预测值

4

我想要通过矩阵乘法手动计算Keras模型的输出结果。我希望这样做可以帮助我更好地理解Keras的工作原理。我将使用简单的XOR问题进行演示。以下是我的代码:

import numpy as np
import keras
from keras.models import Sequential
from keras.layers.core import Dense
from keras.callbacks import LambdaCallback

class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = []

    def on_batch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))


history = LossHistory()

# the four different states of the XOR gate
training_data = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")

# the four expected results in the same order
target_data = np.array([[0],[1],[1],[0]], "float32")

model = Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

print_weights = LambdaCallback(on_epoch_end=lambda batch, logs: print(model.layers[0].get_weights()))

model.compile(loss='mean_squared_error',
              optimizer='adam',
              metrics=['binary_accuracy'])

history2 = model.fit(training_data, target_data, epochs=50, verbose=2, callbacks=[print_weights, history])

print(model.predict(training_data).round())


W1 = model.get_weights()[0]
X1 = np.matrix([[0,0],[1,1]], "float32")
wx = np.dot(X1,W1)
b = model.get_weights()[1]
wx = np.reshape(wx,(4,2))
b = np.reshape(b, (4,1))
z = wx + b
from numpy import array, exp
a1 = 1 / (1 + exp(-z))
print('g =\n', a1)

W2 = model.get_weights()[2]
b2 = model.get_weights()[3]
W2 = np.reshape(W2,(1,4))
a1 = np.reshape(a1, (4,1))
wa = np.dot(W2,a1)
z2 = wa + b2
a2 = 1 / (1 + exp(-z2))
print('g =\n', a2)

据我所了解,get_weights()[0]get_weights()[1]分别是第一层的权重和偏置,get_weights()[2]get_weights()[3]是第二层的权重和偏置。我认为我的问题在于找出x1和x2与方程z = Wx + b的关系。这些权重是从最后一个时期中检索出来的,通常是实现100%准确度的权重。我期望的输出是[0,1,1,0],基于手动计算z = Wx + b并对z取sigmoid得到y-hat预测值。
1个回答

4

你很接近成功了!

首先,仅使用包含4个事件的训练集进行50个时期的训练不足以复制一致正确的输出(0,1,1,0),因此我将时期数增加到了1000。以下是我使用的代码及其十进制和四舍五入输出结果:

import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense

# Set seed for reproducibility
np.random.seed(1)

# the four different states of the XOR gate
training_data = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
# the four expected results in the same order
target_data = np.array([[0],[1],[1],[0]], "float32")

model = Sequential()
model.add(Dense(4, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='mean_squared_error',optimizer='adam',metrics=['binary_accuracy'])

history = model.fit(training_data, target_data, epochs=1000, verbose=1)

# decimal output
print('decimal output:\n'+str(model.predict(training_data)))
# rounded output
print('rounded output:\n'+str(model.predict(training_data).round()))
# ouputs:
decimal output:
[[ 0.25588933]
 [ 0.82657152]
 [ 0.83840138]
 [ 0.16465074]]
rounded output:
[[ 0.]
 [ 1.]
 [ 1.]
 [ 0.]]

这个模型输出的四舍五入结果是正确的,很好!小数输出方便我们用于比较手动计算方法。

对于手动计算方法,X1是输入给模型的,可以是[0,0]、[0,1]、[1,0]或[1,1]。X2是第一层的输出,也是最后一层的输入。权重和偏差与你所说的完全相同("get_weights()[0]"和"get_weights()[1]"分别是第一层的权重和偏差,"get_weights()[2]"和"get_weights()[3]"分别是第二层的权重和偏差)。但是,你可能忘记了在第一层中使用了ReLU激活函数?让我们看看解决方案代码:

# Parameters layer 1
W1 = model.get_weights()[0]
b1 = model.get_weights()[1]

# Parameters layer 2
W2 = model.get_weights()[2]
b2 = model.get_weights()[3]

# Input
X1 = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
# Use the following X1 for single input instead of all at once
#X1 = np.array([[0,0]])

# First layer calculation
L1 = np.dot(X1,W1)+b1
# Relu activation function
X2 = np.maximum(L1,0)
# Second layer calculation
L2 = np.dot(X2,W2)+b2
# Sigmoid
output = 1/(1+np.exp(-L2))

# decimal output
print('decimal output:\n'+str(output))
# rounded output
print('rounded output:\n'+str(output.round()))
# ouputs:
decimal output:
[[ 0.25588933]
 [ 0.82657152]
 [ 0.83840144]
 [ 0.16465074]]
rounded output:
[[ 0.]
 [ 1.]
 [ 1.]
 [ 0.]]

您可以像上面那样同时使用4个输入,或者只使用单个输入,如被注释的#X1所示。请注意,十进制“model.predict”输出和手动方法给出完全相同的输出(第三个值可能由于某些keras / numpy舍入偏差而略有偏差)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接