[英]Using multi-output labels in keras ImageDataGenerator.flow() and using model.fit_generator()
I have a single-input,multi-output Neural Network model whose last layers are我有一个单输入、多输出的神经网络模型,它的最后一层是
out1 = Dense(168, activation = 'softmax')(dense)
out2 = Dense(11, activation = 'softmax')(dense)
out3 = Dense(7, activation = 'softmax')(dense)
model = Model(inputs=inputs, outputs=[out1,out2,out3])
the Y-labels for each image are as follows每个图像的 Y 标签如下
train
>>
image_id class_1 class_2 class_3
0 Train_0 15 9 5
1 Train_1 159 0 0
...
...
...
453651 Train_453651 0 15 34
453652 Train_453652 18 0 7
EDIT:-编辑:-
train.iloc[:,1:4].nunique()
>>
class_1 168
class_2 11
class_3 7
dtype: int64
So looking at these different range of classes, should I use categorical_crossentropy
or sparse_categorical_crossentropy
?所以看看这些不同范围的类,我应该使用categorical_crossentropy
还是sparse_categorical_crossentropy
? and how should I use the Y_labels
in flow for the code given below?我应该如何在下面给出的代码中使用流中的Y_labels
?
imgs_arr = df.iloc[:,1:].values.reshape(df.shape[0],137,236,1)
# 32332 columns representing pixels of 137*236 and single channel images.
# converting it to (samples,w,h,c) format
Y = train.iloc[:,1:].values #need help from here
image_data_gen = ImageDataGenerator(validation_split=0.25)
train_gen = image_data_gen.flow(x=imgs_arr, y=Y, batch_size=32,subset='training')
valid_gen = image_data_gen.flow(x=imgs_arr,y=Y,subset='validation')
is this this the right way to pass Y
or use Y=[y1,y2,y3]
where这是传递Y
或使用Y=[y1,y2,y3]
的正确方法Y=[y1,y2,y3]
y1=train.iloc[:,1].values
y2=train.iloc[:,2].values
y3=train.iloc[:,3].values
Ouch....哎哟....
By the message given in your flow
, you will need a single output.根据flow
给出的消息,您将需要一个输出。 So you need to make the separation inside your model.因此,您需要在模型内部进行分离。 (Keras failed to follow its own standards there) (Keras 在那里没有遵循自己的标准)
This means something like:这意味着:
Y = train.iloc[:,1:].values #shape = (50210, 3)
With a single output like:使用单个输出,如:
out = Dense(168+11+7, activation='linear')(dense)
And a loss function that handles the separation:以及处理分离的损失函数:
def custom_loss(y_true, y_pred):
true1 = y_true[:,0:1]
true2 = y_true[:,1:2]
true3 = y_true[:,2:3]
out1 = y_pred[:,0:168]
out2 = y_pred[:,168:168+11]
out3 = y_pred[:,168+11:]
out1 = K.softmax(out1, axis=-1)
out2 = K.softmax(out2, axis=-1)
out3 = K.softmax(out3, axis=-1)
loss1 = K.sparse_categorical_crossentropy(true1, out1, from_logits=False, axis=-1)
loss2 = K.sparse_categorical_crossentropy(true2, out2, from_logits=False, axis=-1)
loss3 = K.sparse_categorical_crossentropy(true3, out3, from_logits=False, axis=-1)
return loss1+loss2+loss3
Compile the model with loss=custom_loss
.使用loss=custom_loss
编译模型。
Then the flow
should stop complaining when you do flow
.那么当你flow
时, flow
应该停止抱怨。
Just make sure X and Y are exactly in the same order: imgs_arr[i]
corresponds to Y[i]
correctly.只需确保 X 和 Y 的顺序完全相同: imgs_arr[i]
Y[i]
正确对应于Y[i]
。
Another workaround is:另一种解决方法是:
Here is the methods to implement the steps above:以下是实现上述步骤的方法:
def make_array_of_tuple(tuple_of_arrays):
array_0 = tuple_of_arrays[0]
array_of_tuple = np.empty(array_0.shape[0], dtype=np.object)
for i, tuple_of_array_elements in enumerate(zip(*tuple_of_arrays)):
array_of_tuple[i] = tuple_of_array_elements
return array_of_tuple
def convert_to_list_of_arrays(array_of_tuple):
array_length = array_of_tuple.shape[0]
tuple_length = len(array_of_tuple[0])
array_list = [
np.empty(array_length, dtype=np.uint8) for i in range(tuple_length) ]
for i, array_element_tuple in enumerate(array_of_tuple):
for array, tuple_element in zip(array_list, array_element_tuple):
array[i] = tuple_element
return array_list
def tuple_of_arrays_flow(original_flow):
while True:
(X, array_of_tuple) = next(original_flow)
list_of_arrays = convert_to_list_of_arrays(array_of_tuple)
yield X, list_of_arrays
To call the ImageDataGenerator flow() method and get the flow used for the model:要调用 ImageDataGenerator flow() 方法并获取用于模型的流:
y_train = make_array_of_tuple((y_train_1, y_train_2, y_train_3))
orig_image_flow = train_image_generator.flow(X_train, y=y_train)
train_image_flow = tuple_of_arrays_flow(orig_image_flow)
The size of y_train is the same as X_train, so it should be accepted. y_train 的大小和 X_train 一样,所以应该可以接受。 'train_image_flow' returns list of arrays that should be accepted by the Keras multi-output model. 'train_image_flow' 返回 Keras 多输出模型应接受的数组列表。
ADDED (2019/01/26)添加(2019/01/26)
One another idea, simpler than the above one:另一种想法,比上面的更简单:
Here is the implementation:这是实现:
def make_multi_output_flow(image_gen, X, y_list, batch_size):
y_item_0 = y_list[0]
y_indices = np.arange(y_item_0.shape[0])
orig_flow = image_gen.flow(X, y=y_indices, batch_size=batch_size)
while True:
(X, y_next_i) = next(orig_flow)
y_next = [ y_item[y_next_i] for y_item in y_list ]
yield X, y_next
This is an example to call the method above.这是调用上述方法的示例。
y_train = [y_train_1, y_train_2, y_train_3]
multi_output_flow = make_multi_output_flow(
image_data_generator, X_train, y_train, batch_size)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.