神经网络(感知器)——在执行二元分类时可视化决策边界(作为超平面)

Neural network (perceptron) - visualizing decision boundary (as a hyperplane) when performing binary classification

我想可视化只有一个神经元(3 个输入,二进制输出)的简单神经网络的决策边界。我正在从 Keras NN 模型中提取权重,然后尝试使用 matplotlib 绘制表面平面。不幸的是,超平面没有出现在散点图上的点之间,而是显示在所有数据点的下方(参见输出图像)。

我正在使用等式计算超平面的 z 轴 z = (d - ax - by) / c 对于定义为 ax + by + cz = d

的超平面

有人可以帮助我正确构建和显示基于 NN 权重的超平面吗?

此处的目标是根据使用 public 数据集 (https://www.kaggle.com/uciml/pima-indians-diabetes-database) 的 3 个预测变量将个体分为两组(糖尿病或非糖尿病)。

%matplotlib notebook

import pandas as pd
import numpy as np
from keras import models
from keras import layers
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

EPOCHS = 2

#Data source: https://www.kaggle.com/uciml/pima-indians-diabetes-database
ds = pd.read_csv('diabetes.csv', sep=',', header=0)

#subset and split
X = ds[['BMI', 'DiabetesPedigreeFunction', 'Glucose']]
Y = ds[['Outcome']]

#construct perceptron with 3 inputs and a single output
model = models.Sequential()
layer1 = layers.Dense(1, activation='sigmoid', input_shape=(3,))
model.add(layer1)

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

#train perceptron
history = model.fit(x=X, y=Y, epochs=EPOCHS)

#display accuracy and loss
epochs = range(len(history.epoch))

plt.figure()
plt.plot(epochs, history.history['accuracy'])
plt.xlabel('Epochs')
plt.ylabel('Accuracy')

plt.figure()
plt.plot(epochs, history.history['loss'])
plt.xlabel('Epochs')
plt.ylabel('Loss')

plt.show()

#extract weights and bias from model
weights = model.layers[0].get_weights()[0]
biases = model.layers[0].get_weights()[1]

w1 = weights[0][0] #a
w2 = weights[1][0] #b
w3 = weights[2][0] #c
b = biases[0]      #d

#construct hyperplane: ax + by + cz = d
a,b,c,d = w1,w2,w3,b

x_min = ds.BMI.min()
x_max = ds.BMI.max()

x = np.linspace(x_min, x_max, 100)

y_min = ds.DiabetesPedigreeFunction.min()
y_max = ds.DiabetesPedigreeFunction.max()

y = np.linspace(y_min, y_max, 100)

Xs,Ys = np.meshgrid(x,y)
Zs = (d - a*Xs - b*Ys) / c

#visualize 3d scatterplot with hyperplane
fig = plt.figure(num=None, figsize=(9, 9), dpi=100, facecolor='w', edgecolor='k')
ax = fig.gca(projection='3d')

ax.plot_surface(Xs, Ys, Zs, alpha=0.45)

ax.scatter(ds.BMI, ds.DiabetesPedigreeFunction, ds.Glucose, c=ds.Outcome)

ax.set_xlabel('BMI')
ax.set_ylabel('DiabetesPedigreeFunction')
ax.set_zlabel('Glucose')

最佳猜测,无需详细阅读所有代码。看起来您应用了 sigmoid 激活。如果你在没有激活的情况下训练 (activation='linear'),你应该得到你正在寻找的可视化。您可能需要训练更长时间才能收敛(假设它可以在没有激活的情况下收敛)。如果你想保留 sigmoid,那么你需要通过这个激活来映射你的线性神经元(因此它看起来不再像一个平面)。

编辑:

我对神经网络的理解。从 3 到 1 的密集层和 sigmoid 激活是尝试优化等式中的变量 a、b、c、d:

f(x,y,z) = 1/(1+e^(-D(x,y,z)); D(x,y,z) = ax+by+cz+d

以便 binary_crossentropy(您选择的)最小化,我将使用 B 作为日志的总和。我们的损失方程看起来像:

L = ∑ B(y,Y)

其中 y 是我们要预测的值,在本例中为 0 或 1,Y 是上述等式输出的值,总和加在所有数据(或 NN 中的批次)上。因此,这可以写成

L = ∑ B(y,f(x,y,z))

找到 L 个给定变量 a、b、c、d 的最小值可能可以直接通过取偏导数并求解给定的方程组来计算(这就是为什么 NN 不应该与一小组变量一起使用的原因(像 4),因为它们可以被明确地解决,所以训练没有意义)。不管是直接求解还是使用随机梯度下降慢慢将a,b,c,d向最小值移动;在任何情况下,我们最终都会得到优化的 a、b、c、d。

a、b、c、d 已被调整为专门生成值,当将其插入 sigmoid 方程时会产生预测类别,当在损失方程中测试时会给我们带来最小损失。

不过我的观点是正确的。在这种情况下,因为我们有一个特别的 sigmoid,然后设置和求解边界方程,似乎总是产生一个平面(不知道)。我认为这不适用于任何其他激活或任何具有不止一层的神经网络。

1/2 = 1/(1 + e^(-D(x,y,z))) ... D(x,y,z) = 0 ax+by+cz+d = 0

所以,我下载了您的数据和 运行 您的代码。我根本没有收敛;我尝试了各种batch_sizes、损失函数和激活函数。没有什么。根据图片,几乎每个 运行domized 权重都倾向于远离集群,而不是试图找到它的中心,这似乎是合理的。

您可能需要先对数据进行 t运行sform(在所有轴上归一化可能会成功),或者手动将权重设置到中心的某处,以便训练收敛。长话短说,您的 a、b、c、d 不是最优的。您还可以显式求解上述偏导数并找到最优的 a、b、c、d,而不是试图让单个神经元收敛。还有用于计算分离二进制数据的最佳平面的显式方程(线性回归的扩展)。

您网络的决策边界不是 ax + by + cz = d,而是 ax + by + cz + d = 0

您的网络是逻辑回归模型,因此表面方程肯定是 z = (-b-w1x -w2y) / w3 。您的模型需要更多训练。尝试增加 epoch 的数量(尝试大约 500):

由于您的数据不是线性可分的,因此您需要将隐藏层添加到您的网络中,以便学习输入的转换,使其可线性分离。绘制决策边界并不那么简单...