Gland segmentation using Lesson 3 fastai v1

I want to apply the learning of Lesson3 to gland segmentation. The dataset is comming from https://warwick.ac.uk/fac/sci/dcs/research/tia/glascontest/about/
But I am getting this error, but I don’t know why ? Everything before this step works fine.
learn.lr_find()

The error
--------------------------------------------------------------------------
ValueError Traceback (most recent call last)
in ()
1 learn.loss_func=CrossEntropyFlat()
----> 2 learn.lr_find()

/usr/local/lib/python3.6/dist-packages/fastai/train.py in lr_find(learn, start_lr, end_lr, num_it, stop_div, **kwargs)
 28     cb = LRFinder(learn, start_lr, end_lr, num_it, stop_div)
 29     a = int(np.ceil(num_it/len(learn.data.train_dl)))
---> 30     learn.fit(a, start_lr, callbacks=[cb], **kwargs)
 31 
 32 def to_fp16(learn:Learner, loss_scale:float=512., flat_master:bool=False)->Learner:

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(self, epochs, lr, wd, callbacks)
160         callbacks = [cb(self) for cb in self.callback_fns] + listify(callbacks)
161         fit(epochs, self.model, self.loss_func, opt=self.opt, data=self.data, metrics=self.metrics,
--> 162             callbacks=self.callbacks+callbacks)
163 
164     def create_opt(self, lr:Floats, wd:Floats=0.)->None:

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
 92     except Exception as e:
 93         exception = e
---> 94         raise e
 95     finally: cb_handler.on_train_end(exception)
 96 

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
 82             for xb,yb in progress_bar(data.train_dl, parent=pbar):
 83                 xb, yb = cb_handler.on_batch_begin(xb, yb)
---> 84                 loss = loss_batch(model, xb, yb, loss_func, opt, cb_handler)
 85                 if cb_handler.on_batch_end(loss): break
 86 

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in loss_batch(model, xb, yb, loss_func, opt, cb_handler)
 20 
 21     if not loss_func: return to_detach(out), yb[0].detach()
---> 22     loss = loss_func(out, *yb)
 23 
 24     if opt is not None:

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs)
487             result = self._slow_forward(*input, **kwargs)
488         else:
--> 489             result = self.forward(*input, **kwargs)
490         for hook in self._forward_hooks.values():
491             hook_result = hook(self, input, result)

/usr/local/lib/python3.6/dist-packages/fastai/layers.py in forward(self, input, target)
117     def forward(self, input:Tensor, target:Tensor) -> Rank0Tensor:
118         n,c,*_ = input.shape
--> 119         return super().forward(input.view(n, c, -1), target.view(n, -1))
120 
121 class MSELossFlat(nn.MSELoss):

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/loss.py in forward(self, input, target)
865     def forward(self, input, target):
866         return F.cross_entropy(input, target, weight=self.weight,
--> 867                                ignore_index=self.ignore_index, reduction=self.reduction)
868 
869 

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce, reduction)
   1920     if size_average is not None or reduce is not None:
   1921         reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 1922     return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
   1923 
   1924 

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)
   1773         if target.size()[1:] != input.size()[2:]:
   1774             raise ValueError('Expected target size {}, got {}'.format(
-> 1775                 out_size, target.size()))
   1776         input = input.contiguous().view(n, c, 1, -1)
   1777         target = target.contiguous().view(n, 1, -1)

ValueError: Expected target size (4, 101656), got torch.Size([4, 101007])

Please share more of your code as the bug comes from your data. Here the target isn’t the same size as your input.

@sgugger you can find my code here : https://colab.research.google.com/drive/1BeJGD6oZOVJTFkkseBYIQwSFnQG2nhzu

Hi @sgugger, did you have time to look at my code?

Try using a different metric other than accuracy such as iou or dice. The accuracy metric does not work on image segmentation.

When I use dice or IoU

def dice(pred, targs):
    pred = (pred>0).float()
    return 2.0 * (pred*targs).sum() / ((pred+targs).sum() + 1.0)

def IoU(pred, targs):
    pred = (pred>0).float()
    intersection = (pred*targs).sum()
    return intersection / ((pred+targs).sum() - intersection + 1.0)

I have this error :

ValueError                                Traceback (most recent call last)
<ipython-input-46-d81c6bd29d71> in <module>()
----> 1 learn.lr_find()

/usr/local/lib/python3.6/dist-packages/fastai/train.py in lr_find(learn, start_lr, end_lr, num_it, stop_div, **kwargs)
     29     cb = LRFinder(learn, start_lr, end_lr, num_it, stop_div)
     30     a = int(np.ceil(num_it/len(learn.data.train_dl)))
---> 31     learn.fit(a, start_lr, callbacks=[cb], **kwargs)
     32 
     33 def to_fp16(learn:Learner, loss_scale:float=512., flat_master:bool=False)->Learner:

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(self, epochs, lr, wd, callbacks)
    164         callbacks = [cb(self) for cb in self.callback_fns] + listify(callbacks)
    165         fit(epochs, self.model, self.loss_func, opt=self.opt, data=self.data, metrics=self.metrics,
--> 166             callbacks=self.callbacks+callbacks)
    167 
    168     def create_opt(self, lr:Floats, wd:Floats=0.)->None:

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
     92     except Exception as e:
     93         exception = e
---> 94         raise e
     95     finally: cb_handler.on_train_end(exception)
     96 

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
     82             for xb,yb in progress_bar(data.train_dl, parent=pbar):
     83                 xb, yb = cb_handler.on_batch_begin(xb, yb)
---> 84                 loss = loss_batch(model, xb, yb, loss_func, opt, cb_handler)
     85                 if cb_handler.on_batch_end(loss): break
     86 

/usr/local/lib/python3.6/dist-packages/fastai/basic_train.py in loss_batch(model, xb, yb, loss_func, opt, cb_handler)
     20 
     21     if not loss_func: return to_detach(out), yb[0].detach()
---> 22     loss = loss_func(out, *yb)
     23 
     24     if opt is not None:

/usr/local/lib/python3.6/dist-packages/fastai/layers.py in __call__(self, input, target, **kwargs)
    175         if self.floatify: target = target.float()
    176         input = input.view(-1,input.shape[-1]) if self.is_2d else input.view(-1)
--> 177         return self.func.__call__(input, target.view(-1), **kwargs)
    178 
    179 def CrossEntropyFlat(*args, axis:int=-1, **kwargs):

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs)
    487             result = self._slow_forward(*input, **kwargs)
    488         else:
--> 489             result = self.forward(*input, **kwargs)
    490         for hook in self._forward_hooks.values():
    491             hook_result = hook(self, input, result)

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/loss.py in forward(self, input, target)
    902     def forward(self, input, target):
    903         return F.cross_entropy(input, target, weight=self.weight,
--> 904                                ignore_index=self.ignore_index, reduction=self.reduction)
    905 
    906 

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce, reduction)
   1968     if size_average is not None or reduce is not None:
   1969         reduction = _Reduction.legacy_get_string(size_average, reduce)
-> 1970     return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
   1971 
   1972 

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)
   1786     if input.size(0) != target.size(0):
   1787         raise ValueError('Expected input batch_size ({}) to match target batch_size ({}).'
-> 1788                          .format(input.size(0), target.size(0)))
   1789     if dim == 2:
   1790         ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)

ValueError: Expected input batch_size (406624) to match target batch_size (404028).

Encountering the same problem on a new dataset, after a couple of hours of hair-tearing-out, it seems this is due to unet incompatibility with odd-pixel dimensions images, such as your gland scans. I was able to get my dataset working by first ensuring h and w were multiples of 2. My guess would be some padding effect with up/downsample causes this.

You can recreate the error in the lesson3-camvid notebook by changing size = src_size//2 to size = src_size//2+1. @sgugger is this a limitation we are stuck with or can it be handled more gracefully in the library?

2 Likes

Ah makes sense! Yes you need to resize everything to a multiple of 32 to be on the safe side. We’ll work on fixing the padding.

2 Likes

You should modify your code like this:

class MySegmentationLabelList(SegmentationLabelList):
  def open(self, fn): return open_mask(fn, div=True)

class MySegmentationItemList(ImageItemList):
    "`ItemList` suitable for segmentation tasks."
    _label_cls,_square_show_res = MySegmentationLabelList,False

And the load the data:

src = (MySegmentationItemList.from_folder(PATH/TRAIN_DN)
    .split_by_files(valid_fnames)
    .label_from_func(get_y_fn , classes=classes))


tfms = get_transforms()


data = (src.transform(tfms, size=size, tfm_y=True)
        .databunch(bs=bs, num_workers=4)
        .normalize(imagenet_stats))
1 Like