How to correct input to unet_learner/DataBlock? (previously: What does <listcomp>(.0) mean?)

I have several masks which I turn into 0 and 1 tensors. I create ImageBlock isntance:

field = DataBlock(blocks=(ImageBlock, MaskBlock(keys)),
                get_items=get_image_files,
                splitter=FileSplitter('photos/valid.txt'),
                get_y=get_msk,
                batch_tfms=[*aug_transforms(size=half),
                Normalize.from_stats(*imagenet_stats)])

Where get_msk is lambda function to get all masks from directory
Later I use the field DataBlock when creating dataloaders

dls = field.dataloaders(train_path, bs=2)

I use dls when creating unet_learner:

learn = unet_learner(dls, resnet34, opt_func=ranger, act_cls=Mish, self_attention=True, metrics=acc_camvid)

I encounter the TypeError when trying to get learn.summary()

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-bc39e9e85f86> in <module>
----> 1 learn.summary()

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in summary(self)
    189     "Print a summary of the model, optimizer and loss function."
    190     xb = self.dls.train.one_batch()[:self.dls.train.n_inp]
--> 191     res = module_summary(self, *xb)
    192     res += f"Optimizer used: {self.opt_func}\nLoss function: {self.loss_func}\n\n"
    193     if self.opt is not None:

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in module_summary(learn, *xb)
    166     infos = layer_info(learn, *xb)
    167     n,bs = 64,find_bs(xb)
--> 168     inp_sz = _print_shapes(apply(lambda x:x.shape, xb), bs)
    169     res = f"{learn.model.__class__.__name__} (Input shape: {inp_sz})\n"
    170     res += "=" * n + "\n"

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in _print_shapes(o, bs)
    156 def _print_shapes(o, bs):
    157     if isinstance(o, torch.Size): return ' x '.join([str(bs)] + [str(t) for t in o[1:]])
--> 158     else: return str([_print_shapes(x, bs) for x in o])
    159 
    160 # Cell

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in <listcomp>(.0)
    156 def _print_shapes(o, bs):
    157     if isinstance(o, torch.Size): return ' x '.join([str(bs)] + [str(t) for t in o[1:]])
--> 158     else: return str([_print_shapes(x, bs) for x in o])
    159 
    160 # Cell

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in _print_shapes(o, bs)
    156 def _print_shapes(o, bs):
    157     if isinstance(o, torch.Size): return ' x '.join([str(bs)] + [str(t) for t in o[1:]])
--> 158     else: return str([_print_shapes(x, bs) for x in o])
    159 
    160 # Cell

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in <listcomp>(.0)
    156 def _print_shapes(o, bs):
    157     if isinstance(o, torch.Size): return ' x '.join([str(bs)] + [str(t) for t in o[1:]])
--> 158     else: return str([_print_shapes(x, bs) for x in o])
    159 
    160 # Cell

~/anaconda3/envs/rmnt/lib/python3.8/site-packages/fastai/callback/hook.py in _print_shapes(o, bs)
    156 def _print_shapes(o, bs):
    157     if isinstance(o, torch.Size): return ' x '.join([str(bs)] + [str(t) for t in o[1:]])
--> 158     else: return str([_print_shapes(x, bs) for x in o])
    159 
    160 # Cell

TypeError: 'int' object is not iterable```

In the traceback at the end I see what I understand as recursion: _print_shapes calls itself and after two full cycles it encounters int it throws the typeerror

I would appreciate suggestions how to fix the error. I am guessing that the only way is to escape the recurssion loop is to get to the if part o the _print_shapes method

@RMNT
It is most probably an issue with your inputs.
Can you type x,y=dls.one_batch() and tell us the shape of x and y?

1 Like

Itā€™s totally my inputā€™s fault.

xā€™s shape is (2, 3, 1525, 1150) - dimensions of the mask
yā€™s shape gives error - ā€˜listā€™ object has no attribute ā€˜shapeā€™

After looking deeper into the traceback it looks like _print_shapes doesnā€™t recognise the tuple I pass as a tuple. I am currently trying to figure out how to pass it correctly.

I also looked into what you were asking for. The one_batch() returns res, which is first(res) initiated before. I am having problem finding where the method first() is from.

I printed x and y. Turns out that y consists of 4 paths to masks although I have only 2 so far.

The structure of my directory is the main ā€˜photosā€™ dir with folders inside named some code. Inside each of these folders are two folders named image and mask with the image and its mask respectably.

get_msk mentioned before looks like this
get_msk = lambda o: ['photos/{}/masks/mask{}'.format(x, o.suffix) for x in directories]
directories store the lists of codes mentioned above

Printed y shows
[('photos/S1_VV_D10_AD_median_2019_08_01/masks/mask.tif', 'photos/S1_VV_D10_AD_median_2019_08_01/masks/mask.tif'), ('photos/S1_VH_D10_AD_median_2019_04_01/masks/mask.tif', 'photos/S1_VH_D10_AD_median_2019_04_01/masks/mask.tif')]

@RMNT
get_y function is applied to each individual input image file path separately.
So you should not return a list of the locations of all masks,
rather, you should define the get_msk function in a way, such that you get the mask itself.
Also, Im assuming that one input image has only one mask corresponding to the output?

so, in order to write this function, find out how you can relate the path of an input image to the output mask. Grab any input image path (using get_image_files(train_path)[0]). Now define your get_y function such that it will return the path to the mask, when it gets this path as the input.

Hope it helps,Cheers.
Palaash

1 Like

Yes, one input image has only one mask

I did everything as you suggested: made mask path relate to image path and made get_msk return mask itself but the error persists.
get_msk = lambda o: PILMask.create('photos/{}/masks/mask{}'.format(o.parts[1], o.suffix))
Do you have any ideas what else could cause the issue?

@RMNT
Try returning only the path of the output mask.
Again, to debug, Iā€™d recommend you find the shape of a batch of training data by doing x,y=dls.one_batch() followed by x.shape,y.shape

1 Like

Oh, I misread what get_msk should do. I changed it so it would return the path to the mask. Now x.shape is (1, 3, 1525, 1150) and y.shape is (1, 1525, 1150). As I understand correctly, these are the shapes one_batch should return. x.shape - the shape of the input picture, y.shape - the shape of the mask corresponding to the image. The error persists

It turns out that the problem wss that I had to install fastai from the source with:
pip install git+https://github.com/fastai/fastai pip install git+https://github.com/fastai/fastcore