Unet_binary segmentation

lr_find(learn)? notlearn.lr_find()? I guess you can use both, but I am not used to the way you used it.

just saw that this was the way shown in the last lesson… but it is new to me.

Oops - that wasn’t intentional. learn.lr_find is recommended, but both are fine.

learn.lr_find gives the same error:

How may be debug this? I read somewhere we should convert the tensors to cpu and try. I tried doing that for data set and data bunch objects but got error saying the have no attribute as .cpu()

1 Like

I think I have spotted the error. After visualising more of my data I see it is empty somehow:

I changed from bs 8 to 4 and now the finder gave me:

Scrolling all the way at the bottom of the error is :

So I guess there is some mismatch of shapes but don’t know where this happened and why the data was not read fully. There is an accompanying csv, I don’t know if that supplementary or any use for this challenge.

Maybe we should shift this to fastai users

Did you check you masks don’t have values of 0 and 255? That happens sometimes. If that’s the case, you should change the function that opens them to divide by 255. This is done by adding

...datasets(SegmentationDataset)
  .setattr(mask_opener, partial(open_mask, div=True))

in the data block API. You are changing the function used to open the masks (mask_opener) by changing the value of one of its argument (hence the partial) that’s called div to True.

7 Likes

Since there are only two classes, the classes in the masks are exactly 0 and 255…

I was also running into this exact device-side assert error with a binary segmentation problem.

If your binary masks have values of 0 and 255 for the 2 classes like mine do, I can confirm that @sgugger’s suggestion to change the default behavior of mask_opener to div=True fixes that particular problem (by converting class “255” to class “1”).

A few other small points I’ve discovered while fixing this:

  • If you get a cuda runtime error (59) : device-side assert triggered, you have to restart the kernel or you’ll keep getting the same error when you try to create the Learner even after you’ve fixed the label problem.

  • in fastai v1.0.21, the exact data block .set_attr() line that works for me is:
    .set_attr(mask_opener=partial(open_mask, div=True))

  • The order of the functions called in the data block API matter. This works:

data = (src.datasets(SegmentationDataset, classes=codes)
        .set_attr(mask_opener=partial(open_mask, div=True))
        .transform(get_transforms(), size=size, tfm_y=True)
        .databunch(bs=bs)
        .normalize(imagenet_stats))

While this doesn’t:

data = (src.datasets(SegmentationDataset, classes=codes)
        .transform(get_transforms(), size=size, tfm_y=True)
        .set_attr(mask_opener=partial(open_mask, div=True))
        .databunch(bs=bs)
        .normalize(imagenet_stats))
7 Likes

I just pushed div as an argument to SegmentDataset since it seems a lot of people need it. So now,

data = (src.datasets(SegmentationDataset, classes=codes, div=True)
        .transform(get_transforms(), size=size, tfm_y=True)
        .databunch(bs=bs)
        .normalize(imagenet_stats))

should work.

And hi Dave, nice to see you again :wink:

11 Likes

Yup this worked! Thanks

1 Like

That error bothered me for a while. It works now. Thanks

Did anyone try to give a single class because because it is binary(it supposed to predict 0 or 1 for each pixel)?

hello

I am trying to do binary as well.
I am getting this error…Thanks

src = (ImageFileList.from_folder(path_img)
.label_from_func(get_y_fn))
data = (src.datasets(SegmentationDataset, classes=codes)

    .transform(get_transforms(), size=size, tfm_y=True)

    .databunch(bs=bs)

    .normalize(imagenet_stats))

AttributeError Traceback (most recent call last)
in
----> 1 data = (src.datasets(SegmentationDataset, classes=codes)
2 .transform(get_transforms(), size=size, tfm_y=True)
3 .databunch(bs=bs)
4 .normalize(imagenet_stats))

AttributeError: ‘ImageLabelList’ object has no attribute ‘datasets’

1 Like

@sgugger My mask has 0 and 255 as its values(binary segmentation). How do i use div = True for open_mask with SegmentationItemList for that 255 is converted to 1.

1 Like

Just slightly change the source code of SegmentationLabelList in your custom SegmentationLL

class SegmentationLL(ImageItemList):
    def __init__(self, items:Iterator, classes:Collection=None, **kwargs):
        super().__init__(items, **kwargs)
        self.classes,self.loss_func,self.create_func = classes,CrossEntropyFlat(),partial(open_mask, div=True)
        self.c = len(self.classes)

    def new(self, items, classes=None, **kwargs):
        return self.__class__(items, ifnone(classes, self.classes), **kwargs)

Or even shorter:

class SegmentationLL(SegmentationItemList):
    def __init__(self, items:Iterator, classes:Collection=None, **kwargs):
        super().__init__(items, classes, **kwargs)
        self.create_func = partial(open_mask, div=True)
3 Likes

@sgugger I defined a new class in my code as suggested. But i am getting name 'kwarg' is not defined error. Where can i find the definition of kwarg ? What should i do?

It should be kwargs instead kwarg

1 Like

With a double **, I edited my post.

1 Like

@sgugger here is my code used for segmentation. Weirdly i am getting very high validation loss in few epochs while training and dice accuracy are not bad. What could be the reason for this?

class SegmentationLabelList(ImageItemList):
    def __init__(self, items:Iterator, classes:Collection=None, **kwargs):
        super().__init__(items, **kwargs)
        self.classes,self.loss_func,self.create_func = classes,CrossEntropyFlat(),partial(open_mask, div=True)
        self.c = len(self.classes)

    def new(self, items, classes=None, **kwargs):
        return self.__class__(items, ifnone(classes, self.classes), **kwargs)

class SegmentationItemList(ImageItemList):
    def __post_init__(self):
        super().__post_init__()
        self._label_cls = SegmentationLabelList
src = (SegmentationItemList.from_folder(path_img)
   .random_split_by_pct(0.2)
   .label_from_func(get_y_fn, classes=codes))
data = (src.transform(get_transforms(), size=size, tfm_y=True)
    .databunch(bs=bs)
    .normalize(imagenet_stats))
def dice(input:Tensor, targs:Tensor, iou:bool=True)->Rank0Tensor:
    "Dice coefficient metric for binary target. If iou=True, returns iou metric, classic for segmentation problems."
    n = targs.shape[0]
    input = input.argmax(dim=1).view(n,-1)
    targs = targs.view(n,-1)
    intersect = (input*targs).sum().float()
    union = (input+targs).sum().float()
    if not iou: return 2. * intersect / union
    else: return intersect / (union-intersect+1.0)
learn = Learner.create_unet(data, models.resnet34, metrics=dice)
2 Likes