Numpy NN 在合成数据集上产生奇怪的结果

我正在按照书籍Grokking Deep Learning(第8章,代码在这里)中的指导,构建一个Numpy神经网络,用于对MNIST数字进行分类,测试准确率约为82%。但当我修改神经网络以适应一个合成数据集时,它会从训练开始就达到一个特定的训练准确率(取决于隐藏层的维度和alpha),并停留在那里。请检查以下内容:

import numpy as npimport sysfrom sklearn import datasetsX, y = datasets.make_classification(n_samples=10000, n_features=5, n_classes=4,                                         n_clusters_per_class=1, shuffle=True, random_state=1)from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)def relu(x):    return (x >= 0) * x # returns x if x > 0                        # returns 0 otherwisedef relu2deriv(output):    return output >= 0 #returns 1 for input > 0def onehot(arr):    one_hot_labels = np.zeros((len(arr),4))    for i,l in enumerate(arr):        one_hot_labels[i][l] = 1            return one_hot_labelsy_train = onehot(y_train)y_test = onehot(y_test)alpha, iterations, hidden_size = (0.002, 300, 10)weights_0_1 = 0.2*np.random.random((5, hidden_size)) - 0.1weights_1_2 = 0.2*np.random.random((hidden_size, 4)) - 0.1for j in range(iterations):    error, correct_cnt = (0.0,0)    for i in range(len(X_train)):        layer_0 = X_train[i:i+1]        layer_1 = relu(np.dot(layer_0,weights_0_1))        dropout_mask = np.random.randint(2, size=layer_1.shape)        layer_1 *= dropout_mask * 2        layer_2 = np.dot(layer_1,weights_1_2)        error += np.sum((y_train[i:i+1] - layer_2) ** 2)        correct_cnt += int(np.argmax(layer_2) == np.argmax(y_train[i:i+1]))        layer_2_delta = (y_train[i:i+1] - layer_2)        layer_1_delta = layer_2_delta.dot(weights_1_2.T) * relu2deriv(layer_1)        layer_1_delta *= dropout_mask        weights_1_2 += alpha * layer_1.T.dot(layer_2_delta)        weights_0_1 += alpha * layer_0.T.dot(layer_1_delta)    if(j%1 == 0):  # can be set for any interval        test_error = 0.0        test_correct_cnt = 0        for i in range(len(X_test)):            layer_0 = X_test[i:i+1]            layer_1 = relu(np.dot(layer_0, weights_0_1))            layer_2 = np.dot(layer_1, weights_1_2)            test_error += np.sum((y_test[i:i+1] - layer_2) ** 2)            test_correct_cnt += int(np.argmax(layer_2) == np.argmax(y_test[i:i+1]))                sys.stdout.write("\n" + \                     "I:" + str(j) + \                     " Test-Err:" + str(test_error/ float(len(X_test)))[0:5] +\                     " Test-Acc:" + str(test_correct_cnt/ float(len(X_test)))+\                     " Train-Err:" + str(error/ float(len(X_train)))[0:5] +\                     " Train-Acc:" + str(correct_cnt/ float(len(X_train))))

输出:

I:0 Test-Err:0.470 Test-Acc:0.812 Train-Err:0.704 Train-Acc:0.572I:1 Test-Err:0.452 Test-Acc:0.811 Train-Err:0.574 Train-Acc:0.626625I:2 Test-Err:0.445 Test-Acc:0.814 Train-Err:0.571 Train-Acc:0.61425    .    .    .I:297 Test-Err:0.470 Test-Acc:0.7685 Train-Err:0.613 Train-Acc:0.6045I:298 Test-Err:0.492 Test-Acc:0.785 Train-Err:0.612 Train-Acc:0.60525I:299 Test-Err:0.478 Test-Acc:0.778 Train-Err:0.614 Train-Acc:0.60725

这是怎么回事?为什么这个神经网络能在MNIST数据集上表现良好,而在这个数据集上却不行?


回答:

我认为问题在于你没有使用偏置项(bias terms)。

例如,

layer_1 = relu(np.dot(layer_0,weights_0_1))

从几何角度来看,这意味着第1层的输出(以及其余层的输出)没有平移项,这使得决策边界被迫通过原点。

查看可视化

因此,对于不围绕0的数据,可能无法学习到决策边界。想象一下,对于二元分类,数据紧密聚集在(0, 1)(0, 2)周围。通过(0, 0)的任何线性边界都无法分离这些聚类。

关于为什么需要偏置项,这里有一个很好的解释:查看这里


认为(但没有验证),添加偏置项应该可以实现收敛。

layer_1 = relu(np.dot(layer_0,weights_0_1) + layer_0_bias) 

以此类推。

关于偏置的导数,在这里有讨论:查看这里


还有更多可能的原因。

  1. layer_2的输出是输出,计算的是均方误差损失(MSELoss),而不是使用负对数似然损失(NLL)或交叉熵损失(CrossEntropy Loss)。
  2. 没有对输入进行归一化,这可能导致网络无法学习。对于来自超立方的合成数据,这不太可能,但对于其他一般数据来说,很可能如此。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注