Classification - Learner.show_results() not working on test dataloader

Hello everyone,

I trained a binary image classification model and now I’m trying to show the results of the predictions on a test set.
The issue I have is that when I run the function “learn.show_results()” by passing the test dataloader as a parameter I get the error " AssertionError: Match length mismatch".
If I run “learn.show_results()” without passing any parameters I can see the predictions results on the validation images.
I want to be able to show the predictions results also on the test set.

I’d appreciate if someone can tell me how to fix this error.

Thank you.

The key parts of my code are:

DataBlock:

def grand_parent_label(item):
    "Label `item` with it's grand parent folder name."
    return Path(item).parent.parent.name

data = DataBlock(
    blocks=(ImageBlock, CategoryBlock), # CategoryBlock = label
    get_items=get_image_files,
    get_y= grand_parent_label, # grand_parent_label = the grand parent folder names of an images is it's label (normal/effusion)
    splitter= FuncSplitter(lambda img: Path(img).parent.parent.parent.name == 'valid'), # split items by result of func (True for validation, False for training set). 
    batch_tfms= [*aug_transforms(do_flip=False, size=(120,160)), Normalize.from_stats(*imagenet_stats)] 
  )

# On FuncSplitter, If an image path is '[...] train_val/train/normal/normal0.png' 'normal0.png' gets added to the training set. 
# And if an image path is '[...] train_val/valid/normal/normal1.png 'normal1' gets added to the validation set. 

Learner:

learn = cnn_learner(dls, resnet50, metrics=accuracy)

Inference:

testDsPath = "../Datasets/RepoGithub_ref/grids_ds/test/"
effusionTestPath = testDsPath + "effusion"
# Recursively get the effusion test images paths 
effusionTestImages =get_image_files(effusionTestPath)

testEffusion_dl = learn.dls.test_dl(effusionTestImages)
preds, _ = learn.get_preds(dl=testEffusion_dl)

# Show the predictions results based on the effusion test images
learn.show_results(dl=testEffusion_dl, max_n=8)

The full stack trace error is:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_7460\1044661662.py in <module>
     47 preds, _ = learn.get_preds(dl=testEffusion_dl)
     48 # Show the predictions results based on the effusion test images
---> 49 learn.show_results(dl=testEffusion_dl, max_n=8)
     50 
     51 

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\learner.py in show_results(self, ds_idx, dl, max_n, shuffle, **kwargs)
    277         b = dl.one_batch()
    278         _,_,preds = self.get_preds(dl=[b], with_decoded=True)
--> 279         self.dls.show_results(b, preds, max_n=max_n, **kwargs)
    280 
    281     def show_training_loop(self):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in show_results(self, b, out, max_n, ctxs, show, **kwargs)
    104 
    105     def show_results(self, b, out, max_n=9, ctxs=None, show=True, **kwargs):
--> 106         x,y,its = self.show_batch(b, max_n=max_n, show=False)
    107         b_out = type(b)(b[:self.n_inp] + (tuple(out) if is_listy(out) else (out,)))
    108         x1,y1,outs = self.show_batch(b_out, max_n=max_n, show=False)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in show_batch(self, b, max_n, ctxs, show, unique, **kwargs)
     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)
    103         if unique: self.get_idxs = old_get_idxs

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in _pre_show_batch(self, b, max_n)
     90         b = self.decode(b)
     91         if hasattr(b, 'show'): return b,None,None
---> 92         its = self._decode_batch(b, max_n, full=False)
     93         if not is_listy(b): b,its = [b],L((o,) for o in its)
     94         return detuplify(b[:self.n_inp]),detuplify(b[self.n_inp:]),its

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in _decode_batch(self, b, max_n, full)
     84         f1 = self.before_batch.decode
     85         f = compose(f1, f, partial(getattr(self.dataset,'decode',noop), full = full))
---> 86         return L(batch_to_samples(b, max_n=max_n)).map(f)
     87 
     88     def _pre_show_batch(self, b, max_n=9):

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\foundation.py in map(self, f, gen, *args, **kwargs)
    153     def range(cls, a, b=None, step=None): return cls(range_of(a, b=b, step=step))
    154 
--> 155     def map(self, f, *args, gen=False, **kwargs): return self._new(map_ex(self, f, *args, gen=gen, **kwargs))
    156     def argwhere(self, f, negate=False, **kwargs): return self._new(argwhere(self, f, negate, **kwargs))
    157     def argfirst(self, f, negate=False): return first(i for i,o in self.enumerate() if f(o))

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in map_ex(iterable, f, gen, *args, **kwargs)
    696     res = map(g, iterable)
    697     if gen: return res
--> 698     return list(res)
    699 
    700 # Cell

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in __call__(self, *args, **kwargs)
    681             if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
    682         fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> 683         return self.func(*fargs, **kwargs)
    684 
    685 # Cell

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in _inner(x, *args, **kwargs)
    706     if order is not None: funcs = sorted_ex(funcs, key=order)
    707     def _inner(x, *args, **kwargs):
--> 708         for f in funcs: x = f(x, *args, **kwargs)
    709         return x
    710     return _inner

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastai\data\core.py in decode(self, o, full)
    338     def __iter__(self): return (self[i] for i in range(len(self)))
    339     def __repr__(self): return coll_repr(self)
--> 340     def decode(self, o, full=True): return tuple(tl.decode(o_, full=full) for o_,tl in zip(o,tuplify(self.tls, match=o)))
    341     def subset(self, i): return type(self)(tls=L(tl.subset(i) for tl in self.tls), n_inp=self.n_inp)
    342     def _new(self, items, *args, **kwargs): return super()._new(items, tfms=self.tfms, do_setup=False, **kwargs)

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in tuplify(o, use_list, match)
     66 def tuplify(o, use_list=False, match=None):
     67     "Make `o` a tuple"
---> 68     return tuple(listify(o, use_list=use_list, match=match))
     69 
     70 # Cell

~\AppData\Local\Programs\Python\Python37\lib\site-packages\fastcore\basics.py in listify(o, use_list, match, *rest)
     60         if is_coll(match): match = len(match)
     61         if len(res)==1: res = res*match
---> 62         else: assert len(res)==match, 'Match length mismatch'
     63     return res
     64 

AssertionError: Match length mismatch