我想画出一个神经网络的学习误差曲线与训练实例的数目有关。代码如下:
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个的类。我手动重新编码了这些垃圾数据。在
随机化训练集并重复
如果你想公平地比较训练样本数对准确性的影响,我建议从你的训练集中随机选取
n_samples
,而不是在前一批中增加100个样本。您还需要为每个n_samples
值重复拟合N_repeat
次。在这将给出如下结果(未经测试):
热启动
当您使用
fit
函数时,您将从头开始优化。如果您希望在向先前训练过的网络中添加一些示例时看到优化的改进,可以使用选项warm_start=True
根据documentation:
我认为你看到这种曲线的原因是你测量的性能指标和你正在优化的性能指标不同。在
优化指标
神经网络使损失函数最小化,在tanh激活的情况下,我假设你使用的是交叉熵损失的修正版本。如果你画出损失随时间的变化,你会看到一个更单调递减的误差函数。 (实际上并不是单调的,因为神经网络是非凸的,但这不是重点。)
性能指标
您正在测量的性能指标是精确度百分比,它与损失不同。为什么这些不同?损失函数以一种可微的方式告诉我们有多少误差(这对于快速优化方法很重要)。精度指标告诉我们预测的好坏,这对神经网络的应用是有用的。在
把它放在一起
因为您正在绘制相关度量的性能,所以可以预期该绘图看起来与优化度量的性能类似。但是,因为它们不一样,你可能会在你的图中引入一些未解释的差异(从你发布的图中可以看出)。在
有几种方法可以解决这个问题。在
TL;DR
不要期望精度图总是平滑和单调递减的,它不会的。在
问题后编辑:
现在您已经添加了数据集,我看到了其他一些可能导致您所看到的问题的因素。在
震级信息
数据集定义了几个象棋棋子的等级和文件(行和列)。这些输入是从1到6的整数。然而2真的比1好吗?6真的比2强4吗?我不认为国际象棋的位置是这样的。在
假设我正在构建一个将钱作为输入的分类器。我的价值观是否反映了一些信息?是的,1美元和100美元大不相同;我们可以从数量上看出两者之间存在着某种关系。在
对于国际象棋比赛来说,第1排和第8排有什么不同吗?一点也不,事实上这些维度是对称的!在你的网络中使用一个偏差单位可以帮助你解释对称性,通过“重新调整”你的输入有效地从[-3,4]开始,这个值现在以0为中心(ish)。在
解决方案
但是,我认为,你将获得最大的里程瓦片编码或一个热编码的每一个功能。不要让网络依赖于包含在每个特征量中的信息,因为这可能会导致网络陷入糟糕的局部最优状态。在
除了前面的答案之外,您还应该记住,您可能需要调整网络的
learning rate
(通过在初始值设定项中设置learning_rate = value
)来进行调整。如果你选择大的速率,你将从局部最小值跳到另一个或围绕这些点旋转,但实际上不会收敛(见下图,取自here)。在此外,还请绘制
loss
,而不仅仅是网络的准确性。这会让你对它有更好的了解。在另外,请记住,您必须使用大量的训练和测试数据来获得或多或少“平滑”的曲线,甚至是一条具有代表性的曲线;如果您只使用几个(可能几百个)数据点,那么结果度量实际上不会非常准确,因为它们包含了许多随机的东西。要解决这个错误,您不应该每次都用相同的示例训练网络,而是更改训练数据的顺序,并可能将其拆分到不同的mini batches。我很有信心,你可以解决甚至减少你的问题,通过努力注意这些方面并加以实施。在
根据您的问题类型,您应该将激活函数更改为与
tanh
函数不同的值。在执行分类时,OneHotEncoder
可能也很有用(如果您的数据还不是一个热编码的)sklearn
框架也提供了一个implementation。在相关问题 更多 >
编程相关推荐