多类Keras感知器分类器将所有内容归为一个类

时间:2019-05-02 00:09:15

标签: python tensorflow machine-learning keras neural-network

我的数据集具有以下形状

[[  1.   337.   118.   ...   9.65   1.     0.92]
 [  2.   324.   107.   ...   8.87   1.     0.76]
 [  3.   316.   104.   ...   8.     1.     0.72]
 ...
 [498.   330.   120.   ...   9.56   1.     0.93]
 [499.   312.   103.   ...   8.43   0.     0.73]
 [500.   327.   113.   ...   9.04   0.     0.84]]

最后一列是因变量,所有其他列都是自变量。第一列是ID变量,由于我假设它不提供任何信息,因此我将其删除。

我将以这种方式将因变量分组到5个bin中,它们代表5个类:

X = raw[:,1:8]
Y = raw[:,8]

def mapping(x):
  if (x <= 0.5):
    return 0;
  if (x <= 0.65):
    return 1;
  if (x <= 0.8):
    return 2;
  if (x <= 0.9):
    return 3;
  if (x <= 1):
    return 4;

Y = np.array(list(map(mapping, Y)))

最终的班级频率如下:

(array([0, 1, 2, 3, 4]), array([ 39, 119, 200,  81,  61]))

因此,这并不像一类人比其他人盛行。

但是,当运行我的多层感知器模型时,它会将所有内容分类为一个类。哪个类取决于运行,但是每个记录都相同。

我的模型如下:

Y = to_categorical(Y)

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.33, random_state=10)

learning_rate = 0.001
n_layer_1 = 64
n_layer_2 = 64
num_classes = 5

def build_classification_model(train_set):
  model = keras.Sequential([
    layers.Dense(n_layer_1, activation=tf.nn.relu, input_shape=tuple([train_set.shape[1]])),
    layers.Dense(n_layer_2, activation=tf.nn.relu, ),
    layers.Dense(5, activation=tf.nn.softmax)
  ])

  optimizer = tf.keras.optimizers.SGD()

  model.compile(loss='categorical_crossentropy',
                optimizer=optimizer,
                metrics=['categorical_accuracy', 'mean_squared_error'])
  return model

model = build_classification_model(train_X)
num_epochs = 200

print('Training...')
history = model.fit(train_X, train_Y, batch_size=500, epochs=num_epochs, verbose=0)
print('Done.')
prediction = model.predict(train_X)

prediction每次运行都像这样:

array([[2.17507738e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        2.74140113e-14],
       [1.16876501e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        1.38829174e-14],
       [2.22264258e-18, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        4.08135584e-15],
       ...,
       [2.78243342e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        2.62153224e-14],
       [1.69924047e-16, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        1.70491795e-13],
       [5.26733592e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        4.98645043e-14]], dtype=float32)

请注意,它将所有内容都选为第3类。

添加新层,更改隐藏层中的节点数或更改学习率都没有关系:每条记录的概率看起来几乎相同。

我在做什么错了?

谢谢

1 个答案:

答案 0 :(得分:1)

我首先建议两件事:

  1. train_test_split期间以分层方式拆分数据,以确保训练和测试集包含代表数量的所有类别的样本。这很容易实现:

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.33, random_state=10, stratify=Y)

这将确保在所有类别的大量样本上训练模型。

  1. 您的批次大小太大,我认为这里存在误解。使用SGD时,批次大小是在进行梯度更新之前网络处理的样本数量,而不是您拥有的训练示例数量。从外观上看,您甚至没有500个培训示例。通常使用小批量(默认值为32),以确保每个时期多次更新梯度。大量的坡度更新对于坡度下降更为有效,在每次坡度更新时,步长都较小。由于您的网络当前已设置200个更新,因此考虑到您的参数数量并不多,因此请减少批量大小!