Python PyTorch二进制分类-相同的网络结构&x27;更简单';数据,但性能更差?
为了掌握PyTorch(以及一般的深度学习),我从一些基本的分类示例开始。其中一个例子是对使用sklearn创建的非线性数据集进行分类(完整代码在笔记本中提供) 然后使用一个非常基本的神经网络对其进行精确分类Python PyTorch二进制分类-相同的网络结构&x27;更简单';数据,但性能更差?,python,machine-learning,deep-learning,artificial-intelligence,pytorch,Python,Machine Learning,Deep Learning,Artificial Intelligence,Pytorch,为了掌握PyTorch(以及一般的深度学习),我从一些基本的分类示例开始。其中一个例子是对使用sklearn创建的非线性数据集进行分类(完整代码在笔记本中提供) 然后使用一个非常基本的神经网络对其进行精确分类 class Model(nn.Module): def __init__(self, input_size, H1, output_size): super().__init__() self.linear = nn.Linear(input_si
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
由于我对健康数据感兴趣,于是我决定尝试使用相同的网络结构对一些基本的真实数据集进行分类。我从中获取了一名患者的心率数据,并对其进行了修改,使所有大于91的值都被标记为异常(例如,a
1
和所有让我们首先了解神经网络是如何工作的,神经网络观察模式,因此有必要使用大型数据集。在本例中,两种模式是当如果HR<91:label=0
,则这种情况可以用公式sigmoid表示((HR-91)*1),如果您将各种值插入公式中,您可以看到所有值均<91,标签0和其他标签1。我已推断出此公式,只要给出正确的值,它可以是任何值
基本上,我们应用公式wx+b,其中x在我们的输入数据中,我们学习w和b的值。现在,最初的值都是随机的,所以从103011190(随机值)中得到b值,可能98很快,因为损失很大,学习速度允许值快速跳跃。但是一旦你达到98,你的损失就会减少,当你应用学习速度时,需要更多的时间才能接近91,因此损失会缓慢减少。随着值越来越近,所采取的步骤会更慢
这可以通过损耗值来确认,损耗值在不断减小,最初,减速度较高,但随后变小。您的网络仍在学习,但速度较慢
因此,在深度学习中,您可以使用这种称为阶梯式学习速率的方法,随着时间的增加,您的学习速率会降低,因此您的学习速度会更快
您的输入数据未规范化
x_data=(x_data-x_data.mean())/x_data.std()
optimizer=torch.optim.Adam(model.parameters(),lr=0.01)
只需1000次迭代即可收敛 更多细节 两个示例之间的关键区别在于,第一个示例中的数据
x
以(0,0)为中心,方差非常小。另一方面,第二示例中的数据以92为中心并且具有相对较大的方差 当您随机选择输入时,不考虑数据中的初始偏差,这是基于输入大致正态分布在零附近的假设进行的。
优化过程几乎不可能补偿这种总偏差,因此模型陷入次优解 一旦将输入标准化,通过减去平均值并除以std,优化过程将再次变得稳定,并迅速收敛到一个好的解决方案 有关输入规范化和权重初始化的更多详细信息,请参阅He等人(ICCV 2015)中的第2.2节 如果我不能正常化数据怎么办? 如果由于某种原因,您无法提前计算平均值和std数据,则仍可以使用它来估计和规范数据,作为培训过程的一部分
类模型(nn.Module):
定义初始大小(自身、输入大小、H1、输出大小):
super()。\uuuu init\uuuuu()
self.bn=nn.BatchNorm1d(输入大小)#添加batchnorm
self.linear=nn.linear(输入大小,H1)
self.linear2=nn.Linear(H1,输出大小)
def前进(自身,x):
x=火炬.sigmoid(自线性(自bn(x))#输入x
x=火炬S形(自线性2(x))
返回x
在不改变输入数据的情况下,这种修改仅在1000个历元后产生类似的收敛性:小评论 对于数值稳定性,最好使用而不是。为此,您需要从
forward()
输出中删除torch.sigmoid
,将在损失内计算sigmoid
。例如,关于二元预测的相关sigmoid+交叉熵损失,请参见。谢谢,我理解这一过程,但我试图理解的是,为什么第二个数据集需要花费如此长的时间才能获得较低的损失值。这两个数据集的大小相似,但HR示例似乎是一个更简单的分类问题,但训练损失比较表明情况正好相反。这似乎并没有试图回答OP的问题。非常感谢你的赏金。很高兴我能提供帮助。快速跟进问题。我如何处理对新数据的预测,也就是说,这不也需要标准化吗?但如果我只有一个新数据po,我该怎么做呢例如,在你纠正我的方法之前,我会简单地使用
point=torch.tensor([100.])
和model.predict(point)
@PhilipO'Brien您已经计算过一次平均值和标准差。您在整个培训和测试过程中使用这些值validation@PhilipO“Brien,看看我发布的rnn答案的colab中是怎么做的,那么我认为你用新的原始输入数据进行预测,然后乘以标准偏差并加上平均值是对的,例如,*sig+mu
例如,如果点=火炬.张量([100.])
那么pred=模型.预测(点)*sig+mu
我不认为我遵循;在colab中,在生成预测后,你似乎应用了均值和sig,例如pred[-1,…]*sig+mu
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