Keras中多标签分类的奇怪准确性

7
我有一个多标签分类问题,我使用了以下代码。但是验证准确率在第一次 epoch 就跳到了 99%,这很奇怪,因为输入特征是从 Inception 模型 (pool3:0) 的 2048 层中提取而来的,标签是 [1000]。(这里是包含特征和标签样本的文件链接:https://drive.google.com/file/d/0BxI_8PO3YBPPYkp6dHlGeExpS1k/view?usp=sharing)那么我做错了什么吗?
注意:标签是稀疏向量,只包含 1-10 个元素的值为 1,其余为零。
model.compile(optimizer='adadelta', loss='binary_crossentropy', metrics=['accuracy']) 

预测的输出结果为零!

我在训练模型时做错了什么才会影响预测?

#input is the features file and labels file

def generate_arrays_from_file(path ,batch_size=100):
x=np.empty([batch_size,2048])
y=np.empty([batch_size,1000])
while True:
    f = open(path)
    i = 1  
    for line in f:
        # create Numpy arrays of input data
        # and labels, from each line in the file
        words=line.split(',')
        words=map(float, words[1:])
        x_= np.array(words[0:2048])
        y_=words[2048:]
        y_= np.array(map(int,y_))
        x_=x_.reshape((1, -1))
        #print np.squeeze(x_)
        y_=y_.reshape((1,-1))
        x[i]= x_
        y[i]=y_
        i += 1
        if i == batch_size:
            i=1
            yield (x, y)

    f.close()

model = Sequential()
model.add(Dense(units=2048, activation='sigmoid', input_dim=2048))
model.add(Dense(units=1000, activation="sigmoid", 
kernel_initializer="uniform"))
model.compile(optimizer='adadelta', loss='binary_crossentropy', metrics=
['accuracy'])

model.fit_generator(generate_arrays_from_file('train.txt'),
                validation_data= generate_arrays_from_file('test.txt'),
                validation_steps=1000,epochs=100,steps_per_epoch=1000, 
                  verbose=1)

1
生成器是否正确创建标签?听起来你给模型的真实值都是零。 - Daniel Möller
1
你的数据集统计数据是什么?如果你的训练数据集太小,那么你肯定处于过拟合的情况。如果不是这种情况,你应该尝试应用一些dropout来避免过拟合。 - Alessandro Suglia
@AlessandroSuglia 我们的数据集有200k张图片,所以不算小。关于dropout,我尝试了一下,但是问题还是一样。 - RanaSamy
@Daniel,我认为问题出在生成器上,但我确定输入标签并不全是零,我是按照这种方式从文件中生成的。 - RanaSamy
给定示例的类是否独立?也许二元交叉熵不是您问题的最佳解决方案。 - Alessandro Suglia
显示剩余5条评论
2个回答

6
我认为准确性的问题在于你的输出是稀疏的。
Keras使用以下公式计算准确性:
K.mean(K.equal(y_true, K.round(y_pred)), axis=-1)

所以,在你的情况下,只有1~10个非零标签,所有预测值都为0会得到99.9%~99%的准确率。
至于问题未能学习,我认为问题在于你使用sigmoid作为最后一个激活函数,并将0或1用作输出值。这是不好的实践,因为为了使sigmoid返回0或1,它接收的输入值必须非常大或非常小,这反映在网络具有非常大(绝对值)的权重上。此外,由于每个训练输出中1比0少得多,所以网络很快就会达到一个稳定点,在这个点上它只输出所有的0(此时损失也不是很大,应该在0.016~0.16之间)。
你可以将输出标签缩放到(0.2,0.8)之间,以便网络的权重不会变得太大或太小。或者你可以使用relu作为激活函数。

1
谢谢,但我仍然有同样的问题,我将输出从0.2缩放到0.8,但我的模型无法正确预测,因为输出也停留在0.2。 - RanaSamy
尝试使用relu。或者,您是否尝试添加更多的隐藏层?深度通常比宽度更好。看起来您正在尝试使用非常浅的网络模拟复杂问题。1000个标签是很多的,GoogLeNet使用非常深的网络来使用相同数量的标签对图像进行分类(虽然它们的输入为224x224的图像)。您可以尝试使用较少的标签进行分类,然后增加数量(从10开始,然后是100等等)。如果仍然无法训练,则可能存在代码问题。 - gionni
@gionni 如果深度网络也出现了同样的问题,该怎么办? - Pawan Mishra
我不知道,这取决于数据和架构。 - gionni

1

你尝试使用余弦相似度作为损失函数了吗?

我也遇到了多标签和高维度问题。

余弦距离考虑了模型输出(预测)和期望输出(真实类别)向量的方向。

它是两个向量之间的归一化点积。

在keras中,余弦距离函数是-cosine_distance。这意味着-1对应于具有相同大小和方向的两个向量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接