Icevision: Unexpected Stack Trace when training w EfficientDet

Created on 3 Oct 2020  路  6Comments  路  Source: airctic/icevision

馃悰 Bug

Unexpected Stack Trace when training w EfficientDet not in Faster-RCNN

Trying to see my previously reported training issue is fixed by #465. Unfortunately another problem cropped up downstream.

To Reproduce
Steps to reproduce the behavior, run this gist
https://gist.github.com/bguan/dbc36933e5a56014f8bdd19da7ede481

Expected behavior
Training should run till the end without issue.

Error
Instead the following Stack Trace happens

error                                     Traceback (most recent call last)
/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_epoch(self)
    190     def _do_epoch(self):
--> 191         self._do_epoch_train()
    192         self._do_epoch_validate()

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_epoch_train(self)
    182         self.dl = self.dls.train
--> 183         self._with_events(self.all_batches, 'train', CancelTrainException)
    184 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in all_batches(self)
    160         self.n_iter = len(self.dl)
--> 161         for o in enumerate(self.dl): self.one_batch(*o)
    162 

/usr/local/lib/python3.8/dist-packages/fastai/data/load.py in __iter__(self)
    101         self.__idxs=self.get_idxs() # called in context of main process (not workers/subprocesses)
--> 102         for b in _loaders[self.fake_l.num_workers==0](self.fake_l):
    103             if self.device is not None: b = to_device(b, self.device)

~/.local/lib/python3.8/site-packages/torch/utils/data/dataloader.py in __next__(self)
    362     def __next__(self):
--> 363         data = self._next_data()
    364         self._num_yielded += 1

~/.local/lib/python3.8/site-packages/torch/utils/data/dataloader.py in _next_data(self)
    970                 data = self._task_info.pop(self._rcvd_idx)[1]
--> 971                 return self._process_data(data)
    972 

~/.local/lib/python3.8/site-packages/torch/utils/data/dataloader.py in _process_data(self, data)
   1013         if isinstance(data, ExceptionWrapper):
-> 1014             data.reraise()
   1015         return data

~/.local/lib/python3.8/site-packages/torch/_utils.py in reraise(self)
    394             msg = KeyErrorMessage(msg)
--> 395         raise self.exc_type(msg)

error: Caught error in DataLoader worker process 3.
Original Traceback (most recent call last):
  File "/home/brian/.local/lib/python3.8/site-packages/torch/utils/data/_utils/worker.py", line 185, in _worker_loop
    data = fetcher.fetch(index)
  File "/home/brian/.local/lib/python3.8/site-packages/torch/utils/data/_utils/fetch.py", line 34, in fetch
    data = next(self.dataset_iter)
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 111, in create_batches
    yield from map(self.do_batch, self.chunkify(res))
  File "/usr/local/lib/python3.8/dist-packages/fastcore/utils.py", line 381, in chunked
    res = list(itertools.islice(it, chunk_sz))
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 124, in do_item
    try: return self.after_item(self.create_item(s))
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 130, in create_item
    def create_item(self, s):  return next(self.it) if s is None else self.dataset[s]
  File "/usr/local/lib/python3.8/dist-packages/icevision/data/dataset.py", line 38, in __getitem__
    data = self.tfm(data)
  File "/usr/local/lib/python3.8/dist-packages/icevision/tfms/transform.py", line 13, in __call__
    tfmed = self.apply(**data)
  File "/usr/local/lib/python3.8/dist-packages/icevision/tfms/albumentations/tfms.py", line 110, in apply
    d = self.tfms(**params)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/core/composition.py", line 176, in __call__
    data = t(force_apply=force_apply, **data)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/core/composition.py", line 240, in __call__
    return self.transforms[0](force_apply=True, **data)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/core/transforms_interface.py", line 87, in __call__
    return self.apply_with_params(params, **kwargs)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/core/transforms_interface.py", line 100, in apply_with_params
    res[key] = target_function(arg, **dict(params, **target_dependencies))
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/augmentations/transforms.py", line 982, in apply
    return F.resize(crop, self.height, self.width, interpolation)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/augmentations/functional.py", line 70, in wrapped_function
    result = func(img, *args, **kwargs)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/augmentations/functional.py", line 211, in resize
    return resize_fn(img)
  File "/home/brian/.local/lib/python3.8/site-packages/albumentations/augmentations/functional.py", line 188, in __process_fn
    img = process_fn(img, **kwargs)
cv2.error: OpenCV(4.4.0) /tmp/pip-req-build-vu_aq9yd/opencv/modules/imgproc/src/resize.cpp:3929: error: (-215:Assertion failed) !ssize.empty() in function 'resize'



During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
<ipython-input-18-dba7405c6bba> in <module>
      1 min_lr, epochs, freeze_epochs = 5e-2, 300, 20
      2 print(f"Running with image size {size} for {freeze_epochs}+{epochs} epochs at min LR {min_lr}")
----> 3 learn.fine_tune(epochs, min_lr, freeze_epochs=freeze_epochs)

/usr/local/lib/python3.8/dist-packages/fastcore/logargs.py in _f(*args, **kwargs)
     54         init_args.update(log)
     55         setattr(inst, 'init_args', init_args)
---> 56         return inst if to_return else f(*args, **kwargs)
     57     return _f

/usr/local/lib/python3.8/dist-packages/fastai/callback/schedule.py in fine_tune(self, epochs, base_lr, freeze_epochs, lr_mult, pct_start, div, **kwargs)
    159     "Fine tune with `freeze` for `freeze_epochs` then with `unfreeze` from `epochs` using discriminative LR"
    160     self.freeze()
--> 161     self.fit_one_cycle(freeze_epochs, slice(base_lr), pct_start=0.99, **kwargs)
    162     base_lr /= 2
    163     self.unfreeze()

/usr/local/lib/python3.8/dist-packages/fastcore/logargs.py in _f(*args, **kwargs)
     54         init_args.update(log)
     55         setattr(inst, 'init_args', init_args)
---> 56         return inst if to_return else f(*args, **kwargs)
     57     return _f

/usr/local/lib/python3.8/dist-packages/fastai/callback/schedule.py in fit_one_cycle(self, n_epoch, lr_max, div, div_final, pct_start, wd, moms, cbs, reset_opt)
    111     scheds = {'lr': combined_cos(pct_start, lr_max/div, lr_max, lr_max/div_final),
    112               'mom': combined_cos(pct_start, *(self.moms if moms is None else moms))}
--> 113     self.fit(n_epoch, cbs=ParamScheduler(scheds)+L(cbs), reset_opt=reset_opt, wd=wd)
    114 
    115 # Cell

/usr/local/lib/python3.8/dist-packages/fastcore/logargs.py in _f(*args, **kwargs)
     54         init_args.update(log)
     55         setattr(inst, 'init_args', init_args)
---> 56         return inst if to_return else f(*args, **kwargs)
     57     return _f

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in fit(self, n_epoch, lr, wd, cbs, reset_opt)
    205             self.opt.set_hypers(lr=self.lr if lr is None else lr)
    206             self.n_epoch = n_epoch
--> 207             self._with_events(self._do_fit, 'fit', CancelFitException, self._end_cleanup)
    208 
    209     def _end_cleanup(self): self.dl,self.xb,self.yb,self.pred,self.loss = None,(None,),(None,),None,None

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    153 
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')
    157         finally:   self(f'after_{event_type}')        ;final()

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_fit(self)
    195         for epoch in range(self.n_epoch):
    196             self.epoch=epoch
--> 197             self._with_events(self._do_epoch, 'epoch', CancelEpochException)
    198 
    199     @log_args(but='cbs')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')
--> 157         finally:   self(f'after_{event_type}')        ;final()
    158 
    159     def all_batches(self):

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in __call__(self, event_name)
    131     def ordered_cbs(self, event): return [cb for cb in sort_by_run(self.cbs) if hasattr(cb, event)]
    132 
--> 133     def __call__(self, event_name): L(event_name).map(self._call_one)
    134 
    135     def _call_one(self, event_name):

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in map(self, f, *args, **kwargs)
    270              else f.format if isinstance(f,str)
    271              else f.__getitem__)
--> 272         return self._new(map(g, self))
    273 
    274     def filter(self, f, negate=False, **kwargs):

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in _new(self, items, *args, **kwargs)
    216     @property
    217     def _xtra(self): return None
--> 218     def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
    219     def __getitem__(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
    220     def copy(self): return self._new(self.items.copy())

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __call__(cls, x, *args, **kwargs)
    197     def __call__(cls, x=None, *args, **kwargs):
    198         if not args and not kwargs and x is not None and isinstance(x,cls): return x
--> 199         return super().__call__(x, *args, **kwargs)
    200 
    201 # Cell

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __init__(self, items, use_list, match, *rest)
    207         if items is None: items = []
    208         if (use_list is not None) or not _is_array(items):
--> 209             items = list(items) if use_list else _listify(items)
    210         if match is not None:
    211             if is_coll(match): match = len(match)

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in _listify(o)
    114     if isinstance(o, list): return o
    115     if isinstance(o, str) or _is_array(o): return [o]
--> 116     if is_iter(o): return list(o)
    117     return [o]
    118 

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __call__(self, *args, **kwargs)
    177             if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
    178         fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> 179         return self.fn(*fargs, **kwargs)
    180 
    181 # Cell

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _call_one(self, event_name)
    135     def _call_one(self, event_name):
    136         assert hasattr(event, event_name), event_name
--> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
    138 
    139     def _bn_bias_state(self, with_bias): return norm_bias_params(self.model, with_bias).map(self.opt.state)

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in <listcomp>(.0)
    135     def _call_one(self, event_name):
    136         assert hasattr(event, event_name), event_name
--> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
    138 
    139     def _bn_bias_state(self, with_bias): return norm_bias_params(self.model, with_bias).map(self.opt.state)

/usr/local/lib/python3.8/dist-packages/fastai/callback/core.py in __call__(self, event_name)
     42                (self.run_valid and not getattr(self, 'training', False)))
     43         res = None
---> 44         if self.run and _run: res = getattr(self, event_name, noop)()
     45         if event_name=='after_fit': self.run=True #Reset self.run to True at each end of fit
     46         return res

/usr/local/lib/python3.8/dist-packages/fastai/callback/tracker.py in after_epoch(self)
     79         if self.every_epoch: self._save(f'{self.fname}_{self.epoch}')
     80         else: #every improvement
---> 81             super().after_epoch()
     82             if self.new_best:
     83                 print(f'Better model found at epoch {self.epoch} with {self.monitor} value: {self.best}.')

/usr/local/lib/python3.8/dist-packages/fastai/callback/tracker.py in after_epoch(self)
     37     def after_epoch(self):
     38         "Compare the last value to the best up to now"
---> 39         val = self.recorder.values[-1][self.idx]
     40         if self.comp(val - self.min_delta, self.best): self.best,self.new_best = val,True
     41         else: self.new_best = False

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __getitem__(self, idx)
    217     def _xtra(self): return None
    218     def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
--> 219     def __getitem__(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
    220     def copy(self): return self._new(self.items.copy())
    221 

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in _get(self, i)
    221 
    222     def _get(self, i):
--> 223         if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
    224         i = mask2idxs(i)
    225         return (self.items.iloc[list(i)] if hasattr(self.items,'iloc')

IndexError: list index out of range

Environment:

  • OS: ubuntu 20.04

    • Python ver 3.8.2 [GCC 9.3.0]

    • torch 1.6.0, torchvision 0.7.0

    • fastai 2.0.13

    • icevision 0.1.6

Additional context
If switch to using Faster-RCNN this will run to completion.

bug

Most helpful comment

It turns out that IceVision relies on Albumentation's default image augmentation which invokes ShiftScaleRotate with shift_limit=0.0625 and scale_limit=0.1 probabilistically so sometimes small boxes may have effective area of 0, or boxes may be pushed to beyond the borders, leading to invalid or 0 area boxes.

My quick fix is to have logic in my custom parser to filter these risky boxes but. Leaving my code fix here so others may find idea for their own dataset should they counter the same problem:

def box_within_bounds(x, y, w, h, width, height, min_margin_ratio, min_width_height_ratio):
    min_width = min_width_height_ratio*width
    min_height = min_width_height_ratio*height
    if w < min_width or h < min_height:
        return False
    top_margin = min_margin_ratio*height
    bottom_margin = height - top_margin
    left_margin = min_margin_ratio*width
    right_margin = width - left_margin
    if x < left_margin or x > right_margin:
        return False
    if y < top_margin or y > bottom_margin:
        return False
    return True

class SubCocoParser(Parser, LabelsMixin, BBoxesMixin, FilepathMixin, SizeMixin):
    def __init__(self, stats:CocoDatasetStats, min_margin_ratio = 0.15, min_width_height_ratio = 0.1, quiet = True):
        self.stats = stats
        self.data = [] # list of tuple of form (img_id, wth, ht, bbox, label_id, img_path)
        skipped = 0
        for img_id, imgfname in stats.img2fname.items():
            imgf = stats.img_dir/imgfname
            width, height = stats.img2sz[img_id]
            bboxs = []
            lids = []
            for lid, x, y, w, h in stats.img2lbs[img_id]:
                if lid != None and box_within_bounds(x, y, w, h, width, height, min_margin_ratio, min_width_height_ratio): 
                    b = [int(x), int(y), int(w), int(h)]
                    l = int(lid)
                    bboxs.append(b)
                    lids.append(l)
                else:
                    if not quiet: print(f"warning: skipping lxywh of {lid, x, y, w, h}")

            if len(bboxs) > 0:
                self.data.append( (img_id, width, height, bboxs, lids, imgf, ) )
            else:
                skipped += 1

        print(f"Skipped {skipped} out of {stats.num_imgs} images")

...

@lgvaz is working on a solution at IceVision level that may do something similar.

All 6 comments

It turns out that IceVision relies on Albumentation's default image augmentation which invokes ShiftScaleRotate with shift_limit=0.0625 and scale_limit=0.1 probabilistically so sometimes small boxes may have effective area of 0, or boxes may be pushed to beyond the borders, leading to invalid or 0 area boxes.

My quick fix is to have logic in my custom parser to filter these risky boxes but. Leaving my code fix here so others may find idea for their own dataset should they counter the same problem:

def box_within_bounds(x, y, w, h, width, height, min_margin_ratio, min_width_height_ratio):
    min_width = min_width_height_ratio*width
    min_height = min_width_height_ratio*height
    if w < min_width or h < min_height:
        return False
    top_margin = min_margin_ratio*height
    bottom_margin = height - top_margin
    left_margin = min_margin_ratio*width
    right_margin = width - left_margin
    if x < left_margin or x > right_margin:
        return False
    if y < top_margin or y > bottom_margin:
        return False
    return True

class SubCocoParser(Parser, LabelsMixin, BBoxesMixin, FilepathMixin, SizeMixin):
    def __init__(self, stats:CocoDatasetStats, min_margin_ratio = 0.15, min_width_height_ratio = 0.1, quiet = True):
        self.stats = stats
        self.data = [] # list of tuple of form (img_id, wth, ht, bbox, label_id, img_path)
        skipped = 0
        for img_id, imgfname in stats.img2fname.items():
            imgf = stats.img_dir/imgfname
            width, height = stats.img2sz[img_id]
            bboxs = []
            lids = []
            for lid, x, y, w, h in stats.img2lbs[img_id]:
                if lid != None and box_within_bounds(x, y, w, h, width, height, min_margin_ratio, min_width_height_ratio): 
                    b = [int(x), int(y), int(w), int(h)]
                    l = int(lid)
                    bboxs.append(b)
                    lids.append(l)
                else:
                    if not quiet: print(f"warning: skipping lxywh of {lid, x, y, w, h}")

            if len(bboxs) > 0:
                self.data.append( (img_id, width, height, bboxs, lids, imgf, ) )
            else:
                skipped += 1

        print(f"Skipped {skipped} out of {stats.num_imgs} images")

...

@lgvaz is working on a solution at IceVision level that may do something similar.

Hi @bguan, is this still happening after the new autofix implementation?

@Igvaz, sorry was distracted by other things the past few weeks... plus was playing with new pytorch 1.7 and torchvision 0.8 which broke many things with my other experiments. Effdet also hasn't release a torch 1.7 compatible version though they have it on master trunk. So after rolling back torch to 1.6 and torchvision to 0.7, icevision to 0.2.2 and testing autofix, it is still breaking, this time with x_max == x_min.

ValueError                                Traceback (most recent call last)
/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_epoch(self)
    190     def _do_epoch(self):
--> 191         self._do_epoch_train()
    192         self._do_epoch_validate()

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_epoch_train(self)
    182         self.dl = self.dls.train
--> 183         self._with_events(self.all_batches, 'train', CancelTrainException)
    184 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in all_batches(self)
    160         self.n_iter = len(self.dl)
--> 161         for o in enumerate(self.dl): self.one_batch(*o)
    162 

/usr/local/lib/python3.8/dist-packages/fastai/data/load.py in __iter__(self)
    101         self.__idxs=self.get_idxs() # called in context of main process (not workers/subprocesses)
--> 102         for b in _loaders[self.fake_l.num_workers==0](self.fake_l):
    103             if self.device is not None: b = to_device(b, self.device)

/usr/local/lib/python3.8/dist-packages/torch/utils/data/dataloader.py in __next__(self)
    362     def __next__(self):
--> 363         data = self._next_data()
    364         self._num_yielded += 1

/usr/local/lib/python3.8/dist-packages/torch/utils/data/dataloader.py in _next_data(self)
    988                 del self._task_info[idx]
--> 989                 return self._process_data(data)
    990 

/usr/local/lib/python3.8/dist-packages/torch/utils/data/dataloader.py in _process_data(self, data)
   1013         if isinstance(data, ExceptionWrapper):
-> 1014             data.reraise()
   1015         return data

/usr/local/lib/python3.8/dist-packages/torch/_utils.py in reraise(self)
    394             msg = KeyErrorMessage(msg)
--> 395         raise self.exc_type(msg)

ValueError: Caught ValueError in DataLoader worker process 2.
Original Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/torch/utils/data/_utils/worker.py", line 185, in _worker_loop
    data = fetcher.fetch(index)
  File "/usr/local/lib/python3.8/dist-packages/torch/utils/data/_utils/fetch.py", line 34, in fetch
    data = next(self.dataset_iter)
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 111, in create_batches
    yield from map(self.do_batch, self.chunkify(res))
  File "/usr/local/lib/python3.8/dist-packages/fastcore/utils.py", line 159, in chunked
    res = list(itertools.islice(it, chunk_sz))
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 124, in do_item
    try: return self.after_item(self.create_item(s))
  File "/usr/local/lib/python3.8/dist-packages/fastai/data/load.py", line 130, in create_item
    def create_item(self, s):  return next(self.it) if s is None else self.dataset[s]
  File "/usr/local/lib/python3.8/dist-packages/icevision/data/dataset.py", line 35, in __getitem__
    data = self.tfm(data)
  File "/usr/local/lib/python3.8/dist-packages/icevision/tfms/transform.py", line 13, in __call__
    tfmed = self.apply(**data)
  File "/usr/local/lib/python3.8/dist-packages/icevision/tfms/albumentations/tfms.py", line 110, in apply
    d = self.tfms(**params)
  File "/usr/local/lib/python3.8/dist-packages/albumentations/core/composition.py", line 180, in __call__
    p.preprocess(data)
  File "/usr/local/lib/python3.8/dist-packages/albumentations/core/utils.py", line 62, in preprocess
    data[data_name] = self.check_and_convert(data[data_name], rows, cols, direction="to")
  File "/usr/local/lib/python3.8/dist-packages/albumentations/core/utils.py", line 70, in check_and_convert
    return self.convert_to_albumentations(data, rows, cols)
  File "/usr/local/lib/python3.8/dist-packages/albumentations/augmentations/bbox_utils.py", line 51, in convert_to_albumentations
    return convert_bboxes_to_albumentations(data, self.params.format, rows, cols, check_validity=True)
  File "/usr/local/lib/python3.8/dist-packages/albumentations/augmentations/bbox_utils.py", line 303, in convert_bboxes_to_albumentations
    return [convert_bbox_to_albumentations(bbox, source_format, rows, cols, check_validity) for bbox in bboxes]
  File "/usr/local/lib/python3.8/dist-packages/albumentations/augmentations/bbox_utils.py", line 303, in <listcomp>
    return [convert_bbox_to_albumentations(bbox, source_format, rows, cols, check_validity) for bbox in bboxes]
  File "/usr/local/lib/python3.8/dist-packages/albumentations/augmentations/bbox_utils.py", line 251, in convert_bbox_to_albumentations
    check_bbox(bbox)
  File "/usr/local/lib/python3.8/dist-packages/albumentations/augmentations/bbox_utils.py", line 334, in check_bbox
    raise ValueError("x_max is less than or equal to x_min for bbox {bbox}.".format(bbox=bbox))
ValueError: x_max is less than or equal to x_min for bbox (0.2828125, 0.70625, 0.2828125, 0.7229166666666667, 5).


During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    154     def _with_events(self, f, event_type, ex, final=noop):
--> 155         try:       self(f'before_{event_type}')       ;f()
    156         except ex: self(f'after_cancel_{event_type}')

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _do_fit(self)
    196             self.epoch=epoch
--> 197             self._with_events(self._do_epoch, 'epoch', CancelEpochException)
    198 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _with_events(self, f, event_type, ex, final)
    156         except ex: self(f'after_cancel_{event_type}')
--> 157         finally:   self(f'after_{event_type}')        ;final()
    158 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in __call__(self, event_name)
    132 
--> 133     def __call__(self, event_name): L(event_name).map(self._call_one)
    134 

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in map(self, f, gen, *args, **kwargs)
    341 
--> 342     def map(self, f, *args, gen=False, **kwargs): return self._new(map_ex(self, f, *args, gen=gen, **kwargs))
    343     def argwhere(self, f, negate=False, **kwargs): return self._new(argwhere(self, f, negate, **kwargs))

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in map_ex(iterable, f, gen, *args, **kwargs)
    201     if gen: return res
--> 202     return list(res)
    203 

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __call__(self, *args, **kwargs)
    184         fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> 185         return self.fn(*fargs, **kwargs)
    186 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in _call_one(self, event_name)
    136         assert hasattr(event, event_name), event_name
--> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
    138 

/usr/local/lib/python3.8/dist-packages/fastai/learner.py in <listcomp>(.0)
    136         assert hasattr(event, event_name), event_name
--> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
    138 

/usr/local/lib/python3.8/dist-packages/fastai/callback/core.py in __call__(self, event_name)
     43         res = None
---> 44         if self.run and _run: res = getattr(self, event_name, noop)()
     45         if event_name=='after_fit': self.run=True #Reset self.run to True at each end of fit

<ipython-input-13-824bfa0b1ecb> in after_epoch(self)
     11         "Compare the value monitored to its best score and save if best."
---> 12         super().after_epoch()
     13         if self.new_best or self.epoch==0:

/usr/local/lib/python3.8/dist-packages/fastai/callback/tracker.py in after_epoch(self)
     81         else: #every improvement
---> 82             super().after_epoch()
     83             if self.new_best:

/usr/local/lib/python3.8/dist-packages/fastai/callback/tracker.py in after_epoch(self)
     38         "Compare the last value to the best up to now"
---> 39         val = self.recorder.values[-1][self.idx]
     40         if self.comp(val - self.min_delta, self.best): self.best,self.new_best = val,True

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in __getitem__(self, idx)
    300     def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
--> 301     def __getitem__(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
    302     def copy(self): return self._new(self.items.copy())

/usr/local/lib/python3.8/dist-packages/fastcore/foundation.py in _get(self, i)
    304     def _get(self, i):
--> 305         if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
    306         i = mask2idxs(i)

IndexError: list index out of range
...

I think it is due to albumentation scaling again making boxes too small. May be you can enhance autofix by making sure boxes are at least 1x1 pixel?

Hi @bguan, that functionality can be easily added to autofix, the issue is that autofix only happens once on parsing time, but this issue is being caused by albumentations transforms in itself right?

In your solution you're removing the risky boxes that can cause this error, we can add that to autofix but optimally that should not be necessary I think

We need to somehow come with a more deterministic experiment where we can track if the error is really being caused by albumentations and then possibly suggest a fix there

I think this might be related to #596, @bguan can you see if the error is still happening for you?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RibenaMapleSyrup picture RibenaMapleSyrup  路  3Comments

lgvaz picture lgvaz  路  6Comments

lgvaz picture lgvaz  路  3Comments

tugot17 picture tugot17  路  5Comments

lgvaz picture lgvaz  路  5Comments