gpt4 book ai didi

python - PyTorch 二进制分类 - 相同的网络结构, 'simpler' 数据,但性能更差?

转载 作者:太空狗 更新时间:2023-10-29 17:18:48 25 4
gpt4 key购买 nike

为了掌握 PyTorch(以及一般的深度学习),我首先研究了一些基本的分类示例。一个这样的例子是对使用 sklearn 创建的非线性数据集进行分类(完整代码可作为笔记本 here 获得)

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

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

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

def forward(self, x):
x = torch.sigmoid(self.linear(x))
x = torch.sigmoid(self.linear2(x))
return x

def predict(self, x):
pred = self.forward(x)
if pred >= 0.5:
return 1
else:
return 0

由于我对健康数据很感兴趣,因此我决定尝试使用相同的网络结构对一些基本的真实世界数据集进行分类。我从 here 中获取了一名患者的心率数据, 并对其进行了更改,以便所有 > 91 的值都被标记为异常(例如 1 并且所有 <= 91 都被标记为 0)。这完全是任意的,但我只是想看看分类是如何工作的。此示例的完整笔记本是 here .

enter image description here

我不直观的是,为什么第一个示例在 1,000 个迭代后损失了 0.0016,而第二个示例仅达到在 10,000 个迭代后损失了 0.4296

Training Loss for Example 1

Training Loss for Heart Rate Example

也许我天真地认为心率示例会更容易分类。任何有助于我理解为什么这不是我所看到的的见解都会很棒!

最佳答案

长话短说

您的输入数据未规范化。

  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 时,数据中的这种初始偏差没有被考虑在内这是基于输入大致呈​​正态分布在附近的假设来完成的。
优化过程几乎不可能补偿这种严重偏差 - 因此模型陷入次优解决方案。

通过减去均值并除以标准差对输入进行归一化后,优化过程再次变得稳定并迅速收敛到一个好的解决方案。

有关输入归一化和权重初始化的更多详细信息,您可以阅读He et al Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification 中的第 2.2 节(ICCV 2015)。

如果我无法规范化数据怎么办?

如果由于某种原因您无法提前计算均值和标准数据,您仍然可以使用 nn.BatchNorm1d作为训练过程的一部分来估计和规范化数据。例如

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

小评论

为了数值稳定性,最好使用nn.BCEWithLogitsLoss而不是 nn.BCELoss .为此,您需要从 forward() 输出中移除 torch.sigmoidsigmoid 将在损失内计算。< br/>参见,例如,this thread关于二进制预测的相关 sigmoid + 交叉熵损失。

关于python - PyTorch 二进制分类 - 相同的网络结构, 'simpler' 数据,但性能更差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57161576/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com