检测类的sigmoid输出返回不正确的性能

时间:2015-04-11 15:38:36

标签: python machine-learning neural-network pylearn

我的问题摘要:我有检测(二进制分类,不平衡问题)。我使用sigmoid对样本进行分类。报告的f分数,精确度和回忆率似乎都考虑了两个类别,例如:真阳性似乎是正确分类的样本的总数,而不是属于类' 1'的样本的总数。正确分类的。

更长的解释:在我的实验中,我有关于人的人口统计数据,我必须预测他们是否购买了产品。我使用PCA将初始功能减少到只有4个功能,数据存储在csv文件中(第一列包含类标签,' 0'以及' 1')。请注意,大多数人都没有购买,然后这两个类非常不平衡。我使用 CSVDataset 类来读取它:

dataset: &train !obj:pylearn2.datasets.csv_dataset.CSVDataset {
        path: 'input.csv',
        task: 'classification'
}

我想从一个简单的分类模型开始,我使用f-score作为绩效衡量标准。因此,我的第一个想法是使用具有单个S形层的MLP模型(默认监视器'检测'提供回忆,精确度,f分数):

model: !obj:pylearn2.models.mlp.MLP {
        layers: [
                 !obj:pylearn2.models.mlp.Sigmoid {
                     layer_name: 'y',
                     dim: 2,
                     irange: .005
                 }
                ],
        nvis: 4,
    }

我最初的想法是将dim设置为1(决策规则是:如果输出> 0.5选择class' 1',如果< 0.5选择class' 0') 。但是,我收到错误 ValueError:无法转换为dim 1的VectorSpace。预计dim = 2(合并one-hots)或2(concatenated one-hots)然后我决定将dim设置为2(决策规则是:如果out1> out0选择' 1',如果out1

在我的 train.yaml 中,我或多或少地遵循文档中提供的softmax示例笔记本。例如,我使用BGD算法并将batch_size设置为训练集中的示例总数(74164示例,一个小数据集!),以避免在手动检查性能时出现混淆。

使用提供的 train.py 脚本训练模型,一切似乎都很好,直到我查看结果。如前所述,这是一个检测问题,检测类(' 1')很少发生。因此,我很惊讶地看到报告的train_y_f1的值很高(一个纪元后的最佳结果是大约94%)。

为了检查这一点,我使用提供的脚本predict_csv.py手动计算了f-score,然后加载预测。我看到其实只有未命中(所有' 1'被归类为' 0'),因此精确度,召回率和f分数应该全部为零。为什么检测监控器会报告更高的值?

经过一番调查后,我发现MLP每个类都有一个输出,我验证(手动计算并得到相同的数字),get_detection_channels_from_state()中定义的真阳性和误报实际上指的是两个类,& #39; 1'和' 0',例如真阳性是属于' 1'的向量的数量。分类为' 1'总计为属于' 0'的向量的数量。分类为' 0'。因此,MLP将所有内容归类为' 0',并且由于几乎所有向量都属于' 0',因此性能良好。这是不平衡检测问题的已知问题,其中正确的分类率不是合适的度量,并且这是我们具有诸如f分数或AUC的度量的原因。但是,如果get_detection_channels_from_state()中的tp和fp同时考虑这两个类,那么报告的f分数是没用的(至少对我不起)。

我可以想象这对于Sigmoid类的设计者来说是已知的,所以我只能假设我做错了什么。希望有人可以给我一个提示:)

注意:我已将此问题提交给pylearn2用户邮件列表。如果我得到答案,我会在这里复制......

1 个答案:

答案 0 :(得分:0)

pylearn监视器计算每个批次的f1分数,%misclass等,而不是整个时期。当它生成报告时,f1分数是纪元中所有批次的f1的平均值。当你查看像misclass这样的数量时,报告所有批次的均值可以正常工作:

misclass [n]是第n批的得分
misclass_epoch = mean(misclass [0] + misclass [1] + .. misclass [n])

但是,您无法为f1分数构建相同的语句:
f1_epoch!= mean(f1 [0] + f1 [1] + .. f1 [n])
其中f1 [n] = 2 *精度[n] *召回[n] /(精度[n] +召回[n])

出于演示目的,请尝试将批量大小设置为数据集的大小(您可以在mnist示例中使用此方法)。然后f1分数是正确的。

因此,最好的建议是密切监视监视器中的数量,如错误类,其中批次的平均值与纪元的值相同。一旦你训练了nn,你就可以对你的整个验证集进行预测,并计算当时的f1分数。