20.03.2021 Views

Deep-Learning-with-PyTorch

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

390 CHAPTER 13 Using segmentation to find suspected nodules

Since our label_g is effectively a Boolean mask, we can multiply it with our predictions

to get our true positives. Note that we aren’t treating prediction_devtensor as a

Boolean here. A loss defined with it wouldn’t be differentiable. Instead, we’re replacing

the number of true positives with the sum of the predicted values for the pixels

where the ground truth is 1. This converges to the same thing as the predicted values

approach 1, but sometimes the predicted values will be uncertain predictions in the

0.4 to 0.6 range. Those undecided values will contribute roughly the same amount to

our gradient updates, no matter which side of 0.5 they happen to fall on. A Dice coefficient

utilizing continuous predictions is sometimes referred to as soft Dice.

There’s one tiny complication. Since we’re wanting a loss to minimize, we’re going

to take our ratio and subtract it from 1. Doing so will invert the slope of our loss function

so that in the high-overlap case, our loss is low; and in the low-overlap case, it’s

high. Here’s what that looks like in code.

Listing 13.24

training.py:315, .diceLoss

Sums over everything except the batch dimension to

get the positively labeled, (softly) positively detected,

and (softly) correct positives per batch item

def diceLoss(self, prediction_g, label_g, epsilon=1):

diceLabel_g = label_g.sum(dim=[1,2,3])

dicePrediction_g = prediction_g.sum(dim=[1,2,3])

diceCorrect_g = (prediction_g * label_g).sum(dim=[1,2,3])

diceRatio_g = (2 * diceCorrect_g + epsilon) \

/ (dicePrediction_g + diceLabel_g + epsilon)

To make it a loss, we take 1 – Dice

return 1 - diceRatio_g ratio, so lower loss is better.

The Dice ratio. To

avoid problems when we

accidentally have neither

predictions nor labels, we

add 1 to both numerator

and denominator.

We’re going to update our computeBatchLoss function to call self.diceLoss. Twice.

We’ll compute the normal Dice loss for the training sample, as well as for only the pixels

included in label_g. By multiplying our predictions (which, remember, are floating-point

values) times the label (which are effectively Booleans), we’ll get pseudo-predictions that

got every negative pixel “exactly right” (since all the values for those pixels are multiplied

by the false-is-zero values from label_g). The only pixels that will generate loss are the

false negative pixels (everything that should have been predicted true, but wasn’t). This

will be helpful, since recall is incredibly important for our overall project; after all, we can’t

classify tumors properly if we don’t detect them in the first place!

Listing 13.25

training.py:282, .computeBatchLoss

def computeBatchLoss(self, batch_ndx, batch_tup, batch_size, metrics_g,

classificationThreshold=0.5):

input_t, label_t, series_list, _slice_ndx_list = batch_tup

input_g = input_t.to(self.device, non_blocking=True)

label_g = label_t.to(self.device, non_blocking=True)

Transfers

to GPU

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!