神经网络与随机森林性能差异

我想使用PyTorch进行一些神经网络实验,所以我尝试了一个简单的练习作为热身,但结果让我有些困惑。

这个练习试图根据问题的各种统计数据(如变量数量、最大子句长度等)来预测1000个TPTP问题的评级。数据文件https://github.com/russellw/ml/blob/master/test.csv非常简单,有1000行,最后一列是评级,初始有几十列输入数据,所有数字都缩放到0-1的范围内,我逐步删除特征以查看结果是否仍然有效,确实如此,一直减少到只剩一列输入;其他版本可以在Git历史中找到。

我开始时使用了独立的训练和测试集,但目前暂时搁置了测试集,因为关于训练性能是否能推广到测试的问题,只有在首先获得训练性能后才会出现。

对这个数据集进行的简单线性回归的均方误差约为0.14。

我实现了一个简单的前馈神经网络,代码在https://github.com/russellw/ml/blob/master/test_nn.py,并复制如下,经过几百个训练轮次后,均方误差也为0.14。

所以我尝试将隐藏层的数量从1改为2再改为3,使用了不同的优化器,调整了学习率,将激活函数从relu改为tanh再改为两者的混合,增加了轮次到5000,增加了隐藏单元的数量到1000。此时,它应该已经有能力完全记住整个数据集。(此时我并不担心过拟合。我只是想让训练数据的均方误差变成0.14以外的其他值。)没有任何改变。仍然是0.14。我会说它一定是陷入了局部最优,但这不应该发生在你有几百万权重的时候;所有参数同时处于局部最优应该是几乎不可能的。而且每次运行时我确实得到了稍微不同的数字序列。但它总是收敛到0.14。

显而易见的结论是,对于这个问题,0.14已经是最好的了,除了即使网络有足够的记忆来记住所有数据,它仍然保持不变。但关键是,我还尝试了随机森林,https://github.com/russellw/ml/blob/master/test_rf.py

… 而随机森林在原始数据集上的均方误差为0.01,随着特征的删除性能逐渐下降,在仅剩一个特征的数据上仍然为0.05。

在机器学习的传说中,从未听说过“随机森林大大优于神经网络”,所以我显然是做错了什么,但我看不出是什么。也许只是简单地错过了一个标志或在PyTorch中需要设置的某些东西。如果有人能看一看,我将不胜感激。

import numpy as npimport pandas as pdimport torchimport torch.nn as nn# datadf = pd.read_csv("test.csv")print(df)print()# separate the output columny_name = df.columns[-1]y_df = df[y_name]X_df = df.drop(y_name, axis=1)# numpy arraysX_ar = np.array(X_df, dtype=np.float32)y_ar = np.array(y_df, dtype=np.float32)# torch tensorsX_tensor = torch.from_numpy(X_ar)y_tensor = torch.from_numpy(y_ar)# hyperparametersin_features = X_ar.shape[1]hidden_size = 100out_features = 1epochs = 500# modelclass Net(nn.Module):    def __init__(self, hidden_size):        super(Net, self).__init__()        self.L0 = nn.Linear(in_features, hidden_size)        self.N0 = nn.ReLU()        self.L1 = nn.Linear(hidden_size, hidden_size)        self.N1 = nn.Tanh()        self.L2 = nn.Linear(hidden_size, hidden_size)        self.N2 = nn.ReLU()        self.L3 = nn.Linear(hidden_size, 1)    def forward(self, x):        x = self.L0(x)        x = self.N0(x)        x = self.L1(x)        x = self.N1(x)        x = self.L2(x)        x = self.N2(x)        x = self.L3(x)        return xmodel = Net(hidden_size)criterion = nn.MSELoss()optimizer = torch.optim.Adam(model.parameters(), lr=0.1)# trainprint("training")for epoch in range(1, epochs + 1):    # forward    output = model(X_tensor)    cost = criterion(output, y_tensor)    # backward    optimizer.zero_grad()    cost.backward()    optimizer.step()    # print progress    if epoch % (epochs // 10) == 0:        print(f"{epoch:6d} {cost.item():10f}")print()output = model(X_tensor)cost = criterion(output, y_tensor)print("mean squared error:", cost.item())

回答:

你能打印出输入的形状吗?我建议你首先检查以下几点:

  • 确保你的目标y的形状是(-1, 1),我不知道PyTorch在这情况下是否会抛出错误。你可以使用y.reshape(-1, 1)如果它不是二维的
  • 你的学习率过高。通常使用Adam时,默认值就足够好,或者你可以尝试简单地降低学习率。0.1作为起始学习率是一个较高的值
  • 将optimizer.zero_grad()放在for循环的第一行
  • 标准化/归一化你的数据(这通常对神经网络有好处)
  • 移除数据中的异常值(我的意见:我认为这对随机森林的影响不大,但对神经网络的影响可能很大)
  • 使用交叉验证(也许skorch可以在这里帮助你。它是一个PyTorch的scikit-learn包装器,使用起来很简单,如果你熟悉keras的话)

请注意,随机森林回归器或任何其他回归器在某些情况下可能优于神经网络。有些领域神经网络是英雄,如图像分类或自然语言处理,但你需要意识到一个简单的回归算法可能优于它们。通常当你的数据不够大时会发生这种情况。

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中创建了一个多类分类项目。该项目可以对…

发表回复

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