keras: Multi label classification with binary_crossentropy and class_weight - must contain all classes error
Hello,
I have run into an issue with class_weights and binary_crossentropy for multi label outputs.
In essence: Output is an ndarray Y with Y.shape[1] the number of label outputs, e.g.: [[0,0,1,0,1,1,0], [0,0,1,0,1,1,1], … [0,0,0,0,1,0,0]]
I have defined the output layer as follows (method A):
...
out_dense=Dense(Y.shape[1],
activation='sigmoid', name='OUTPUT_BINARY')(intermediate_dense)
and defined the model:
model = Model(inputs=[... some inputs...], outputs=out_dense)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
weight dictionary defined as follows:
W = {0.0: 0.54356142358280057, 1.0: 6.2390227278685089}
Now, when I fit:
model.fit([...some inputs...], Y, batch_size=64, epochs=1, validation_split=0.25, class_weight={'OUTPUT_BINARY':W}, sample_weight=None)
I get the error:
/usr/local/lib/python3.5/dist-packages/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, **kwargs)
1521 check_batch_axis=False,
1522 batch_size=batch_size)
-> 1523 # Prepare validation data.
1524 do_validation = False
1525 if validation_data:
/usr/local/lib/python3.5/dist-packages/keras/engine/training.py in _standardize_user_data(self, x, y, sample_weight, class_weight, check_batch_axis, batch_size)
1388 for (ref, sw, cw, mode)
1389 in zip(y, sample_weights, class_weights, self._feed_sample_weight_modes)]
-> 1390 _check_array_lengths(x, y, sample_weights)
1391 _check_loss_and_target_compatibility(y,
1392 self._feed_loss_fns,
/usr/local/lib/python3.5/dist-packages/keras/engine/training.py in <listcomp>(.0)
1387 sample_weights = [_standardize_weights(ref, sw, cw, mode)
1388 for (ref, sw, cw, mode)
-> 1389 in zip(y, sample_weights, class_weights, self._feed_sample_weight_modes)]
1390 _check_array_lengths(x, y, sample_weights)
1391 _check_loss_and_target_compatibility(y,
/usr/local/lib/python3.5/dist-packages/keras/engine/training.py in _standardize_weights(y, sample_weight, class_weight, sample_weight_mode)
556 '`class_weight`.'
557 % (existing_classes - existing_class_weight))
--> 558 return weights
559 else:
560 if sample_weight_mode is None:
ValueError: `class_weight` must contain all classes in the data. The classes {2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 17, 19, 20, 21, 28, 29, 31, 34, 36, 37, 38, 41, 43, 44, 45, 47} exist in the data but not in `class_weight`.
I have traced it to :
def _standardize_weights(y, sample_weight=None, class_weight=None,
sample_weight_mode=None):
...
if y.shape[1] > 1:
y_classes = y.argmax(axis=1)
elif y.shape[1] == 1:
y_classes = np.reshape(y, y.shape[0])
else:
y_classes = y
in training.py.
It seems that here keras sees the output as a softmax type one hot encoded and returns the index of the maximum for each row.
The only way I saw to fix this was to create multiple single outputs by using a for loop (method B):
outputs=[]
l_weights=[]
for i in range(y_in_service_indicator.shape[1]):
out_dense=Dense(1, activation='sigmoid', name='O_'+str(1+i))(intermediate_dense)
outputs.append(out_dense)
l_weights.append(1.0)
model = Model([...some inputs...], outputs=outputs)
model.compile(loss='binary_crossentropy', loss_weights=l_weights,
optimizer='adam', metrics=['accuracy'])
(I appreciate may not need the loss weights) and define the outputs as :
y_s_binary = []
for i in list(range(Y.shape[1])):
y_s_binary.append(y_in_service_indicator[:,i])
and now fit:
model.fit(X_intervals, y_s_binary, batch_size=64, epochs=1, validation_split=0.25,
class_weight={'OUTPUT_BINARY':W}, sample_weight=None)
This works, but it feels to me like I am missing somehting - would appreciate input on how to make Keras work with single defined Y ndarray and model output as in method A.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 13
- Comments: 17
Keras has fix this problem.This issue should be closed.
Multilabel : Binary Classification : Class weights for biased data. I have similar issue as mentioned in the thread. Wondered if a solution now exists ? My Y is of of shape : [[0,0,0,1], [0,1,0,0], [1,1,1,0] … [0,1,1,1]]
So its multilabel : binary classification with biased Data.
hi @alanlisten, is there any corresponding new api in keras? i get a similar error when setting the class weight with keras version 2.2.0. And my Y is something like:
[[1,0,0,1], [1,1,0,0] [1,0,1,0]]
so for this multi-label problem i setclass_weight={0.0:0.6,1.0:0.4}
in the model.fit() function,and i get an error message says:ValueError:
class_weightmust contain all classes in the data. The classes {2, 3} exist in the data but not in
class_weight.
,@sharifza Of course. That’s why this bug is open.
Here’s a workaround (see a discussion on StackOverflow): add two artificial classes in
out_dense
in positions0
and1
and makeAll actual classes start from index
2
onward. This will force keras think that there are 2 classes.