I created a custom bb_pad function.
I did a reshape of the TensorBbox to convert it’s shape from (2,4) into (8,). To do the reshape you told me to add the line “bbox = torch.reshape(bbox,-1)”, but after this line was executed I got an error saying the second parameter of reshape (-1) can’t be an int, it must be a tuple of ints. On the website you attached (torch.reshape — PyTorch 1.11.0 documentation) it indicates that the second parameter of the reshape function (new shape) must be a tuple of ints.
I changed “bbox = torch.reshape(bbox,-1)” to “bbox = torch.reshape(bbox,(-1,))” and the error I was having was fixed.
I also created a custom BboxBlock with no labels, as I don’t need the bboxes to be labeled and because also I think making the bboxes labeled is a problem because for each image I need to have the bboxes with size (8,) but the labels list have size (2,), so, the sizes don’t match. To create the custom BboxBlock I followed the example shown at Share your V2 projects here - #376 by idraja.
I deleted each line of the original bb_pad function() related to the labels because I only need to return from that function aTensorImage and a TensorBbox. I also don’t use the function clip_remove_empty() because it splits a TensorBbox of size (2,4) into to 2 TensorBbox of size (1,4).
I post the modifications I did on the code:
class NoLabelBBoxLabeler(Transform):
""" Bounding box labeler with no label """
def setups(self, x): noop
def decode (self, x, **kwargs):
self.bbox,self.lbls = None,None
return self._call('decodes', x, **kwargs)
def decodes(self, x:TensorBBox):
self.bbox = x
return self.bbox if self.lbls is None else LabeledBBox(self.bbox, self.lbls)
'''
def clip_remove_empty(bbox):
"Clip bounding boxes with image border and label background the empty ones"
"Splits bbox of size (2,4) into to bboxes of size (1,4)"
bbox = torch.clamp(bbox, -1, 1)
empty = ((bbox[...,2] - bbox[...,0])*(bbox[...,3] - bbox[...,1]) <= 0.)
return (bbox[~empty])
'''
def custom_bb_pad(samples, pad_idx=0):
"Function that collect `samples` of bboxes and adds padding with `pad_idx`."
#samples = [(s[0], *clip_remove_empty(*s[1:])) for s in samples] # s[0] is a tuple of TensorImage & TensorBbox, TensorBbox size is (2,4)
#max_len = max([len(s[2]) for s in samples]) # equals to 4 (number of bbox coordinates)
def _f(img,bbox):
#bbox = torch.cat([bbox,bbox.new_zeros(2, 4)])
bbox = torch.reshape(bbox,(-1,)) # convert bboxes tensor to a 1D tensor
return img,bbox
return [_f(*s) for s in samples]
CustomBboxBlock = TransformBlock(type_tfms=TensorBBox.create,
item_tfms=[PointScaler, NoLabelBBoxLabeler], dls_kwargs = {'before_batch': custom_bb_pad})
data = DataBlock(
blocks=(ImageBlock, CustomBboxBlock), # ImageBlock means type of inputs are images; BBoxBlock & BBoxLblBlock = type of targets are BBoxes & their labels
get_items=get_image_files,
n_inp=1, # number of inputs; it's 1 because the only inputs are the rx images (ImageBlock)
get_y=[lambda o: get_bboxes(o.name)], # get_y = targets [bboxes, labels]; get_x = inputs
splitter = RandomSplitter (0.1), # split training/validation; parameter 0.1 means there will be 10% of validation images
batch_tfms= [*aug_transforms(do_flip=False, size=(120,160)), Normalize.from_stats(*imagenet_stats)]
)
I’m stuck trying to fix an error that is produced when the line "dls.show_batch(max_n=20, figsize=(9,6))
" is executed. The error is: “IndexError: Dimension out of range (expected to be in range of [-2, 1], but got 2)”.
As you can see in the stack trace I post at the end the error doesn’t refer to the parts of code I changed, it refers to an internal function. I don’t know what is causing the error.
I also thought about creating a 2D ouput of the CNN as we commented but I don’t know how to do it, I haven’t found any documentation regarding creating a 2D ouput model. I also tried to find examples of Binary Object Detection as it’s my case on Github or a repository about lungs detection and I haven’t found anything.
I hope you or anybody can tell me what is causing the error and if the changes I did are right.
I also would appreciate if @idraja, that is the user who created the example using the BboxBlock with no labels can help me solve the error of show_batch function.
The stack trace is:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_14288\2938148043.py in <module>
2
3 dls = data.dataloaders(path_dl, path=path_dl, bs = 64) # bs: how many samples per batch to load
----> 4 dls.show_batch(max_n=20, figsize=(9,6)) # NOTE: what do the values of figsize represent?
5 # NOTE: The batch shown contains validation and training images?
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in show_batch(self, b, max_n, ctxs, show, unique, **kwargs)
98 old_get_idxs = self.get_idxs
99 self.get_idxs = lambda: Inf.zeros
--> 100 if b is None: b = self.one_batch()
101 if not show: return self._pre_show_batch(b, max_n=max_n)
102 show_batch(*self._pre_show_batch(b, max_n=max_n), ctxs=ctxs, max_n=max_n, **kwargs)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in one_batch(self)
146 def one_batch(self):
147 if self.n is not None and len(self)==0: raise ValueError(f'This DataLoader does not contain any batches')
--> 148 with self.fake_l.no_multiproc(): res = first(self)
149 if hasattr(self, 'it'): delattr(self, 'it')
150 return res
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in first(x, f, negate, **kwargs)
553 x = iter(x)
554 if f: x = filter_ex(x, f=f, negate=negate, gen=True, **kwargs)
--> 555 return next(x, None)
556
557 # Cell
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in __iter__(self)
109 for b in _loaders[self.fake_l.num_workers==0](self.fake_l):
110 if self.device is not None: b = to_device(b, self.device)
--> 111 yield self.after_batch(b)
112 self.after_iter()
113 if hasattr(self, 'it'): del(self.it)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in __call__(self, o)
198 self.fs = self.fs.sorted(key='order')
199
--> 200 def __call__(self, o): return compose_tfms(o, tfms=self.fs, split_idx=self.split_idx)
201 def __repr__(self): return f"Pipeline: {' -> '.join([f.name for f in self.fs if f.name != 'noop'])}"
202 def __getitem__(self,i): return self.fs[i]
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in compose_tfms(x, tfms, is_enc, reverse, **kwargs)
148 for f in tfms:
149 if not is_enc: f = f.decode
--> 150 x = f(x, **kwargs)
151 return x
152
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\vision\augment.py in __call__(self, b, split_idx, **kwargs)
33 def __call__(self, b, split_idx=None, **kwargs):
34 self.before_call(b, split_idx=split_idx)
---> 35 return super().__call__(b, split_idx=split_idx, **kwargs) if self.do else b
36
37 # Cell
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in __call__(self, x, **kwargs)
71 @property
72 def name(self): return getattr(self, '_name', _get_name(self))
---> 73 def __call__(self, x, **kwargs): return self._call('encodes', x, **kwargs)
74 def decode (self, x, **kwargs): return self._call('decodes', x, **kwargs)
75 def __repr__(self): return f'{self.name}:\nencodes: {self.encodes}decodes: {self.decodes}'
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in _call(self, fn, x, split_idx, **kwargs)
81 def _call(self, fn, x, split_idx=None, **kwargs):
82 if split_idx!=self.split_idx and self.split_idx is not None: return x
---> 83 return self._do_call(getattr(self, fn), x, **kwargs)
84
85 def _do_call(self, f, x, **kwargs):
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in _do_call(self, f, x, **kwargs)
88 ret = f.returns(x) if hasattr(f,'returns') else None
89 return retain_type(f(x, **kwargs), x, ret)
---> 90 res = tuple(self._do_call(f, x_, **kwargs) for x_ in x)
91 return retain_type(res, x)
92
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in <genexpr>(.0)
88 ret = f.returns(x) if hasattr(f,'returns') else None
89 return retain_type(f(x, **kwargs), x, ret)
---> 90 res = tuple(self._do_call(f, x_, **kwargs) for x_ in x)
91 return retain_type(res, x)
92
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\transform.py in _do_call(self, f, x, **kwargs)
87 if f is None: return x
88 ret = f.returns(x) if hasattr(f,'returns') else None
---> 89 return retain_type(f(x, **kwargs), x, ret)
90 res = tuple(self._do_call(f, x_, **kwargs) for x_ in x)
91 return retain_type(res, x)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\dispatch.py in __call__(self, *args, **kwargs)
116 elif self.inst is not None: f = MethodType(f, self.inst)
117 elif self.owner is not None: f = MethodType(f, self.owner)
--> 118 return f(*args, **kwargs)
119
120 def __get__(self, inst, owner):
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\vision\augment.py in encodes(self, x)
399 def encodes(self, x:TensorImage): return self._encode(x, self.mode)
400 def encodes(self, x:TensorMask): return self._encode(x, self.mode_mask)
--> 401 def encodes(self, x:(TensorPoint, TensorBBox)): return self._encode(x, self.mode, reverse=True)
402
403 # Cell
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\vision\augment.py in _encode(self, x, mode, reverse)
395 def _encode(self, x, mode, reverse=False):
396 coord_func = None if len(self.coord_fs)==0 or self.split_idx else partial(compose_tfms, tfms=self.coord_fs, reverse=reverse)
--> 397 return x.affine_coord(self.mat, coord_func, sz=self.size, mode=mode, pad_mode=self.pad_mode, align_corners=self.align_corners)
398
399 def encodes(self, x:TensorImage): return self._encode(x, self.mode)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\vision\augment.py in affine_coord(x, mat, coord_tfm, sz, mode, pad_mode, align_corners)
347 if sz is None: sz = getattr(x, "img_size", None)
348 bs,n = x.shape[:2]
--> 349 pnts = stack([x[...,:2], stack([x[...,0],x[...,3]],dim=2),
350 stack([x[...,2],x[...,1]],dim=2), x[...,2:]], dim=2)
351 pnts = TensorPoint(pnts.view(bs, 4*n, 2), img_size=sz).affine_coord(mat, coord_tfm, sz, mode, pad_mode)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\torch_core.py in __torch_function__(self, func, types, args, kwargs)
338 convert=False
339 if _torch_handled(args, self._opt, func): convert,types = type(self),(torch.Tensor,)
--> 340 res = super().__torch_function__(func, types, args=args, kwargs=kwargs)
341 if convert: res = convert(res)
342 if isinstance(res, TensorBase): res.set_meta(self, as_copy=True)
~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\_tensor.py in __torch_function__(cls, func, types, args, kwargs)
1140
1141 with _C.DisableTorchFunction():
-> 1142 ret = func(*args, **kwargs)
1143 if func in get_default_nowrap_functions():
1144 return ret
IndexError: Dimension out of range (expected to be in range of [-2, 1], but got 2)