-
Notifications
You must be signed in to change notification settings - Fork 19.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keras - how to use class_weight with 3D data #3653
Comments
You should use |
Hi, I have the same problem. I don't understand how this can be accomplished by using |
Hi, I also could not get how to use sample_weight for class weighting. Because keras requires that length of the sample_weight should be the same as that of the first dimension of the class labels. But, class labels have also second and third dimensions for image height and width. And to weight the class types, I should weight the pixel labels not just the whole image. Thanks. |
To follow up on this, I got it to work using
I hope that helps. |
Hey @KKOG, I got exactly the same issue, did you find any solution? |
@uschmidt83 But this is not very clear. how did you build you weight vector? Say I have 3 classes, my weight vector size will be equals to the number of pixels in my image, with values being weight_0, weight_1 and weight_2? seems like a waste of space, maybe I'm wrong? |
Hi @rdelassus,
it seems like a waste of space for your particular use case, although I doubt that this actually matters much in practice. However, it also allows much more fine-grained control, which is probably crucial for other applications/models. Sorry for the late reply. |
@uschmidt83 I'm having trouble making this work and wonder if you have an insight. I have 4 classes in a semantic segmentation task, and my class weights are
When I put this in
When I change
The shapes in the final portions of the model are
Do you have any suggestions to get this to work? |
@mptorr I am facing a similar problem but am stuck elsewhere... However, the way I understand @uschmidt83's suggestion you need to use:
Hope it helps, please let us know how it goes. And if anyone knows more feel free to chime in. ;-) |
Figured out where some changes could happen to make progress in this direction. #6538 (comment) |
@kglspl @mptorr I tried to set the sample weights like suggested. I have a binary pixel-wise classification task that i want to perform that takes in 100x100 images and outputs the same resolution images basically. On final layer I reshape the output so it is the same as in @mptorr arcitecture above. Here is my arch:
Then I try setting sample_weight to this (where 13000 is number of training samples):
But I get this error:
Then I also tried doing this:
But got the following error:
So now I am confused. Buy @mptorr you said you made it work by reshaping the layers. So how exactly did you reshape them and how should I do that in my case? |
@ezisezis
Then reshape your |
@mptorr I figured it out a bit earlier today with the output i have in previous comment, from 100x100 images, i output a (10000,2) shape. I have 13000 training images and then the sample_weight dimensions are (13000,10000) and it works very well. |
I ran into a similar problem, using categorical cross entropy Maybe we can just use a weighted version of it ? What do you think of : Note that:
That way you can give more importance to rare classes |
Could someone post a concise example of this, or perhaps a small pull request in the examples directory? It seems like a number of people would find it very valuable. |
Below is what I meant with some code. It is a bit specific to my use case but it should be easy to adapt I guess. Just tell me if there is something wrong in it. I think that it gives more weight to rare classes. I may have misunderstood the problem
|
@sebastienbaur Thanks, that looks like an eay way to add it in. Be careful though! The raw formulation of cross-entropy in your code can be numerically unstable as commented in the tensorflow mnist example, so that might affect your results with the code above. |
Hi, I am running into the same problem as @ezisezis, using keras 2.0.5 and theano as backend (python 2.7). My goal it to use unet to perform image segmentation but the regions i am trying to segment are of different size. I tried to use sample_weight instead of class weight so I compiled the model accordingly: Here is the input data size:
The size of labels:
The size of input weights
The last layers of my network: conv2d_92 (Conv2D) (None, 6, 256, 256) 33 conv2d_91[0][0] permute_4 (Permute) (None, 256, 256, 6) 0 conv2d_92[0][0] reshape_4 (Reshape) (None, 65536, 6) 0 permute_4[0][0] And finally the error i am getting:
Then I tried the suggestion of @mptorr to reshape your sample_weight to (N, dimx * dimy). Please let me know if you have any suggestion or need more information. |
Dear @potis . If you read carefully what I experienced and how I solved it, then in your case the input_weights shape has to be: (4717,65536) OR, in general - (number_of_images, number_of_pixels_in_img). So, each value in this 2D array is a weight of the class that the pixel belongs to (you dont have to assign 6 values to each pixel, only one - the class's weight). Hope it makes more sense. |
@ezisezis thanks for the response. I guess i was miss interpreting the N as number of classes. |
For anybody else struggling with this, this details a formula to get class weights for pixels. Set your class weightings up like described in the above blog, then set To get your sample weights, multiply each output channel with the corresponding class weight found from the above blog ( Finally, |
Can someone elaborate on that pls? I really dont understand why that is ambigous. |
@ezisezis Thanks a lot for your post, I've been digging into the code for hours and this really did the trick. I still would prefer class_weight to do what is supposed to, but I don't get how should we use it or in which scenario. Thanks in advance :) |
One approach to resolving the ambiguity would be to add support for a property we can attach to a tensor or numpy array that specifies the type of data each dimension in a tensor represents (batch, width, height, depth, class, etc). |
OK! I'll answer to my own comment. My bad, I didn't see the input tuple can indeed be (inputs, target, weights), so this should solve the problem |
@ezisezis Hi, you |
Following @JianbingDong question, does an array with a shape (num_class) works? such that classes are weighted, not pixels |
Iam facing a similar issue...how to set the values for weights(sample and class) if i use sparse categorical cross-entropy?? |
I am skeptic if we need a custom loss function, because keras is embedding weighting and masking in its loss function prototypes inherently (see keras/keras/engine/training.py Line 309 in 58fd1f0
@anilsathyan7 |
Well, this is still an ongoing issue, and drove me nuts for 36 hours, but I've got it figured out for my dataset. For anyone trying to use TensorFlow 2.0 with Keras, and the tf.data.Dataset pipelines, this info may help you, since it worked for me. Here's my basic setup: Input data: RGB images (png format) Goal: I want my model to 'learn' the relevant classes (1-7) and ignore the background / void class (0). To do this, class_weights does nothing... (not even an error when I tried it, it just did nothing). So, I want to use sample_weights with the sample_weight_mode='temporal' to handle pixel-wise 3D weights. To make this all work, I did the following:
This gives 0's for class 0 and 1's for all other classes. However, you can add weights to other classes by using numpy directly instead, for example: would replace the number 4 with your desired weight for the class 4. You could do this for any classes and set others to 1's, or whatever.
(note: the shape was because my data was (320, 320, 1) and I'm not sure the -1 was necessary or if I could've used 1, but it works. Either way, your labels here (prior to batching) need to be 2D). The sample_weights are reshaped a bit differently: (note: the shape of the sample_weight matrix needs to end up (batch_size, 1D tensor) so that it becomes a 2D tensor when given to model.fit(). In my case, I perform batching with tf.data.dataset.batch(), so the added shape value for batch_size gets added at that point.
Following the above steps results in a model successfully training while ignoring the background class, and uses the keras built-in loss function sparse categorical cross entropy. In that loss function, the sample weights are automatically applied to the weights, resulting in weights for class zero being made 0, and all other class weights being unchanged. To perform inference, and have a meaningful prediction image saved to disk, I simply remove the last layer added in step 4 above (the one that reshaped the output) and then load the model and saved weights. Predictions / inference images now have only classes 1-7. Thanks to Keras / TensorFlow for making this challenging as humanly possible, and for allowing this complexity to persist for over 3 years! |
Hi @ylmeng , thanks for your solution! Thanks for your help! |
You can do this without a custom loss function, by changing the y_true values from eg: |
I am not completely sure why this happens but I seemed to have solved this by changing the syntax of the class weights. Instead of using a dict, try this (binary classification example): class_weight=[1, 0.1] It worked for me... |
As this problem was extremely annoying to overcome, After thats done, you can feed the array to the model during fitting it by adding argument sample_weight= your_array_with_sample_weights The function that I created to transform the y_train array into the sample_weights 2D input array is as follows:
It is based on another post on stack exchange, https://datascience.stackexchange.com/a/31542 |
@GitHubUser97 I really like your solution and think it might work for my use case of this problem, but there is one concern I have. I am working with a data generator, so I cannot pre-compute the sample weights. Do you have an idea on how to let Keras generate sample weights on the fly? |
@janwillembuist I think that the answer by @janbrrr is what you are looking for. You can modify your generator to produce array with sample weights on the fly from predefined classes as he did
|
@GitHubUser97, @janbrrr Thanks for your help, I ended up creating a combination of your contributions, which solved my problem in the end! |
No problem, happy to help @janwillembuist :) |
Sure! I am working with a custom generator, a subclassed sample_weights = np.take(np.array(self.class_weights), np.round(y[:, :, :, :, 1]).astype('int')) The class weights I specify in the generator's init method, and for generating the weights I am using the second channel of my one-hot-encoded output. Then, you add the |
As I created it as an issue on stackoverflow before, where I was pointed to this issue, I gave a long answer there! @GitHubUser97, and of course others, you can check it out here |
@graffam Did you open any PR about this since then? |
@aloerch could you expand a bit more on where you are incorporating the following? Are you calculating this externally or inside the tf.data pipeline? A bit more clarification would be very helpful. |
For binary segmentation problems, could we do something like the following (inspired by this tutorial)? def loss_function(real, pred):
mask = tf.math.logical_not(tf.math.equal(real, 0))
loss_ = keras.losses.binary_crossentropy(real, pred)
loss_ = tf.expand_dims(loss_, axis=-1)
mask = tf.cast(mask, dtype=loss_.dtype)
loss_ *= mask
loss_ = tf.nn.compute_average_loss(loss_, global_batch_size=BATCH_SIZE)
mask = tf.nn.compute_average_loss(mask, global_batch_size=BATCH_SIZE)
return loss_/mask
|
Fixes: tensorflow/tensorflow#48714 A workaround for: keras-team/keras#3653 PiperOrigin-RevId: 371482994
Here's a section showing how to get the Huge thanks to @MarkDaoust for this one. |
Sample weight for class imbalances is quite wasteful as mentioned earlier on this thread. One may not feel that when dealing with small datasets but it would become quite clear when dealing with volume data like my case, even 48GB GPUs run out-of-memory. Rather than wasting all the space to define similar values for an entire class incorporated into sample weights, one can write customized loss functions and split the loss function into multiple sums each with a single value for the associated class. Hope this helps those who get into this thread and are dealing with large data volumes like me. |
Hi,
I am using Keras to segment images to road and background pixels. As you can imagine percentage of road pixels are much lower than that of background pixels. Hence, I want to use class_weight= {0:0.05, 1:0.95} while fitting the model so that cnn won't predict every pixel as background. But, when I do this I got the following error:
File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 597, in fit
sample_weight=sample_weight)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1035, in fit
batch_size=batch_size)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 973, in _standardize_user_data
in zip(y, sample_weights, class_weights, self.sample_weight_modes)]
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 387, in standardize_weights
raise Exception('class_weight not supported for '
Exception: class_weight not supported for 3+ dimensional targets.
My training labels are in this form: (number_of_training_samples=10000, number_of_pixels_in_patch=16384, number_of_classes=2). How can I weight the classes in Keras?
Thanks in advance.
The text was updated successfully, but these errors were encountered: