我实施神经网络有什么问题?

时间:2017-08-28 12:41:21

标签: python scikit-learn neural-network

enter image description here我想根据训练样本的数量绘制神经网络的学习误差曲线。这是代码:

import sklearn
import numpy as np
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
from sklearn import neural_network
from sklearn import cross_validation

myList=[]
myList2=[]
w=[]

dataset=np.loadtxt("data", delimiter=",")
X=dataset[:, 0:6]
Y=dataset[:,6]
clf=sklearn.neural_network.MLPClassifier(hidden_layer_sizes=(2,3),activation='tanh')

# split the data between training and testing
X_train, X_test, Y_train, Y_test = cross_validation.train_test_split(X, Y, test_size=0.25, random_state=33)

# begin with few training datas
X_eff=X_train[0:int(len(X_train)/150), : ]
Y_eff=Y_train[0:int(len(Y_train)/150)]

k=int(len(X_train)/150)-1


for m in range (140) :


    print (m)

    w.append(k)

    # train the model and store the training error
    A=clf.fit(X_eff,Y_eff)
    myList.append(1-A.score(X_eff,Y_eff))

      # compute the testing error
    myList2.append(1-A.score(X_test,Y_test))

    # add some more training datas
    X_eff=np.vstack((X_eff,X_train[k+1:k+101,:]))
    Y_eff=np.hstack((Y_eff,Y_train[k+1:k+101]))
    k=k+100

plt.figure(figsize=(8, 8))
plt.subplots_adjust()
plt.title("Erreur d'entrainement et de test")
plt.plot(w,myList,label="training error")
plt.plot(w,myList2,label="test error")
plt.legend()
plt.show()

然而,我得到一个非常奇怪的结果,曲线波动,训练误差非常接近测试误差,这似乎不正常。 哪里出错了?我无法理解为什么有这么多的起伏,以及为什么培训错误没有增加,正如预期的那样。任何帮助都将不胜感激!

编辑:我使用的数据集是https://archive.ics.uci.edu/ml/datasets/Chess+%28King-Rook+vs.+King%29,在那里我摆脱了少于1000个实例的类。我手动重新编码了litteral数据。

3 个答案:

答案 0 :(得分:13)

我认为您之所以看到这种曲线的原因是您衡量的效果指标与您优化的效果指标不同

优化指标

神经网络使损失函数最小化,并且在tanh激活的情况下,我假设您正在使用交叉熵损失的修改版本。如果你要绘制一段时间内的损失,你会看到一个像你期望的更单调递减的错误函数。 (实际上并不是单调的,因为神经网络是非凸的,但这不是重点。)

效果指标

您衡量的绩效指标是百分比准确度,与损失不同。为什么这些不同?损失函数以可微分的方式告诉我们有多少错误(这对于快速优化方法很重要)。准确度指标告诉我们我们如何预测,这对于神经网络的应用是有用的。

把它放在一起

由于您正在绘制相关指标的效果,因此您可以预期该图表看起来与优化指标的图表类似。但是因为它们不一样,你可能会在你的情节中引入一些未说明的差异(正如你发布的情节所证明的那样)。

有几种方法可以解决这个问题。

  1. 绘制损失而不是准确度。如果您实际上需要精确度图,这实际上并不能解决您的问题,但它会为您提供更加平滑的曲线。
  2. 绘制多次运行的平均值。保存算法的20多次独立运行的准确度图(如在网络中训练20次),然后将它们平均并绘制出来。这将大大减少差异。
  3. TL; DR

    不要期望精确度图总是平滑且单调递减,它不会成为。

    问题编辑后:

    既然您已添加了数据集,我会看到一些其他可能导致您遇到问题的事情。

    数量级的信息

    数据集定义了几个棋子的等级和文件(行和列)。这些是从1到6的整数输入。然而,2真的1比1好吗? 6真的比4好4吗?我不认为国际象棋的位置就是这种情况。

    想象一下,我正在构建一个以金钱为输入的分类器。是否有一些信息被我的价值观所描绘?是的,1美元与100美元完全不同;而且我们可以看出存在基于幅度的关系。

    对于国际象棋游戏,第1行是否意味着与第8行不同的东西?事实上,根本没有,这些尺寸是对称的!在网络中使用偏置单元有助于通过“重新缩放”来解决对称性问题。你的输入有效地从[-3,4]开始,现在以(0)为中心(ish)。

    解决方案

    但是,我认为,您可以从每个功能的拼贴编码或单热编码中获得最大的收益。不要让网络依赖于每个功能的大小中包含的信息,因为这可能会导致网络进入糟糕的本地最佳状态。

答案 1 :(得分:7)

除了之前的答案,您还应该记住,您可能需要调整网络中的learning rate(通过在初始值设定项中设置learning_rate = value)。如果您选择较大的比率,您将从局部最小值跳到另一个或围绕这些点圈出,但实际上并未收敛(请参阅下面的图片,取自here)。

此外,请同时绘制loss,而不仅仅是网络的准确性。这将为您提供更好的见解。

另外,请记住,您必须使用大量培训和测试数据才能获得更多或更少的平稳"曲线,甚至是代表性的曲线;如果您只使用几个(可能是几百个)数据点,那么得到的指标实际上并不是非常准确,因为它们包含许多随机事物。要解决此错误,您不应每次都使用相同的示例训练网络,而是更改训练数据的顺序,并将其拆分为不同的mini batches。我非常有信心,您可以通过尝试解决这些问题并实施它们来解决甚至减少您的问题。

根据您的问题类型,您应该将激活功能更改为与tanh功能不同的功能。执行分类时,OneHotEncoder也可能有用(如果您的数据尚未进行热编码); sklearn框架也提供了implementation这个。

答案 2 :(得分:5)

随机化训练集并重复

如果您希望公平地比较训练样本数量对准确性的影响,我建议您从训练集中随机选择n_samples,而不是将100个样本添加到上一批。您还需要为每个N_repeat值重复n_samples次拟合。

这会产生类似的结果(未经测试):

n_samples_array = np.arange(100,len(X_train),100)
N_repeat = 10

for n_samples in n_samples_array:
    print(n_samples)

    # repeat the fit several times and take the mean
    myList_tmp, myList2_tmp = [],[]
    for repeat in range(0,N_repeat):
        # Randomly pick samples
        selection = np.random.choice(range(0,len(X_train)),n_samples,repeat=False)

        # train the model and store the training error
        A=clf.fit(X_train[selection],Y_train[selection])
        myList_tmp.append(1-A.score(X_train[selection],Y_train[selection]))

          # compute the testing error
        myList2_tmp.append(1-A.score(X_test,Y_test))

    myList.append(np.mean(myList_tmp))
    myList2.append(np.mean(myList2_tmp))

热烈启动

使用fit功能时,从头开始重新启动优化。如果您希望在向同一个以前训练过的网络添加一些示例时看到优化方面的改进,则可以使用选项warm_start=True

根据documentation

  

warm_start:bool,可选,默认为False

     

当设置为True时,重复使用前一个调用的解决方案以适合初始化,否则,只需擦除以前的解决方案。