Inference - Error learn.get_preds "No such file or directory"

Hello everyone,

I’m trying to apply inference on a trained model.
In one folder (roi_detection_subset) I have a subfolder with the training and validation set and another subfolder with the test set.

The folders structure is the following:
Datasets
→ roi_detection_subset
------> train_val
------> test

The issue I have is that when the function “learn.get_preds” is executed, it returns the following error:
FileNotFoundError: [Errno 2] No such file or directory: ‘71615993363456904745360715343162325531-2_luzweh.png’

Next, I show the key parts of my code:

path = 'Datasets/roi_detection_subset/train_val/'
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= get_bboxes,
    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), BBoxReshape] 
)
path_dl = Path(path)
dls = data.dataloaders(path_dl, path=path_dl, bs = 64) 
learn = Learner(dls, LungDetector(arch=models.resnet50).cuda(), loss_func=loss_fn) 
from os import listdir

test_images = [filename for filename in listdir('Datasets/roi_detection_subset/test/')]

test_dl = learn.dls.test_dl(test_images)

preds, targs = learn.get_preds(dl=test_dl) 

I don’t know what I’m doing wrong because the image that gives the error exists inside the test folder.

I would appreciate any suggestions on how I can solve this problem.

Thank you.

1 Like

You probably want to pass your test path rather than the test images.
Something like this:

test_path = 'Datasets/roi_detection_subset/test/'
test_dl = learn.dls.test_dl(test_path)
preds, targs = learn.get_preds(dl=test_dl) 

I applied your proposed code and now when get_preds is executed, it returns the following error:

PermissionError: [Errno 13] Permission denied: ‘Datasets/roi_detection_subset/test/’.

The full stack trace is:

---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_15560\664772027.py in <module>
----> 1 preds, targs = learn.get_preds(dl=test_dl)
      2 
      3 predicted_bboxes = ((preds + 1) / 2).numpy()
      4 # (preds + 1) is used to make negative predictions turn into positive
      5 # NOTE: Why is ((preds + 1) divided by 2? are the predictions too big (I GET THAT IT'S A NORMALIZATION OF PREDICTIONS)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in get_preds(self, ds_idx, dl, with_input, with_decoded, with_loss, act, inner, reorder, cbs, **kwargs)
    251         if with_loss: ctx_mgrs.append(self.loss_not_reduced())
    252         with ContextManagers(ctx_mgrs):
--> 253             self._do_epoch_validate(dl=dl)
    254             if act is None: act = getattr(self.loss_func, 'activation', noop)
    255             res = cb.all_tensors()

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in _do_epoch_validate(self, ds_idx, dl)
    201         if dl is None: dl = self.dls[ds_idx]
    202         self.dl = dl
--> 203         with torch.no_grad(): self._with_events(self.all_batches, 'validate', CancelValidException)
    204 
    205     def _do_epoch(self):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in _with_events(self, f, event_type, ex, final)
    161 
    162     def _with_events(self, f, event_type, ex, final=noop):
--> 163         try: self(f'before_{event_type}');  f()
    164         except ex: self(f'after_cancel_{event_type}')
    165         self(f'after_{event_type}');  final()

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in all_batches(self)
    167     def all_batches(self):
    168         self.n_iter = len(self.dl)
--> 169         for o in enumerate(self.dl): self.one_batch(*o)
    170 
    171     def _do_one_batch(self):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in __iter__(self)
    107         self.before_iter()
    108         self.__idxs=self.get_idxs() # called in context of main process (not workers/subprocesses)
--> 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)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\dataloader.py in __next__(self)
    528             if self._sampler_iter is None:
    529                 self._reset()
--> 530             data = self._next_data()
    531             self._num_yielded += 1
    532             if self._dataset_kind == _DatasetKind.Iterable and \

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\dataloader.py in _next_data(self)
    568     def _next_data(self):
    569         index = self._next_index()  # may raise StopIteration
--> 570         data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
    571         if self._pin_memory:
    572             data = _utils.pin_memory.pin_memory(data)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\_utils\fetch.py in fetch(self, possibly_batched_index)
     37                 raise StopIteration
     38         else:
---> 39             data = next(self.dataset_iter)
     40         return self.collate_fn(data)
     41 

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in create_batches(self, samps)
    116         if self.dataset is not None: self.it = iter(self.dataset)
    117         res = filter(lambda o:o is not None, map(self.do_item, samps))
--> 118         yield from map(self.do_batch, self.chunkify(res))
    119 
    120     def new(self, dataset=None, cls=None, **kwargs):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in chunked(it, chunk_sz, drop_last, n_chunks)
    215     if not isinstance(it, Iterator): it = iter(it)
    216     while True:
--> 217         res = list(itertools.islice(it, chunk_sz))
    218         if res and (len(res)==chunk_sz or not drop_last): yield res
    219         if len(res)<chunk_sz: return

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in do_item(self, s)
    131     def prebatched(self): return self.bs is None
    132     def do_item(self, s):
--> 133         try: return self.after_item(self.create_item(s))
    134         except SkipItemException: return None
    135     def chunkify(self, b): return b if self.prebatched else chunked(b, self.bs, self.drop_last)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in create_item(self, s)
    138     def retain(self, res, b):  return retain_types(res, b[0] if is_listy(b) else b)
    139     def create_item(self, s):
--> 140         if self.indexed: return self.dataset[s or 0]
    141         elif s is None:  return next(self.it)
    142         else: raise IndexError("Cannot index an iterable dataset numerically - must use `None`.")

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in __getitem__(self, it)
    330 
    331     def __getitem__(self, it):
--> 332         res = tuple([tl[it] for tl in self.tls])
    333         return res if is_indexer(it) else list(zip(*res))
    334 

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in <listcomp>(.0)
    330 
    331     def __getitem__(self, it):
--> 332         res = tuple([tl[it] for tl in self.tls])
    333         return res if is_indexer(it) else list(zip(*res))
    334 

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in __getitem__(self, idx)
    296         res = super().__getitem__(idx)
    297         if self._after_item is None: return res
--> 298         return self._after_item(res) if is_indexer(idx) else res.map(self._after_item)
    299 
    300 # Cell

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in _after_item(self, o)
    258         return super()._new(items, tfms=self.tfms, do_setup=False, types=self.types, split_idx=split_idx, **kwargs)
    259     def subset(self, i): return self._new(self._get(self.splits[i]), split_idx=i)
--> 260     def _after_item(self, o): return self.tfms(o)
    261     def __repr__(self): return f"{self.__class__.__name__}: {self.items}\ntfms - {self.tfms.fs}"
    262     def __iter__(self): return (self[i] for i in range(len(self)))

~\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\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)
     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\core.py in create(cls, fn, **kwargs)
    108         if isinstance(fn,ndarray): return cls(Image.fromarray(fn))
    109         if isinstance(fn,bytes): fn = io.BytesIO(fn)
--> 110         return cls(load_image(fn, **merge(cls._open_args, kwargs)))
    111 
    112     def show(self, ctx=None, **kwargs):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\vision\core.py in load_image(fn, mode)
     83 def load_image(fn, mode=None):
     84     "Open and load a `PIL.Image` and convert to `mode`"
---> 85     im = Image.open(fn)
     86     im.load()
     87     im = im._new(im.im)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\Image.py in open(fp, mode, formats)
   2951 
   2952     if filename:
-> 2953         fp = builtins.open(filename, "rb")
   2954         exclusive_fp = True
   2955 

PermissionError: [Errno 13] Permission denied: 'Datasets/roi_detection_subset/test/'

According to the stack trace I understand the error is due to the fact that in the last inner function, the open function, there is expected to be an image filename as the parameter but instead a path is passed (the path is ‘Datasets/roi_detection_subset/test/’).

My original code of inference/batch prediction was done by taking as reference the example code shown at the following website: Inference With fast.ai | Just Stir It Some More.

After reading the documentation of fast.ai on DataLoaders.test_dl (Data core | fastai) I understand the appropiate way to create the test dataloader is how I was doing, that is, passing a list of the test image filenames, instead of their path.

I hope anyone can give me any suggestions on how I can fix the original error stated at the start of this topic.

I managed to solve the error stated on the last message by passing a list of the path names of the test images as a parameter of “learn.dls.test_dl”.

My new inference code is:

import glob
path = glob.glob("Datasets/roi_detection_subset/test/*.png")
test_files = [fn for fn in path]
# Create a test dataloader from test_items using validation transforms of dls
test_dl = learn.dls.test_dl(test_files)

preds = learn.get_preds(dl=test_dl) 

But now I have a new error when “learn.get_preds” is executed. I guess the error is related to the fact that I couldn’t load the annotation files (".txt") into the test dataloader, because if I set the path variable to be “path = glob.glob(“Datasets/roi_detection_subset/test/”)” I get an error on “test_dl = learn.dls.test_dl(test_files)” telling me it can’t identify an image file with filename extension .txt.

The stack trace related to the new error is:

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_6732\982592345.py in <module>
      6 test_dl = learn.dls.test_dl(test_files) # Documentation: https://docs.fast.ai/data.core.html#DataLoaders.test_dl
      7 
----> 8 preds = learn.get_preds(dl=test_dl)
      9 
     10 predicted_bboxes = ((preds + 1) / 2).numpy()

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in get_preds(self, ds_idx, dl, with_input, with_decoded, with_loss, act, inner, reorder, cbs, **kwargs)
    251         if with_loss: ctx_mgrs.append(self.loss_not_reduced())
    252         with ContextManagers(ctx_mgrs):
--> 253             self._do_epoch_validate(dl=dl)
    254             if act is None: act = getattr(self.loss_func, 'activation', noop)
    255             res = cb.all_tensors()

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in _do_epoch_validate(self, ds_idx, dl)
    201         if dl is None: dl = self.dls[ds_idx]
    202         self.dl = dl
--> 203         with torch.no_grad(): self._with_events(self.all_batches, 'validate', CancelValidException)
    204 
    205     def _do_epoch(self):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in _with_events(self, f, event_type, ex, final)
    161 
    162     def _with_events(self, f, event_type, ex, final=noop):
--> 163         try: self(f'before_{event_type}');  f()
    164         except ex: self(f'after_cancel_{event_type}')
    165         self(f'after_{event_type}');  final()

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in all_batches(self)
    167     def all_batches(self):
    168         self.n_iter = len(self.dl)
--> 169         for o in enumerate(self.dl): self.one_batch(*o)
    170 
    171     def _do_one_batch(self):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in __iter__(self)
    107         self.before_iter()
    108         self.__idxs=self.get_idxs() # called in context of main process (not workers/subprocesses)
--> 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)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\dataloader.py in __next__(self)
    528             if self._sampler_iter is None:
    529                 self._reset()
--> 530             data = self._next_data()
    531             self._num_yielded += 1
    532             if self._dataset_kind == _DatasetKind.Iterable and \

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\dataloader.py in _next_data(self)
    568     def _next_data(self):
    569         index = self._next_index()  # may raise StopIteration
--> 570         data = self._dataset_fetcher.fetch(index)  # may raise StopIteration
    571         if self._pin_memory:
    572             data = _utils.pin_memory.pin_memory(data)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\torch\utils\data\_utils\fetch.py in fetch(self, possibly_batched_index)
     37                 raise StopIteration
     38         else:
---> 39             data = next(self.dataset_iter)
     40         return self.collate_fn(data)
     41 

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in create_batches(self, samps)
    116         if self.dataset is not None: self.it = iter(self.dataset)
    117         res = filter(lambda o:o is not None, map(self.do_item, samps))
--> 118         yield from map(self.do_batch, self.chunkify(res))
    119 
    120     def new(self, dataset=None, cls=None, **kwargs):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\load.py in do_batch(self, b)
    142         else: raise IndexError("Cannot index an iterable dataset numerically - must use `None`.")
    143     def create_batch(self, b): return (fa_collate,fa_convert)[self.prebatched](b)
--> 144     def do_batch(self, b): return self.retain(self.create_batch(self.before_batch(b)), b)
    145     def to(self, device): self.device = device
    146     def one_batch(self):

~\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\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)
     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\Temp\ipykernel_6732\4024806903.py in custom_bb_pad(samples, pad_idx)
     14     "Function that collect `samples` of bboxes and adds padding with `pad_idx`."
     15     #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)
---> 16     max_len = max([len(s[1]) for s in samples]) # equals to 4 (number of bbox coordinates)
     17     def _f(img,bbox):
     18         bbox = torch.cat([bbox,bbox.new_zeros(max_len-bbox.shape[0], 4)])

~\AppData\Local\Temp\ipykernel_6732\4024806903.py in <listcomp>(.0)
     14     "Function that collect `samples` of bboxes and adds padding with `pad_idx`."
     15     #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)
---> 16     max_len = max([len(s[1]) for s in samples]) # equals to 4 (number of bbox coordinates)
     17     def _f(img,bbox):
     18         bbox = torch.cat([bbox,bbox.new_zeros(max_len-bbox.shape[0], 4)])

IndexError: tuple index out of range

I haven’t found any example about predicting a test set in object detection and I don’t know what I should change on my code.
I hope someone with experience on inference in object detection can help me on solving this error.

To know more parts of my code (DataBlock creation, Learner creation) you can check the initial message of this topic.

Thank you.