ValueError:使用序列设置数组元素-将字典中的列表传递给DataGenerator



我正在处理一个keras多标签问题。为了处理大量数据以避免内存问题,我实现了一个自定义数据生成器。

到目前为止,我使用的是一个csv文件,其中包含ID、文件名和相应的标签(总共21个(,看起来像这样:

Filename  label1  label2  label3  label4  ...   ID
abc1.jpg    1       0       0       1     ...  id-1
def2.jpg    1       0       0       1     ...  id-2
ghi3.jpg    1       0       0       1     ...  id-3
...

我把id和标签放在字典中,字典有以下输出:

partition: {'train': ['id-1','id-2','id-3',...], 'validation': ['id-7','id-14','id-21',...]}
labels:    {'id-0': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
'id-1': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
'id-2': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
...}

我所有的图像都被转换成数组并保存在单个npy文件中。id-1.npy,id-2.npy…

然后我执行我的代码:

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 __len__(self):
'Denotes the number of batches per epoch'
return int(np.floor(len(self.list_IDs) / self.batch_size))
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), 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)

并引发以下错误:ValueError:设置具有序列的数组元素

错误的以下部分似乎至关重要:

<ipython-input-58-fedc63607310> in __getitem__(self, index)
31 
32         # Generate data
---> 33         X, y = self.__data_generation(list_IDs_temp)
34 
35         return X, y
<ipython-input-58-fedc63607310> in __data_generation(self, list_IDs_temp)
53 
54             # Store class
---> 55             y[i] = self.labels[ID]
56 
57         return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

一旦我从一开始就用以下内容替换labels,代码就会被执行:

labels = {'id-0': 0,
'id-1': 2,
'id-2': 1,
...}

我仍然想将多个标签传递给DataGenerator,因此我选择在字典中放入一个列表,如开头所示,但这给了我ValueError。如何按照建议将单个ID的多个值传递给DataGenerator?我需要调整什么?一个提示或一段代码我非常感激。

如果我很好地理解你的代码,这里有问题:

y = np.empty((self.batch_size), dtype=int)

您正在创建emty 1D阵列,但在这里:

y[i] = self.labels[ID]

你正在用一个序列填充它:

'id-0': [1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

为了工作,您需要使用batch_size的形状和序列的长度创建标签数组:

y = np.empty((self.batch_size, len(sequence)), dtype=int)

编辑

to_categorical是将分类特征编码为[0,0,0,1],[0],0,1,0]等数组。但你正在喂养序列,而不是分类特征
通过将序列馈送到网络,您不想对其进行one_hot编码,因此请替换:

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

发件人:

return X, y

上次评论中的建议

问题是,你的Softmax激活会试图给正确的类提供最好的分数,但在这里你会给出序列数组,Softmax会用多个"正确的类"来解释:

例如:如果您有3个标签[1,2,3],通过one_hot编码,您将有[1,0,0],[0,1,0],[0],每个编码的标签数组只有一个"1",一个正确的类,softmax将尝试使该类得分尽可能大
但在您的情况下,您给出的数组具有多个"1":有了这个:[1,0,1]softmax不知道哪一类的分数最好。

所以我建议,从21个标签[0,1,2,3,..]开始,然后对这个数组进行one_hot编码,并将其提供给网络
如果你真的需要这个序列,你必须找到其他解决方案!

希望我没事!

最新更新