Learn.predict()

This question comes from fast book master - part 1 - lesson 13 convolutions.
After successfully completing learning achieving 94%, i want to make a prediction using 1 image but i got all sort of errors. How to use prediction? or how to make an inference after completing learning?

3 cases below:

  1. I try to use the same data format used when learning, so i make it gray scale image, with a tensor format (1,1,28,28) but says cannot handle data (1,1,28,28)
  2. some says it can only take an image format, so use grayscale image bw, but says error list index out of range
  3. i use data directly from the datalist, but says cannot hanlde (1,1,1)

thanks

def fit(epochs=1):
set_seed(42, reproducible=True)
learn = Learner(dls, simple_cnn(), loss_func=F.cross_entropy,
metrics=accuracy, cbs=ActivationStats(with_hist=True))
learn.fit(epochs, 0.06)
return learn

learn = fit(5)

path = Path(r’D:\fastai\fastbook-master\mnist_png\training\2\10009.png’)
tmp = Image.open(path)
tmp = tmp.convert(‘L’)
bw = tmp
tmp = tensor(tmp)
tmp = tmp.unsqueeze(0)
tmp = tmp.unsqueeze(0)

  1. learn.predict(tmp)
    TypeError: Cannot handle this data type: (1, 1, 28, 28), |u1

  2. learn.predict(bw)
    IndexError: list index out of range

x,y = learn.dls.one_batch()
x.shape, x[0].shape
x = to_cpu(x)
learn.predict(x[0])
6. TypeError: Cannot handle this data type: (1, 1, 1), |u1

Did you try this?

tmp = Image.open(path)
learn.predict(tmp)

Also, remember to format your markdown so the code doesn’t lose readability.

thank you Jason,
Already did, case 2, is BW (black white - grayscale)
It comes from the code above it

path = Path(r’D:\fastai\fastbook-master\mnist_png\training\2\10009.png’)
tmp = Image.open(path)
tmp = tmp.convert(‘L’)
bw = tmp

without convert, it will throw a different error because the input is color, which expecting 1 and receiving 3.

I found a solution, is to simply use your model to predict directly.

simple_cnn(xb.to('mps'))

worked for me. If you are using windows, change mps to cuda.
Also, this works with a single image, so you can also use

simple_cnn(xb[0].to('mps'))

And then just do a softmax.

1 Like

Hello!
Thanks for the info I will try to figure it out for more.

1 Like

Perhaps, it is much clearer if paste the entire code to see where I make a mistake here.
Training has no issue, but when i try to use predict, it doesnt’ work.

thanks

dls = get_dls()
	
# def conv(ni, nf, ks=3, act=True):
#     res = nn.Conv2d(ni, nf, stride=2, kernel_size=ks, padding=ks//2)
#     if act: res = nn.Sequential(res, nn.ReLU())
#     res.append(nn.BatchNorm2d(nf))    
#     return nn.Sequential(*res)
    
def conv(ni, nf, ks=3, act=True):
    layers = [nn.Conv2d(ni, nf, stride=2, kernel_size=ks, padding=ks//2)]
    if act: layers.append(nn.ReLU())
    layers.append(nn.BatchNorm2d(nf))
    return nn.Sequential(*layers)
    
def simple_cnn():
    return sequential(
        conv(1 ,8, ks=5),        #14x14
        conv(8 ,16),             #7x7
        conv(16,32),             #4x4
        conv(32,64),             #2x2
        conv(64,10, act=False),  #1x1
        Flatten(),
    )

def fit(epochs=1):
    set_seed(42, reproducible=True)
    learn = Learner(dls, simple_cnn(), loss_func=F.cross_entropy,
                    metrics=accuracy, cbs=ActivationStats(with_hist=True))
    learn.fit(epochs, 0.06)
    return learn

learn = fit(1)  

show_image(dls.dataset[0][0])
tmp = dls.dataset[10000][0]
tmp.shape
tmp2 = to_cpu(tmp) # with or without to_cpu(), result in the same error
learn.predict(tmp2)

i got the same error:

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[14], line 2
      1 tmp2 = to_cpu(tmp)
----> 2 learn.predict(tmp2)

File D:\fastai\fastai\fastai\learner.py:326, in Learner.predict(self, item, rm_type_tfms, with_input)
    324 i = getattr(self.dls, 'n_inp', -1)
    325 inp = (inp,) if i==1 else tuplify(inp)
--> 326 dec = self.dls.decode_batch(inp + tuplify(dec_preds))[0]
    327 dec_inp,dec_targ = map(detuplify, [dec[:i],dec[i:]])
    328 res = dec_targ,dec_preds[0],preds[0]

File D:\fastai\fastai\fastai\data\core.py:123, in TfmdDL.decode_batch(self, b, max_n, full)
    118 def decode_batch(self, 
    119     b, # Batch to decode
    120     max_n:int=9, # Maximum number of items to decode
    121     full:bool=True # Whether to decode all transforms. If `False`, decode up to the point the item knows how to show itself
    122 ): 
--> 123     return self._decode_batch(self.decode(b), max_n, full)

File D:\fastai\fastai\fastai\data\core.py:129, in TfmdDL._decode_batch(self, b, max_n, full)
    127 f1 = self.before_batch.decode
    128 f = compose(f1, f, partial(getcallable(self.dataset,'decode'), full = full))
--> 129 return L(batch_to_samples(b, max_n=max_n)).map(f)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\foundation.py:163, in L.map(self, f, *args, **kwargs)
    160 @classmethod
    161 def range(cls, a, b=None, step=None): return cls(range_of(a, b=b, step=step))
--> 163 def map(self, f, *args, **kwargs): return self._new(map_ex(self, f, *args, gen=False, **kwargs))
    164 def argwhere(self, f, negate=False, **kwargs): return self._new(argwhere(self, f, negate, **kwargs))
    165 def argfirst(self, f, negate=False): 

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\basics.py:934, in map_ex(iterable, f, gen, *args, **kwargs)
    932 res = map(g, iterable)
    933 if gen: return res
--> 934 return list(res)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\basics.py:919, in bind.__call__(self, *args, **kwargs)
    917     if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
    918 fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
--> 919 return self.func(*fargs, **kwargs)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\basics.py:944, in compose.<locals>._inner(x, *args, **kwargs)
    943 def _inner(x, *args, **kwargs):
--> 944     for f in funcs: x = f(x, *args, **kwargs)
    945     return x

File D:\fastai\fastai\fastai\data\core.py:457, in Datasets.decode(self, o, full)
--> 457 def decode(self, o, full=True): return tuple(tl.decode(o_, full=full) for o_,tl in zip(o,tuplify(self.tls, match=o)))

File D:\fastai\fastai\fastai\data\core.py:457, in <genexpr>(.0)
--> 457 def decode(self, o, full=True): return tuple(tl.decode(o_, full=full) for o_,tl in zip(o,tuplify(self.tls, match=o)))

File D:\fastai\fastai\fastai\data\core.py:372, in TfmdLists.decode(self, o, **kwargs)
--> 372 def decode(self, o, **kwargs): return self.tfms.decode(o, **kwargs)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\transform.py:218, in Pipeline.decode(self, o, full)
    217 def decode  (self, o, full=True):
--> 218     if full: return compose_tfms(o, tfms=self.fs, is_enc=False, reverse=True, split_idx=self.split_idx)
    219     #Not full means we decode up to the point the item knows how to show itself.
    220     for f in reversed(self.fs):

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\transform.py:160, in compose_tfms(x, tfms, is_enc, reverse, **kwargs)
    158 for f in tfms:
    159     if not is_enc: f = f.decode
--> 160     x = f(x, **kwargs)
    161 return x

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\transform.py:84, in Transform.decode(self, x, **kwargs)
     82 def name(self): return getattr(self, '_name', _get_name(self))
     83 def __call__(self, x, **kwargs): return self._call('encodes', x, **kwargs)
---> 84 def decode  (self, x, **kwargs): return self._call('decodes', x, **kwargs)
     85 def __repr__(self): return f'{self.name}:\nencodes: {self.encodes}decodes: {self.decodes}'
     87 def setup(self, items=None, train_setup=False):

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\transform.py:93, in Transform._call(self, fn, x, split_idx, **kwargs)
     91 def _call(self, fn, x, split_idx=None, **kwargs):
     92     if split_idx!=self.split_idx and self.split_idx is not None: return x
---> 93     return self._do_call(getattr(self, fn), x, **kwargs)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\transform.py:99, in Transform._do_call(self, f, x, **kwargs)
     97     if f is None: return x
     98     ret = f.returns(x) if hasattr(f,'returns') else None
---> 99     return retain_type(f(x, **kwargs), x, ret)
    100 res = tuple(self._do_call(f, x_, **kwargs) for x_ in x)
    101 return retain_type(res, x)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\dispatch.py:122, in TypeDispatch.__call__(self, *args, **kwargs)
    120 elif self.inst is not None: f = MethodType(f, self.inst)
    121 elif self.owner is not None: f = MethodType(f, self.owner)
--> 122 return f(*args, **kwargs)

File D:\fastai\fastai\fastai\data\transforms.py:266, in Categorize.decodes(self, o)
--> 266 def decodes(self, o): return Category  (self.vocab    [o])

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\foundation.py:90, in CollBase.__getitem__(self, k)
---> 90 def __getitem__(self, k): return self.items[list(k) if isinstance(k,CollBase) else k]

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\foundation.py:116, in L.__getitem__(self, idx)
    114 def __getitem__(self, idx):
    115     if isinstance(idx,int) and not hasattr(self.items,'iloc'): return self.items[idx]
--> 116     return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\foundation.py:124, in L._get(self, i)
    120 if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
    121 i = mask2idxs(i)
    122 return (self.items.iloc[list(i)] if hasattr(self.items,'iloc')
    123         else self.items.__array__()[(i,)] if hasattr(self.items,'__array__')
--> 124         else [self.items[i_] for i_ in i])

File ~\.conda\envs\FastAi\lib\site-packages\fastcore\foundation.py:124, in <listcomp>(.0)
    120 if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
    121 i = mask2idxs(i)
    122 return (self.items.iloc[list(i)] if hasattr(self.items,'iloc')
    123         else self.items.__array__()[(i,)] if hasattr(self.items,'__array__')
--> 124         else [self.items[i_] for i_ in i])

IndexError: list index out of range

hi Jason,
Thank you for your help, i finally figure it out.
3 cases are tested:
learn.predict(), learn.get_preds(), convolution + softmax.

However, when I tested on a network containing batchnormalization, it somehows doesnt produce the correct result for the third case. The other 2 methods (learn.predict(), learn.get_preds()) result is correct.

The third case, this code below using convolution + softmax which produces a wrong class.

from PIL import Image
img1 = PILImage.create(r'D:\fastai\fastbook-master\mnist_png\testing\1\1004.png') 
img2 = PILImage.create(r'D:\fastai\fastbook-master\mnist_png\testing\4\1010.png') 
img1 = img1.convert('L')
img2 = img2.convert('L')

use_image =img2
show_image(use_image)


# torch.backends.cpu.deterministic = True
# torch.backends.cpu.benchmark = False

learn.model.eval()
modelLearn = learn.model.cpu()
#print(modelLearn[0][0].bias)

in1 = tensor(use_image).float()
in1 = in1.unsqueeze(0)
in1 = in1.unsqueeze(0) 
out = modelLearn(to_cpu(in1))
print('out')
print(out)
d = F.softmax(out, dim=0)
#d = F.softmax(out)

print('softmax')
print(d)
print('arg max')
d.argmax(dim=0)
#d.argmax()


Yeah, it’s hard to figure out how to get predictions and activations from the fastai Learner. For the next few months I’m going to study fastai library’s source code - maybe that will give me some insights.