bragancas / VNet_PyTorch-Atriaseg2018

An image segmentation project using PyTorch to segment the Left Atrium in 3D Late gadolinium enhanced - cardiac MR images of the human heart.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SurfaceLoss:'function' object has no attribute 'shape'

pangda72 opened this issue · comments

commented

Hi,@bragancas

Thank you for sharing such a great repo.I have some confusion about the loss, could you give me some help ?

Q1: In the utils.py,focal_loss = (1+(label199)) * (1 - pt) ** self.gamma * BCE.Actually,focal_loss = self.alpha * (1 - pt) ** self.gamma * BCE,
I don't know why alpha=(1+(label
199)) ,Could you give me some guidance?

Q2:When I use SurfaceLoss,I got a error:'function' object has no attribute 'shape' ,I don't know how to solve this bug. Could you give me some help ?

Thanks in advance.
Looking forward your reply.
Best.

Hey @pangda72

Glad you like the repo, hope its of good use to you!

A1: Yes you're right about Focal Loss. You should probably use 'focal_loss = self.alpha * (1 - pt) ** self.gamma * BCE' (of course dependent to your use case).

I was experimenting with weighting my calculated loss dependent on the ground truth label values and used alpha = (1+ ('1' * 199)) to assign a higher weightage where label values were '1' and alpha = (1+ ('0' * 199)) == 1 where ground truth label was '0'.

A2: I think the error occurs at 'Line 321' of utils.py . This bit of code ensures that the prediction tensor must be of the same shape as the distance map tensor, so as to calculate the batch_surface_loss variable properly.

I could be wrong, but I think this error occurs as the input you are supplying to the Surface Loss object isn't a tensor and so that input doesn't have the shape attribute. So, check the dtype of the value supplied.

Hope the above helps solve your queries. Let me know if it does so i can close this issue!

commented

Hi,@bragancas

Thank you for your prompt reply and the answer to my confusion.I feel very happy.I'm sorry, I have some new puzzles.Could you give me some help?

(1)I'm using this focal loss to segment medical grayscale images on a private dataset .How do I calculate my own alpha and gamma values like you ?Could you give me some guidance?

(2)I feel very sorry,SurfaceLoss still cannot be run successfully. The input i am supplying to the Surface Loss object is a tensor.I have a puzzle at 'Line 341' of utils.py. At 'Line 474' of train.py, raw_image_patches, label_patches, dist_maps = data,but at 'Line 237' of train.py, raw_image, label = data,I don't know why the former returns three values, and what does dist_maps stand for?
When I want to use surfaceloss,I don't know what should I supply to distance_maps.
#def forward(self, predicted_output, distance_maps):
Also,At 'Line 299' of utils.py,You define a distance_map function,But I can't see where this function is called.Whether it can be annotated,Could you give me some help ?

Thanks in advance.
Best.

A1.
I cannot advise for your dataset what specific value would be better. I suggest trying multiple values and find which works best for your dataset and neural network. I suggest to read the Focal Loss paper to develop an intuition of what effect different gamma values will have on the loss calculation and which value would be more appropriate to your use case.

Briefly, Focal loss paper(doi: 10.1109/TPAMI.2018.2858826), mentions gamma as a hyperparameter that is used to downweight easy to classify predictions(predicted value having probability (Pt) closer to 1, for example-0.88) and upweight harder to classify examples or low confidence predictions (having probability Pt closer to 0, example-0.3). This weighting affects the overall loss and consequently gradient updates, so as to reduce the overall loss by correctly predicting harder to classify pixels and with a higher confidence.

A2.
There are 2 phases in my pipeline which is needed due to the nature of my dataset. The first phase is a locator phase which 'approximately' segments the foreground in any image and the second phase uses this approximate prediction to crop the foreground from the image and perform 'accurate' segmentation on it.

'Line 237' of train.py, raw_image, label = data,,, is part of the approximate segmentation phase and can use Dice Loss 'only', thus no need for any additional variables.
'Line 474' of train.py, raw_image_patches, label_patches, dist_maps = data,,, uses the cropped foreground (foreground patches) and 'can also use Surface Loss' hence the need to provide dist_maps as 3rd variable which is necessary for calculation of surface loss.

dist_maps stands for distance maps which is necessary to calculate the surface loss(refer doi: 10.1016/j.media.2020.101851) && (note: my code for surface loss is an adaptation of the authors code found at - https://github.com/LIVIAETS/boundary-loss/blob/master/utils.py).

-- 'Line 299' of utils.py, distance_map function is used in Lines 145 & 175 of data.py to calculate distance maps of label images.

  • Line 145 for computing distance maps of labels for 'predefined' data augmentation(predefined augmentations performed in Lines 70-73 of utils.py)
  • Line 175 for computing distance maps of labels for 'user provided' data augmentation(augmentation to be provided by user in Lines 418-428 + 430 of train.py and performed in Lines 75-82 of utils.py)
commented

Dear, @bragancas
(1)Thank you for your guidance.I've read Focal Loss paper,and learned a lot from it. Next,I will try multiple values and find which works best for my dataset and neural network as you suggested.
(2)About Surface Loss, thank you for your patient guidance to me. I've run surface loss successfully ,but the results were strange.Sometimes my loss value is greater than 1 and sometimes less than 0, and Valid Loss is always smaller than Train Loss.(red: valid loss ,blue :train loss; x: epoch,y: loss)

loss curve

I don't know what's wrong.,Could you give me some help?
Thanks in advance.
Best.

A2. Yes, this can happen. Its a bit hard to explain this concept, but i'll mention some details in brief.

Surface Loss uses the precomputed (using distance maps) distance between ground truth pixels and predicted pixels and weights the predicted pixels with this distance. Because of the way the precomputed distance maps are calculated and used for gradient updates, there can be instances where a 'local minimum' is achieved. Here, the prediction boundaries correspond to an 'almost empty foreground' causing the calculated overall surface loss to 'add up' to a 'negative value'. This misleads the optimiser and gets stuck in this local minimum. This could be the reason for your loss being less than 0 and also validation loss lesser than training at each iteration.

This can be avoided (more or less) by using the surface loss in conjunction with other region based losses(Dice loss) with a balancing/scheduling factor(check Lines 344-346 of utils.py).

The same reason on how distance maps and consequently surface loss is calculated applies to it having a value greater than 1.

For a better understanding of the concepts and surface loss in general, I suggest you read the authors paper at https://arxiv.org/abs/1812.07032. Page 7 and Page 12 has information about the cause of empty foreground and consequently negative loss value. Additionally, I suggest to check the first authors presentation at https://www.youtube.com/watch?v=_z6gmFlD_qE . Should help in understanding the paper and the loss formulation better.

Also, you probably should use a different metric to measure the segmentation accuracy of your model such as Dice Score or Haussdorff distance, etc instead of measuring via surface loss.

commented

Hi,@bragancas

Thanks a bunch !
I have read the authors paper ,and have a further understanding with surface loss because of your help. At the same time, I also tried to change the loss into the HybridLoss loss(Dice loss+surface loss) and use a different metric to measure the segmentation accuracy of my model such as Dice Score or Haussdorff distance, etc instead of measuring via surface loss as you suggested.But the result is worse than what I did with dice loss only,maybe I didn't set the alpha value properly. Next,I will try multiple values and find which works best for my dataset and neural network ,but I have a confusion,Why alpha is not a specific value (e.g.0.7,0.5....), but a variable value( Lines 595-596 of trian.py),Could you tell me the reason for doing so?
Thank you very much.

Best.

This is the balancing/scheduling factor implementation. Sorry i forgot to mention this in addition to Lines 344-346 of utils.py.

Depending on your dataset you might have to tweak the values for alpha max at start iteration and alpha min after several iterations. I suggest starting with a higher alpha for Dice Loss and move towards a mixture of the two losses towards the final iterations. Although keep in mind it is possible that this loss function might not be effective for your dataset.

Good Luck!

commented

Hi,@bragancas

Thank you for your suggestions. I'll keep it in mind.At the same time,thank you for sharing such a great repo,I learned a lot from it.You're so nice , patient,and give me a lot of guidance.Thanks a million.

Hope you have a good day.

Best.

Thanks for your kind words! Would appreciate even more if you helped someone out in return!