【问题标题】:Basic binary classification with Keras not workingKeras 的基本二进制分类不起作用
【发布时间】:2019-05-18 19:13:12
【问题描述】:

我是 ML 的新手,想用 Keras 执行最简单的分类:如果 y > 0.5,则 label = 1(x 无所谓),y

据我了解,1 个具有 sigmoid 激活的神经元可以执行这种线性分类。

import tensorflow.keras as keras
import math

import numpy as np
import matplotlib as mpl

train_data = np.empty((0,2),float)
train_labels = np.empty((0,1),float)


train_data = np.append(train_data, [[0, 0]], axis=0)
train_labels = np.append(train_labels, 0)

train_data = np.append(train_data, [[1, 0]], axis=0)
train_labels = np.append(train_labels, 0)

train_data = np.append(train_data, [[0, 1]], axis=0)
train_labels = np.append(train_labels, 1)

train_data = np.append(train_data, [[1, 1]], axis=0)
train_labels = np.append(train_labels, 1)


model = keras.models.Sequential()
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.Dense(1, input_dim = 2, activation='sigmoid'))

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

model.fit(train_data, train_labels, epochs=20)

培训:

Epoch 1/5
4/4 [==============================] - 1s 150ms/step - loss: 0.4885 - acc: 0.7500
Epoch 2/5
4/4 [==============================] - 0s 922us/step - loss: 0.4880 - acc: 0.7500
Epoch 3/5
4/4 [==============================] - 0s 435us/step - loss: 0.4875 - acc: 0.7500
Epoch 4/5
4/4 [==============================] - 0s 396us/step - loss: 0.4869 - acc: 0.7500
Epoch 5/5
4/4 [==============================] - 0s 465us/step - loss: 0.4863 - acc: 0.7500

而且预测不好:

predict_data = np.empty((0,2),float)
predict_data = np.append(predict_data, [[0, 0]], axis=0)
predict_data = np.append(predict_data, [[1, 0]], axis=0)
predict_data = np.append(predict_data, [[1, 1]], axis=0)
predict_data = np.append(predict_data, [[1, 1]], axis=0)

predict_labels = model.predict(predict_data)
print(predict_labels)

[[0.49750862]
 [0.51616406]
 [0.774486  ]
 [0.774486  ]]

如何解决这个问题?

毕竟,我尝试在 2000 点上训练模型(在我看来,对于这个简单的问题来说已经绰绰有余了),但没有成功......

train_data = np.empty((0,2),float)
train_labels = np.empty((0,1),float)

for i in range(0, 1000):
  train_data = np.append(train_data, [[i, 0]], axis=0)
  train_labels = np.append(train_labels, 0)
  train_data = np.append(train_data, [[i, 1]], axis=0)
  train_labels = np.append(train_labels, 1)

model = keras.models.Sequential()
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.Dense(1, input_dim = 2, activation='sigmoid'))

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

model.fit(train_data, train_labels, epochs=5)

Epoch 1/5
2000/2000 [==============================] - 1s 505us/step - loss: 7.9669 - acc: 0.5005
Epoch 2/5
2000/2000 [==============================] - 0s 44us/step - loss: 7.9598 - acc: 0.5010
Epoch 3/5
2000/2000 [==============================] - 0s 45us/step - loss: 7.9511 - acc: 0.5010
Epoch 4/5
2000/2000 [==============================] - 0s 50us/step - loss: 7.9408 - acc: 0.5010
Epoch 5/5
2000/2000 [==============================] - 0s 53us/step - loss: 7.9279 - acc: 0.5015

<tensorflow.python.keras.callbacks.History at 0x7f4bdbdbda90>

预测:

predict_data = np.empty((0,2),float)
predict_data = np.append(predict_data, [[0, 0]], axis=0)
predict_data = np.append(predict_data, [[1, 0]], axis=0)
predict_data = np.append(predict_data, [[1, 1]], axis=0)
predict_data = np.append(predict_data, [[1, 1]], axis=0)

predict_labels = model.predict(predict_data)
print(predict_labels)

[[0.6280617 ]
 [0.48020774]
 [0.8395983 ]
 [0.8395983 ]]

(0,0) 的 0.6280617 非常糟糕。

【问题讨论】:

  • 您没有足够的数据来学习。 4 个数据点对于一般机器学习来说是不够的,这对于神经网络/深度学习来说更糟

标签: python tensorflow machine-learning keras classification


【解决方案1】:

你的问题设置有点奇怪,因为你只有四个数据点,却想学习梯度下降(或亚当)的模型权重。此外,batchnorm 在这里并没有什么意义,所以我建议将其删除。

除此之外,您的网络预测的是 0 到 1 之间的数字(“概率”),而不是类别标签。要获得预测的类标签,您可以使用model.predict_classes(predict_data) 而不是model.predict()

如果您是 ML 新手并且想尝试玩具数据集,您还可以查看 scikit-learn,它是一个实现更传统 ML 算法的库,而 Keras 专门用于深度学习。以逻辑回归为例,它与具有 sigmoid 激活的单个神经元相同,但在 sklearn 中使用不同的求解器实现:

from sklearn.linear_model import LogisticRegression

model  = LogisticRegression()
model = model.fit(train_data, train_labels)
model.predict(predict_data)
> array([0., 0., 1., 1.])

scikit-learn 网站包含大量示例,这些示例说明了玩具数据集上的这些不同算法。

在您的第二种情况下,您不允许第二个功能有任何变化,这是唯一重要的一个。如果您想在 1000 个数据点上训练模型,您可以在原始数据集中的四个点周围生成数据,并在其中添加一些随机噪声:

import keras
import numpy as np
import matplotlib.pyplot as plt

# Generate toy dataset
train_data = np.random.randint(0, 2, size=(1000, 2))
# Add gaussian noise
train_data = train_data + np.random.normal(scale=2e-1, size=train_data.shape)
train_labels = (train_data[:, 1] > 0.5).astype(int)

# Visualize the data, color-coded by their classes
fig, ax = plt.subplots()
ax.scatter(train_data[:, 0], train_data[:, 1], c=train_labels)

# Train a simple neural net
model = keras.models.Sequential()
model.add(keras.layers.Dense(1, input_shape= (2,), activation='sigmoid'))
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])

history = model.fit(train_data, train_labels, epochs=20)

您可以使用历史对象来可视化损失或准确性在训练期间的演变情况:

fig, ax = plt.subplots()
ax.plot(history.history['acc'])

最后,在一些测试数据上测试模型:

from sklearn.metrics import accuracy_score
# Test on test data
test_data = np.random.randint(0, 2, size=(100, 2))
# Add gaussion noise
test_data = test_data + np.random.normal(scale=2e-1, size=test_data.shape)
test_labels = (test_data[:, 1] > 0.5).astype(int)

accuracy_score(test_labels, model.predict_classes(test_data[:, 1]))

但是,请注意,您可以仅使用第二个坐标来解决整个问题。所以如果你把第一个扔掉它就可以了:

# Use only second coordinate
model = keras.models.Sequential()
model.add(keras.layers.Dense(1, input_shape= (1,), activation='sigmoid'))
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])

history = model.fit(train_data[:,1], train_labels, epochs=20)

此模型快速达到高精度:

【讨论】:

    【解决方案2】:

    是的,首先 BatchNorm 和 Adam 在这种情况下并没有什么意义。您的预测不起作用的原因是您的模型太弱而无法解决您的方程。如果你尝试用数学方法解决它,你将拥有:

    sigmoid(w1*x1+w2+x2+b0) = y
    

    因此,使用您的训练数据,您可以获得:

    1) sigmoid(b0) = 0 => b0 = -infinite
    2) sigmoid(w1+b0) = 0 => w1 = constant
    3) sigmoid(w2+b0) = 1 => w2 >> |b0| (already starting to break...)
    4) sigmoid(w1+w2+b0) = 1 => same as 3
    

    所以在我看来,训练器将开始在 2 和 3 之间波动,开始将一个比另一个增加得更高,而您将永远无法使用此模型达到您的预测

    如果您查看 75% 的准确率,这将是有意义的,因为您有 4 个训练示例,并且如上所述,一个预测是不可能的,因此您将获得 3/4 acc

    【讨论】:

    • 这些类在输入空间中是线性可分的,所以我不会说模型太弱,而是说优化问题是不适定的。
    • @sdcbr 但您不认为将这个理论应用于空间中距离相等的 4 个点可能不合适吗?
    • 这里的模型实际上太复杂了,因为我们甚至不需要第一个特征来进行正确的分类。所以是的,在这个问题上抛出 batchnorm、adam 和神经网络绝对是“不合适的”。我认为使用简单但可行的玩具数据集(例如 sklearn 示例)会提供更多信息:scikit-learn.org/stable/auto_examples/linear_model/…
    • 更新问题
    • 更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    相关资源
    最近更新 更多