我的数据集具有以下形状
[[ 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个区间,代表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.001n_layer_1 = 64n_layer_2 = 64num_classes = 5def 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 modelmodel = build_classification_model(train_X)num_epochs = 200print('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。
无论我添加新层、更改隐藏层中的节点数量还是更改学习率,每条记录的概率看起来都非常相似。
我做错了什么?
谢谢
回答:
我首先建议做两件事:
- 在
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)
这将确保模型在所有类别的样本上都进行公平的训练。
- 你的批量大小太高了,我认为这里存在一个误解。使用SGD时,批量大小是网络在进行梯度更新之前处理的样本数量,而不是你拥有的训练样本数量。从外观上看,你甚至没有500个训练样本。较小的批量大小,通常使用默认值32,可以确保每个epoch有多个梯度更新。大量的梯度更新对于梯度下降更为有效,因为每次梯度更新时都是小步前进。你的网络目前设置的200次更新,考虑到你的参数数量,并不多,所以减少批量大小吧!