【问题标题】:how to feed DataGenerator for KERAS multilabel issue?如何为 KERAS 多标签问题提供数据生成器?
【发布时间】:2020-06-04 22:32:13
【问题描述】:

我正在使用 KERAS 解决多标签分类问题。 当我执行这样的代码时,出现以下错误:

ValueError:检查目标时出错:预期activation_19 有2 维,但得到的数组形状为(32, 6, 6)

这是因为我的标签字典中的列表充满了“0”和“1”,正如我最近了解到的那样,它们在 return 语句中不适合 keras.utils.to_categorical。 softmax 也不能处理多个“1”。

我想我首先需要一个 Label_Encoder,然后是 labels 的 One_Hot_Encoding,以避免标签中出现多个“1”,这些“1”不能与 softmax 一起使用。

我希望有人能给我一个提示,如何预处理或转换标签数据,以修复代码。我会很感激。 即使是代码 sn-p 也会很棒。

csv 看起来像这样:

Filename  label1  label2  label3  label4  ...   ID
abc1.jpg    1       0       0       1     ...  id-1
def2.jpg    0       1       0       1     ...  id-2
ghi3.jpg    0       0       0       1     ...  id-3
...
import numpy as np
import keras
from keras.layers import *
from keras.models import Sequential

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'
    def __init__(self, list_IDs, labels, batch_size=32, dim=(224,224), n_channels=3,
                 n_classes=21, shuffle=True):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_classes = n_classes
        self.shuffle = shuffle
        self.on_epoch_end()


    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        y = np.empty((self.batch_size, self.n_classes), dtype=int)

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            X[i,] = np.load('Folder with npy files/' + ID + '.npy')

            # Store class
            y[i] = self.labels[ID]

        return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

-----------------------

# Parameters
params = {'dim': (224, 224),
          'batch_size': 32,
          'n_classes': 21,
          'n_channels': 3,
          'shuffle': True}

# Datasets
partition = partition
labels = labels

# Generators
training_generator = DataGenerator(partition['train'], labels, **params)
validation_generator = DataGenerator(partition['validation'], labels, **params)

# Design model
model = Sequential()

model.add(Conv2D(32, (3,3), input_shape=(224, 224, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

...

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dense(21))
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

# Train model on dataset
model.fit_generator(generator=training_generator,
                    validation_data=validation_generator)

【问题讨论】:

    标签: arrays machine-learning keras deep-learning multilabel-classification


    【解决方案1】:

    由于您已经将标签作为 0 和 1 的 21 个元素的向量,因此您不应在函数 __data_generation(self, list_IDs_temp) 中使用 keras.utils.to_categorical。只需返回Xy

    【讨论】:

    • 我已经试过了,但我的损失越来越大。因此我正在寻找一种不同的方法。还是谢谢!
    • @sebk 哦,这是一个不同的问题,与您提到的错误无关。
    • true,错误不会再出现,但执行还是不满意
    • @sebk 您当前的问题根本没有传达您想到的问题。请提出一个关于损失没有改善的新问题。这样的东西对你有用:stats.stackexchange.com/questions/207794/…
    • 嘿,阿基拉,这与损失无关,更多的是关于我如何以何种方式将数据传递给 DataGenerator。我的问题是关于预处理,我问“我希望有人能给我一个提示如何预处理或转换标签数据......”无论如何谢谢你:)
    【解决方案2】:

    好的,我有一个解决方案,但我不确定这是最好的.. :

    from sklearn import preprocessing #for LAbelEncoder
    
    
    labels_list = [x[1] for x in labels.items()] #get the list of all sequences
    
    def convert(list):  
        res = int("".join(map(str, list)))
    
        return res
    
    label_int = [convert(i) for i in labels_list] #Convert each sequence to int 
    
    print(label_int) #E.g : [1,2,3] become 123
    
    
    le = preprocessing.LabelEncoder()
    le.fit(label_int)
    labels = le.classes_   #Encode each int to only get the uniques
    print(labels)
    d = dict([(y,x) for x,y in enumerate(labels)])   #map each unique sequence to an label like 0, 1, 2, 3 ...
    print(d)
    
    labels_encoded = [d[i] for i in label_int]  #get all the sequence and encode them with label obtained 
    print(labels_encoded)
    
    labels_encoded = to_categorical(labels_encoded) #encode to_cagetorical 
    print(labels_encoded)
    

    我认为这不是很干净,但它正在工作

    您需要更改最后一个 Dense 层,使其神经元数量等于标签编码序列的长度。

    对于预测,您将拥有将预测值映射到原始序列样式的字典“d”。

    如果您需要澄清,请告诉我!

    对于一些测试序列,它为您提供:

    labels = {'id-0': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
              'id-1': [0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
              'id-2': [0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
              'id-3': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
              'id-4': [0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]}
    
    [100100001100000001011, 10100001100000000001, 100001100010000001, 100100001100000001011, 10100001100000000001]
    [100001100010000001 10100001100000000001 100100001100000001011]
    {100001100010000001: 0, 10100001100000000001: 1, 100100001100000001011: 2}
    [2, 1, 0, 2, 1]
    [[0. 0. 1.]
     [0. 1. 0.]
     [1. 0. 0.]
     [0. 0. 1.]
     [0. 1. 0.]]
    

    澄清后编辑:

    好的,我阅读了有关该主题的更多信息,softmax 的问题再次是它会尝试最大化一个类而最小化其他类。
    因此,我建议保留 21 个 1 和 0 的数组,但不要使用Softmax,而是使用Sigmoid(预测每个类的0到1之间的概率)和binary_crossentropy

    并使用阈值进行预测:

    preds = model.predict(X_test)
    preds[preds>=0.5] = 1
    preds[preds<0.5] = 0
    

    让我知道结果!

    【讨论】:

    • 标签用于图像识别。例如,如果label1(序列中的第一个数字)表示,图像中是一座山,如果有0,则没有山。如果 label2 表示太阳并且第二个数字是 1,则图像中有太阳……我希望这是可以理解的。
    • 我想遵循您之前提到的评论:从您的 21 个标签 [0,1,2,3, ..] 开始,然后您对该数组进行 one_hot 编码并将其提供给您的网络。我只是不知道如何像你建议的那样塑造我的数据......
    • 我昨天深夜也发现了这个 sigmoid 选项 :)。无论如何,代码的性能不如预期的那么强。我添加了批处理规范,尝试了 dropout 并更改了模型的架构几次。 acc 的最佳结果是 71%,这一点也不令人惊讶……我会检查我的输入数据和 hpoe 以找到错误……
    • 一些提高性能的提示:尝试其他优化器(adam ?),查看训练和验证损失曲线是否存在潜在的过拟合/欠拟合,更改学习率,增加网络的复杂性(更多转换,更多块,残余块,挤压和激发块等),添加更多数据,如果尚未完成图像预处理......如果需要,您可以共享您的网络,我可以看看潜在的改进!
    猜你喜欢
    • 2017-03-26
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多