Beginner: Basics of fastai, PyTorch, numpy, etc ✅


I am doing the first lesson 'Is it a bird? Creating a model from your own data"
And I don’t know what to do with this error

pil_img = PILImage.create('bird.jpg')
is_bird,_,probs = learn.predict(pil_img)

I have the following error - AttributeError: read
The file exists. The path is correct. All versions are updated.

The text of the error

AttributeError Traceback (most recent call last)
/tmp/ipykernel_17/ in
----> 1 is_bird,_,probs = learn.predict(img)
2 print(f"This is a: {is_bird}.“)
3 print(f"Probability it’s a bird: {probs[0]:.4f}”)

/opt/conda/lib/python3.7/site-packages/fastai/ in predict(self, item, rm_type_tfms, with_input)
319 def predict(self, item, rm_type_tfms=None, with_input=False):
320 dl = self.dls.test_dl([item], rm_type_tfms=rm_type_tfms, num_workers=0)
→ 321 inp,preds,_,dec_preds = self.get_preds(dl=dl, with_input=True, with_decoded=True)
322 i = getattr(self.dls, ‘n_inp’, -1)
323 inp = (inp,) if i==1 else tuplify(inp)

/opt/conda/lib/python3.7/site-packages/fastai/ in get_preds(self, ds_idx, dl, with_input, with_decoded, with_loss, act, inner, reorder, cbs, **kwargs)
306 if with_loss: ctx_mgrs.append(self.loss_not_reduced())
307 with ContextManagers(ctx_mgrs):
→ 308 self._do_epoch_validate(dl=dl)
309 if act is None: act = getcallable(self.loss_func, ‘activation’)
310 res = cb.all_tensors()

/opt/conda/lib/python3.7/site-packages/fastai/ in _do_epoch_validate(self, ds_idx, dl)
242 if dl is None: dl = self.dls[ds_idx]
243 self.dl = dl
→ 244 with torch.no_grad(): self._with_events(self.all_batches, ‘validate’, CancelValidException)
246 def _do_epoch(self):

/opt/conda/lib/python3.7/site-packages/fastai/ in with_events(self, f, event_type, ex, final)
198 def with_events(self, f, event_type, ex, final=noop):
→ 199 try: self(f’before
{event_type}'); f()
200 except ex: self(f’after_cancel
201 self(f’after_{event_type}’); final()

/opt/conda/lib/python3.7/site-packages/fastai/ in all_batches(self)
203 def all_batches(self):
204 self.n_iter = len(self.dl)
→ 205 for o in enumerate(self.dl): self.one_batch(*o)
207 def _backward(self): self.loss_grad.backward()

/opt/conda/lib/python3.7/site-packages/fastai/data/ in iter(self)
125 self.before_iter()
126 self.__idxs=self.get_idxs() # called in context of main process (not workers/subprocesses)
→ 127 for b in _loadersself.fake_l.num_workers==0:
128 # pin_memory causes tuples to be converted to lists, so convert them back to tuples
129 if self.pin_memory and type(b) == list: b = tuple(b)

/opt/conda/lib/python3.7/site-packages/torch/utils/data/ in next(self)
519 if self._sampler_iter is None:
520 self._reset()
→ 521 data = self._next_data()
522 self._num_yielded += 1
523 if self._dataset_kind == _DatasetKind.Iterable and \

/opt/conda/lib/python3.7/site-packages/torch/utils/data/ in _next_data(self)
559 def _next_data(self):
560 index = self._next_index() # may raise StopIteration
→ 561 data = self._dataset_fetcher.fetch(index) # may raise StopIteration
562 if self._pin_memory:
563 data = _utils.pin_memory.pin_memory(data)

/opt/conda/lib/python3.7/site-packages/torch/utils/data/_utils/ in fetch(self, possibly_batched_index)
32 raise StopIteration
33 else:
—> 34 data = next(self.dataset_iter)
35 return self.collate_fn(data)

/opt/conda/lib/python3.7/site-packages/fastai/data/ in create_batches(self, samps)
136 if self.dataset is not None: = iter(self.dataset)
137 res = filter(lambda o:o is not None, map(self.do_item, samps))
→ 138 yield from map(self.do_batch, self.chunkify(res))
140 def new(self, dataset=None, cls=None, **kwargs):

/opt/conda/lib/python3.7/site-packages/fastcore/ in chunked(it, chunk_sz, drop_last, n_chunks)
228 if not isinstance(it, Iterator): it = iter(it)
229 while True:
→ 230 res = list(itertools.islice(it, chunk_sz))
231 if res and (len(res)==chunk_sz or not drop_last): yield res
232 if len(res)<chunk_sz: return

/opt/conda/lib/python3.7/site-packages/fastai/data/ in do_item(self, s)
151 def prebatched(self): return is None
152 def do_item(self, s):
→ 153 try: return self.after_item(self.create_item(s))
154 except SkipItemException: return None
155 def chunkify(self, b): return b if self.prebatched else chunked(b,, self.drop_last)

/opt/conda/lib/python3.7/site-packages/fastai/data/ in create_item(self, s)
158 def retain(self, res, b): return retain_types(res, b[0] if is_listy(b) else b)
159 def create_item(self, s):
→ 160 if self.indexed: return self.dataset[s or 0]
161 elif s is None: return next(
162 else: raise IndexError(“Cannot index an iterable dataset numerically - must use None.”)

/opt/conda/lib/python3.7/site-packages/fastai/data/ in getitem(self, it)
457 def getitem(self, it):
→ 458 res = tuple([tl[it] for tl in self.tls])
459 return res if is_indexer(it) else list(zip(*res))

/opt/conda/lib/python3.7/site-packages/fastai/data/ in (.0)
457 def getitem(self, it):
→ 458 res = tuple([tl[it] for tl in self.tls])
459 return res if is_indexer(it) else list(zip(*res))

/opt/conda/lib/python3.7/site-packages/fastai/data/ in getitem(self, idx)
415 res = super().getitem(idx)
416 if self._after_item is None: return res
→ 417 return self._after_item(res) if is_indexer(idx) else
419 # %% …/…/nbs/03_data.core.ipynb 53

/opt/conda/lib/python3.7/site-packages/fastai/data/ in _after_item(self, o)
375 raise
376 def subset(self, i): return self._new(self._get(self.splits[i]), split_idx=i)
→ 377 def _after_item(self, o): return self.tfms(o)
378 def repr(self): return f"{}: {self.items}\ntfms - {self.tfms.fs}"
379 def iter(self): return (self[i] for i in range(len(self)))

/opt/conda/lib/python3.7/site-packages/fastcore/ in call(self, o)
206 self.fs = self.fs.sorted(key=‘order’)
→ 208 def call(self, o): return compose_tfms(o, tfms=self.fs, split_idx=self.split_idx)
209 def repr(self): return f"Pipeline: {’ → '.join([ for f in self.fs if != ‘noop’])}"
210 def getitem(self,i): return self.fs[i]

/opt/conda/lib/python3.7/site-packages/fastcore/ in compose_tfms(x, tfms, is_enc, reverse, **kwargs)
156 for f in tfms:
157 if not is_enc: f = f.decode
→ 158 x = f(x, **kwargs)
159 return x

/opt/conda/lib/python3.7/site-packages/fastcore/ in call(self, x, **kwargs)
79 @property
80 def name(self): return getattr(self, ‘_name’, _get_name(self))
—> 81 def call(self, x, **kwargs): return self._call(‘encodes’, x, **kwargs)
82 def decode (self, x, **kwargs): return self._call(‘decodes’, x, **kwargs)
83 def repr(self): return f’{}:\nencodes: {self.encodes}decodes: {self.decodes}’

/opt/conda/lib/python3.7/site-packages/fastcore/ in _call(self, fn, x, split_idx, **kwargs)
89 def _call(self, fn, x, split_idx=None, **kwargs):
90 if split_idx!=self.split_idx and self.split_idx is not None: return x
—> 91 return self._do_call(getattr(self, fn), x, **kwargs)
93 def _do_call(self, f, x, **kwargs):

/opt/conda/lib/python3.7/site-packages/fastcore/ in do_call(self, f, x, **kwargs)
95 if f is None: return x
96 ret = f.returns(x) if hasattr(f,‘returns’) else None
—> 97 return retain_type(f(x, **kwargs), x, ret)
98 res = tuple(self.do_call(f, x, **kwargs) for x
in x)
99 return retain_type(res, x)

/opt/conda/lib/python3.7/site-packages/fastcore/ in call(self, *args, **kwargs)
118 elif self.inst is not None: f = MethodType(f, self.inst)
119 elif self.owner is not None: f = MethodType(f, self.owner)
→ 120 return f(*args, **kwargs)
122 def get(self, inst, owner):

/opt/conda/lib/python3.7/site-packages/fastai/vision/ in create(cls, fn, **kwargs)
123 if isinstance(fn,bytes): fn = io.BytesIO(fn)
124 if isinstance(fn,Image.Image) and not isinstance(fn,cls): return cls(fn)
→ 125 return cls(load_image(fn, **merge(cls._open_args, kwargs)))
127 def show(self, ctx=None, **kwargs):

/opt/conda/lib/python3.7/site-packages/fastai/vision/ in load_image(fn, mode)
96 def load_image(fn, mode=None):
97 “Open and load a PIL.Image and convert to mode
—> 98 im =
99 im.load()
100 im = im._new(

/opt/conda/lib/python3.7/site-packages/PIL/ in open(fp, mode, formats)
2919 exclusive_fp = True
→ 2921 prefix =
2923 preinit()

/opt/conda/lib/python3.7/site-packages/PIL/ in getattr(self, name)
539 )
540 return self._category
→ 541 raise AttributeError(name)
543 @property

AttributeError: read

Seems there is something wrong with 2.7.11.
Try this in cell 2…

if iskaggle:
    !pip install -Uqq fastai==2.7.10 duckduckgo_search
import fastai

If cell execution doesn’t result in 2.7.10, try a restart or factory reset.


I was very close to giving up.

1 Like

Seems like the newest release no longer supports PIL images being passed as parameter.

Instead, the predict method takes care of all of that for you. You can just pass the name of the file:

img_filename = 'bird.jpg'
is_bird,_,probs = learn.predict(image_filename)

Hi, to everyone.

I am a PhD student in Greece and i would like to learn and use fastai. I would like to train various timeseries models based on Agrometerorological stations and spatial data in order to predict some agricultural indexes.

Can i please be a part of your forum to ask my question ?

Best regards
Chris Koliopanos

1 Like

Alternative work around for 2.7.11 . Thanks to @ bwarner in Fastai discord.


Replace this line:

is_bird,_,probs = learn.predict(PILImage.create('bird.jpg'))

with this:

is_bird,_,probs = learn.predict('bird.jpg')

Can i please be a part of your forum to ask my question ?

Yes, and welcome.

I can confirm this works! Thanks @zerotosingularity


yeah just dropped the PR to fix that → Fix error AttributeError: read by drsmog · Pull Request #52 · fastai/course22 · GitHub

1 Like

Not sure if the cause of this is permanent, or just a result of an unintentional library change in the latest release (2.7.11)

1 Like

For the following code block:

# For the book, we can't actually click an upload button, so we fake it
uploader = SimpleNamespace(data = ['dog.jpg'])

#img = 'images/chapter1_cat_example.jpg' #PILImage.create('images/chapter1_cat_example.jpg')
is_cat,_,probs = learn.predict('dog.jpg')
print(f"Is this a cat?: {is_cat}.")
print(f"Probability it's a cat: {probs[1].item():.6f}")

I get the following error:

FileNotFoundError Traceback (most recent call last)
1 #img = ‘images/chapter1_cat_example.jpg’ #PILImage.create(‘images/chapter1_cat_example.jpg’)
----> 2 is_cat,_,probs = learn.predict(‘dog.jpg’)
3 print(f"Is this a cat?: {is_cat}.“)
4 print(f"Probability it’s a cat: {probs[1].item():.6f}”)

25 frames
/usr/local/lib/python3.9/dist-packages/PIL/ in open(fp, mode, formats)
2974 if filename:
→ 2975 fp =, “rb”)
2976 exclusive_fp = True

FileNotFoundError: [Errno 2] No such file or directory: ‘dog.jpg’

No such file or directory: ‘dog.jpg’

In the folder you are running this code, is there such file ‘dog’jpg’?

!ls 'dog.jpg' 

Hello all !
I’m also having a similar problem with the last step in Lesson 1. I have tried the fix mentioned further above, which says to remove the PILImage portion of that line of code with simply ‘bird.jpg’
This does indeed get rid of the error, but (at least for me) does not actually work.
For example, if I save an image of a car in the directory and call it ‘bird.jpg’, the notebook still says it is 100% probability of being a bird.
If I replace the bird image with a human cartoon, it says its 100% probability of being a bird.
In summary, the fix mentioned above seems to get rid of the error, but the last step is not able to differentiate between a bird and things that are not birds.

Ok, I’ve managed to figure out the answer to my own question. I’ll post it here in case it helps others (and hopefully I’m right in what I’m saying.)
What I said above is true. If I feed the notebook a picture of a coffee or a car or a beer, it says it is a bird. But I think I understand now that we haven’t really trained (fine-tuned) the model, to recognize birds (so the xkcd cartoon at the beginning of the lecture is a little bit misleading)…but rather, what we’ve done is taught the model to be able to tell the difference between a bird and a forest. That’s a significant difference.
I expanded the loop in the notebook to also get pictures of ‘car’ and of ‘beer’. Then I tested the notebook with new pictures of birds, cars, beers, and forests. It was very accurate in recognizing each new picture! But if I give it something new, like a cooking pan with some stuff in it, it says its a bird.
So I think what this notebook does is to teach a model to distinguish items from each other, but not in general.

1 Like

Indeed, if you train a classifier on pictures of birds or forests, it will always output either one of these 2 classes. Even if you give it a picture of a car.

What you could do is use multi-label classification, in principle that should be able to also classify “nothing” in case you run inference on an image of a class it wasn’t trained on.

1 Like

Hello everyone,

As I’m a total beginner, I still feel a bit overwhelmed browsing the docs, especially when I need to look for a very specific piece of information.

In the lesson 1 of the course, the method fine_tune is called on a Vision Learner, as in =>

learn = vision_learner(dls, resnet18, metrics=error_rate)

What is the integer param passed to the fine_tune method ?

Thanks in advance !

Hi Yacine,

You pass the number of epochs you want the model to train, aka the number of times the models gets to improve using the entire dataset.

For more details, have a look at my answer here: "fine_tune" vs. "fit_one_cycle" - #7 by zerotosingularity

1 Like

thanks a lot ! checking your linked answer right now

Small update: in v2.7.12 (PyTorch 2.0.0) you can use the PILImage again to make a prediction:

img_file = "my_image.jpg"
img = PILImage.create(img_file)


is_bird,_,probs = learn.predict(PILImage.create('bird.jpg'))
print(f"This is a: {is_bird}.")
print(f"Probability it's a bird: {probs[0]:.4f}")

For this last cell in Lesson 1’s code, how do we know which index of probs is referring to bird? I tried a very simple change in the notebook by changing all the ‘bird’ to ‘dog’ but to get the relevant prediction I had to use ‘probs[1]’ instead of ‘probs[0]’. What gives?