Image Classifier learn.predict(img)

I trained a image classifier and tried to use the model to make predictions using “learn.predict(img)”. However, the error occurred “IndexError: list index out of range”. I ran into this problem both on my Google Cloud Platform and my local MacBook Laptop. Here is the detail:

My Code:

from fastai2.vision.all import *
from utils import *
matplotlib.rc(‘image’, cmap=‘Greys’)

path = Path(‘data/’)
dls = ImageDataLoaders.from_folder(path)
learn = cnn_learner(dls, resnet18, pretrained=False, loss_func=F.cross_entropy, metrics=accuracy)
learn.fit_one_cycle(10, 0.001)

uploader = SimpleNamespace(data = [‘data/test/1/1.jpg’])
img = PILImage.create(uploader.data[0])
learn.predict(img)

Error Message:


IndexError Traceback (most recent call last)
in
----> 1 learn.predict(img)

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/learner.py in predict(self, item, rm_type_tfms, with_input)
214 dl = self.dls.test_dl([item], rm_type_tfms=rm_type_tfms)
215 inp,preds,_,dec_preds = self.get_preds(dl=dl, with_input=True, with_decoded=True)
–> 216 dec = self.dls.decode_batch((*tuplify(inp),*tuplify(dec_preds)))[0]
217 i = getattr(self.dls, ‘n_inp’, -1)
218 dec_inp,dec_targ = map(detuplify, [dec[:i],dec[i:]])

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/core.py in decode_batch(self, b, max_n, full)
72
73 def decode(self, b): return self.before_batch.decode(to_cpu(self.after_batch.decode(self._retain_dl(b))))
—> 74 def decode_batch(self, b, max_n=9, full=True): return self._decode_batch(self.decode(b), max_n, full)
75
76 def _decode_batch(self, b, max_n=9, full=True):

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/core.py in _decode_batch(self, b, max_n, full)
77 f = self.after_item.decode
78 f = compose(f, partial(getattr(self.dataset,‘decode’,noop), full = full))
—> 79 return L(batch_to_samples(b, max_n=max_n)).map(f)
80
81 def _pre_show_batch(self, b, max_n=9):

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in map(self, f, *args, **kwargs)
360 else f.format if isinstance(f,str)
361 else f.getitem)
–> 362 return self._new(map(g, self))
363
364 def filter(self, f, negate=False, **kwargs):

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in _new(self, items, *args, **kwargs)
313 @property
314 def _xtra(self): return None
–> 315 def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
316 def getitem(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
317 def copy(self): return self._new(self.items.copy())

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in call(cls, x, args, **kwargs)
39 return x
40
—> 41 res = super().call(
((x,) + args), **kwargs)
42 res._newchk = 0
43 return res

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in init(self, items, use_list, match, *rest)
304 if items is None: items = []
305 if (use_list is not None) or not _is_array(items):
–> 306 items = list(items) if use_list else _listify(items)
307 if match is not None:
308 if is_coll(match): match = len(match)

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in _listify(o)
240 if isinstance(o, list): return o
241 if isinstance(o, str) or _is_array(o): return [o]
–> 242 if is_iter(o): return list(o)
243 return [o]
244

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in call(self, *args, **kwargs)
206 if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
207 fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
–> 208 return self.fn(*fargs, **kwargs)
209
210 # Cell

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/utils.py in _inner(x, *args, **kwargs)
339 if order is not None: funcs = funcs.sorted(order)
340 def _inner(x, *args, **kwargs):
–> 341 for f in L(funcs): x = f(x, *args, **kwargs)
342 return x
343 return _inner

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/core.py in decode(self, o, full)
271 def iter(self): return (self[i] for i in range(len(self)))
272 def repr(self): return coll_repr(self)
–> 273 def decode(self, o, full=True): return tuple(tl.decode(o_, full=full) for o_,tl in zip(o,tuplify(self.tls, match=o)))
274 def subset(self, i): return type(self)(tls=L(tl.subset(i) for tl in self.tls), n_inp=self.n_inp)
275 def _new(self, items, *args, **kwargs): return super()._new(items, tfms=self.tfms, do_setup=False, **kwargs)

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/core.py in (.0)
271 def iter(self): return (self[i] for i in range(len(self)))
272 def repr(self): return coll_repr(self)
–> 273 def decode(self, o, full=True): return tuple(tl.decode(o_, full=full) for o_,tl in zip(o,tuplify(self.tls, match=o)))
274 def subset(self, i): return type(self)(tls=L(tl.subset(i) for tl in self.tls), n_inp=self.n_inp)
275 def _new(self, items, *args, **kwargs): return super()._new(items, tfms=self.tfms, do_setup=False, **kwargs)

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/core.py in decode(self, o, **kwargs)
208 def iter(self): return (self[i] for i in range(len(self)))
209 def show(self, o, **kwargs): return self.tfms.show(o, **kwargs)
–> 210 def decode(self, o, **kwargs): return self.tfms.decode(o, **kwargs)
211 def call(self, o, **kwargs): return self.tfms.call(o, **kwargs)
212 def overlapping_splits(self): return L(Counter(self.splits.concat()).values()).filter(gt(1))

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/transform.py in decode(self, o, full)
191
192 def decode (self, o, full=True):
–> 193 if full: return compose_tfms(o, tfms=self.fs, is_enc=False, reverse=True, split_idx=self.split_idx)
194 #Not full means we decode up to the point the item knows how to show itself.
195 for f in reversed(self.fs):

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/transform.py in compose_tfms(x, tfms, is_enc, reverse, **kwargs)
136 for f in tfms:
137 if not is_enc: f = f.decode
–> 138 x = f(x, **kwargs)
139 return x
140

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/transform.py in decode(self, x, **kwargs)
71 def name(self): return getattr(self, ‘_name’, _get_name(self))
72 def call(self, x, **kwargs): return self._call(‘encodes’, x, **kwargs)
—> 73 def decode (self, x, **kwargs): return self._call(‘decodes’, x, **kwargs)
74 def repr(self): return f’{self.name}: {self.encodes} {self.decodes}’
75

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/transform.py in _call(self, fn, x, split_idx, **kwargs)
81 if split_idx!=self.split_idx and self.split_idx is not None: return x
82 f = getattr(self, fn)
—> 83 if not _is_tuple(x): return self.do_call(f, x, **kwargs)
84 res = tuple(self.do_call(f, x, **kwargs) for x
in x)
85 return retain_type(res, x)

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/transform.py in _do_call(self, f, x, **kwargs)
86
87 def _do_call(self, f, x, **kwargs):
—> 88 return x if f is None else retain_type(f(x, **kwargs), x, f.returns_none(x))
89
90 add_docs(Transform, decode=“Delegate to decodes to undo transform”, setup=“Delegate to setups to set up transform”)

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/dispatch.py in call(self, *args, **kwargs)
96 if not f: return args[0]
97 if self.inst is not None: f = MethodType(f, self.inst)
—> 98 return f(*args, **kwargs)
99
100 def get(self, inst, owner):

~/Projects/anaconda3/lib/python3.7/site-packages/fastai2/data/transforms.py in decodes(self, o)
198
199 def encodes(self, o): return TensorCategory(self.vocab.o2i[o])
–> 200 def decodes(self, o): return Category (self.vocab [o])
201
202 # Cell

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in getitem(self, k)
268 def init(self, items): self.items = items
269 def len(self): return len(self.items)
–> 270 def getitem(self, k): return self.items[k]
271 def setitem(self, k, v): self.items[list(k) if isinstance(k,CollBase) else k] = v
272 def delitem(self, i): del(self.items[i])

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in getitem(self, idx)
314 def _xtra(self): return None
315 def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
–> 316 def getitem(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
317 def copy(self): return self._new(self.items.copy())
318

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in get(self, i)
322 return (self.items.iloc[list(i)] if hasattr(self.items,‘iloc’)
323 else self.items.array()[(i,)] if hasattr(self.items,‘array’)
–> 324 else [self.items[i_] for i
in i])
325
326 def setitem(self, idx, o):

~/Projects/anaconda3/lib/python3.7/site-packages/fastcore/foundation.py in (.0)
322 return (self.items.iloc[list(i)] if hasattr(self.items,‘iloc’)
323 else self.items.array()[(i,)] if hasattr(self.items,‘array’)
–> 324 else [self.items[i_] for i_ in i])
325
326 def setitem(self, idx, o):

IndexError: list index out of range

Hi,

I think the easiest way is to use the image path as an argument of the predict method.

pred = learn.predict(‘data/test/1/1.jpg’)

or this should also work:
img = open_image(‘imgs/cat_example.jpg’)
pred = learn.predict(img)

Florian

Thank you. But I’ve tried these method, the same problem still exists.

I think you are missing the pred =
pred = learn.predict(img)

I get the same error when running just:
learn_predict(img)

I have no idea why.

Florian

I tried this code:

dls = ImageDataLoaders.from_name_func(
path, get_image_file(path), valid_pct=0.2, seed=42,
label_func=is_cat, item_tfms=Resize(224))

learn = cnn_learner(dls, resnet34, metrics=error_rate)
learn.fine_tune(1)

Then I do the predict, using:
is_cat,_,probs = learn.predict(img)

This will work, both on Mac and on Collab

1 Like

I’m facing the same issue in a completely different setting and it doesn’t seem to work at all. I checked the definition for predict and it returns dec_targ,dec_preds[0],preds[0] if requested without input. I’ve been investigating this for 6 hours now and still no luck.

Reference notebook

Hi all,

Thanks to muellerzr and sgugger, we resolved this issue. Here is the catch, the code that threw an error used F.cross_entropy loss learn = cnn_learner(dls, resnet18, pretrained=False, loss_func=F.cross_entropy, metrics=accuracy)

When it magically worked for you learn = cnn_learner(dls, resnet34, metrics=error_rate), you skipped providing the loss function and fastai picked the CrossEntropyLossFlat function for you. The reason this works is that every loss function has an extension where both input and targets are flattened. In technical terms, the loss function requires an activation and a decode method for the predict method to work.

Why is that important is beyond me for now but I’ll try to answer that soon. Hope that helped.

3 Likes

The reasoning is the new transform-based API fastai2 has. Every transform method needs a decode for you to get back everything in a sensible way, and a transform is not just limited to augmentation! :slight_smile: I’d begin by looking into what encodes and decodes are doing

2 Likes