Pythorch二进制分类相同的网络结构,“更简单”的数据,但性能更差?

2024-05-19 20:53:59 发布

您现在位置:Python中文网/ 问答频道 /正文

为了掌握PyTorch(以及一般的深度学习),我从一些基本的分类示例开始。其中一个例子是对使用sklearn创建的非线性数据集进行分类(完整代码可作为notebookhere

n_pts = 500
X, y = datasets.make_circles(n_samples=n_pts, random_state=123, noise=0.1, factor=0.2)
x_data = torch.FloatTensor(X)
y_data = torch.FloatTensor(y.reshape(500, 1))

enter image description here

然后使用非常基本的神经网络对其进行准确分类

^{pr2}$

由于我对健康数据感兴趣,我决定尝试使用相同的网络结构对一些基本的现实世界数据集进行分类。我从here获取一名患者的心率数据,并对其进行了修改,使所有值>;91都被标记为异常(例如a 1和所有<;=91标记为a0)。这完全是武断的,但我只是想看看分类是如何工作的。本例的完整笔记本是here。在

enter image description here

我不直观的是为什么第一个例子在1000个时代之后达到了0.0016的损失,而第二个例子在10000个时代之后只达到了0.4296的损失

{a6}

Training Loss for Heart Rate Example

也许我天真地认为心率的例子更容易分类。任何见解,帮助我理解为什么这不是太好了!在


Tags: 数据标记示例datahere分类torchpytorch
2条回答

让我们先来了解一下神经网络是如何工作的,神经网络观察模式,因此需要大数据集。在这个例子中,你想要找到的两个what模式是when if HR < 91: label = 0,这个if条件可以用公式sigmoid((HR-91)*1来表示,如果你在公式中插入不同的值,你可以看到所有值<;91,标签0和其他标签1。我已经推断出这个公式,只要它给出正确的值,它可以是任何东西。在

基本上,我们应用公式wx+b,其中x在我们的输入数据中,我们学习w和b的值。现在最初的值都是随机的,所以从1030131190(一个随机值)得到b值可能很快,因为损失很大,所以学习率允许值快速跳跃。但一旦你达到98,你的损失就在减少,当你应用学习率时,要花更多的时间才能接近91,因此损失会慢慢减少。随着数值越接近,所采取的步骤就越慢。在

这可以通过损失值来证实,它们是不断减小的,最初,减速度较高,但后来变小。你的人际网络仍在学习,但速度很慢。在

在你的学习速度下降的时代,你用这种方法来提高学习速度

TL;DR

您的输入数据未规范化。在

  1. 使用x_data = (x_data - x_data.mean()) / x_data.std()
  2. 提高学习率optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

您将得到
enter image description here

仅在1000次迭代中收敛。在

更多详情

两个示例之间的关键区别在于第一个示例中的数据x以(0,0)为中心,并且具有非常低的方差。
另一方面,第二个例子中的数据以92为中心,具有相对较大的方差。在

当您随机initialize the weights时,数据中的这种初始偏差没有考虑在内,这是基于输入大致正态分布在zero
优化过程几乎不可能补偿这种总偏差,因此模型陷入了次优解。在

一旦你规范化输入,通过减去平均值并除以标准差,优化过程再次变得稳定,并迅速收敛到一个好的解决方案。在

有关输入规范化和权重初始化的更多详细信息,请参阅He et alDelving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification(ICCV 2015)中的第2.2节。在

如果我不能规范化数据怎么办?

如果由于某种原因,您不能预先计算平均值和标准数据,那么您仍然可以使用^{}来估计和规范化数据,作为训练过程的一部分。例如

class Model(nn.Module):
    def __init__(self, input_size, H1, output_size):
        super().__init__()
        self.bn = nn.BatchNorm1d(input_size)  # adding batchnorm
        self.linear = nn.Linear(input_size, H1)
        self.linear2 = nn.Linear(H1, output_size)

    def forward(self, x):
        x = torch.sigmoid(self.linear(self.bn(x)))  # batchnorm the input x
        x = torch.sigmoid(self.linear2(x))
        return x

在输入数据没有任何改变的情况下,这种修改只在1000个周期后产生类似的收敛性:
enter image description here

小评论

为了数值稳定性,最好使用^{}而不是{a7}。为此,您需要从forward()输出中删除torch.sigmoid,而{}将在损失内计算。
例如,参见this thread关于二元预测的相关sigmoid+交叉熵损失。在

相关问题 更多 >