Create Dataset from tensors or images in RAM

I am able to successfully create at Databunch from a list of tensors using the following code:
final_image_list=[fastai.vision.Image(tz) for tz in preds_list]

preds_list is simply a list of tensors extracted from a video using:
t = torch.tensor(np.ascontiguousarray(np.flip(frame, 2)).transpose(2,0,1)).float()/255

when i attempt to load this into a learner, i receive the error “‘Image’ object has no attribute ‘read’”. If i convert the data to a tensor or nd.array, i get the same error. Reviewing source seems to indicate that this is because it is looking specifically for a physical file in disk and cannot actually work from tensors in RAM. Is that correct?

Is there a workaround short of going over to pytorch?

The actual error is below:

Thanks for any input

AttributeError Traceback (most recent call last)
~/anaconda3/envs/devml/lib/python3.7/site-packages/PIL/Image.py in open(fp, mode)
2655 try:
-> 2656 fp.seek(0)
2657 except (AttributeError, io.UnsupportedOperation):

AttributeError: ‘Image’ object has no attribute ‘seek’

During handling of the above exception, another exception occurred:

AttributeError Traceback (most recent call last)
in
----> 1 learn = load_learner(“models”, file=‘final-stage-328-fp32.pkl’, test=final_image_list)

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/basic_train.py in load_learner(path, file, test, **db_kwargs)
611 model = state.pop(‘model’)
612 src = LabelLists.load_state(path, state.pop(‘data’))
–> 613 if test is not None: src.add_test(test)
614 data = src.databunch(**db_kwargs)
615 cb_state = state.pop(‘cb_state’)

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in add_test(self, items, label, tfms, tfm_y)
560 elif isinstance(items, ItemList): items = self.valid.x.new(items.items, inner_df=items.inner_df).process()
561 else: items = self.valid.x.new(items).process()
–> 562 self.test = self.valid.new(items, labels, tfms=tfms, tfm_y=tfm_y)
563 return self
564

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in new(self, x, y, tfms, tfm_y, **kwargs)
627 tfms,tfm_y = ifnone(tfms, self.tfms),ifnone(tfm_y, self.tfm_y)
628 if isinstance(x, ItemList):
–> 629 return self.class(x, y, tfms=tfms, tfm_y=tfm_y, **self.tfmargs)
630 else:
631 return self.new(self.x.new(x, **kwargs), self.y.new(y, **kwargs), tfms=tfms, tfm_y=tfm_y).process()

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in init(self, x, y, tfms, tfm_y, **kwargs)
599 self.y.x = x
600 self.item=None
–> 601 self.transform(tfms, **kwargs)
602
603 def len(self)->int: return len(self.x) if self.item is None else 1

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in transform(self, tfms, tfm_y, **kwargs)
719 def transform(self, tfms:TfmList, tfm_y:bool=None, **kwargs):
720 “Set the tfms and tfm_y value to be applied to the inputs and targets.”
–> 721 _check_kwargs(self.x, tfms, **kwargs)
722 if tfm_y is None: tfm_y = self.tfm_y
723 tfms_y = None if tfms is None else list(filter(lambda t: getattr(t, ‘use_on_y’, True), listify(tfms)))

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in _check_kwargs(ds, tfms, **kwargs)
588 if (tfms is None or len(tfms) == 0) and len(kwargs) == 0: return
589 if len(ds.items) >= 1:
–> 590 x = ds[0]
591 try: x.apply_tfms(tfms, **kwargs)
592 except Exception as e:

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/data_block.py in getitem(self, idxs)
116 “returns a single item based if idxs is an integer or a new ItemList object if idxs is a range.”
117 idxs = try_int(idxs)
–> 118 if isinstance(idxs, Integral): return self.get(idxs)
119 else: return self.new(self.items[idxs], inner_df=index_row(self.inner_df, idxs))
120

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/vision/data.py in get(self, i)
269 def get(self, i):
270 fn = super().get(i)
–> 271 res = self.open(fn)
272 self.sizes[i] = res.size
273 return res

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/vision/data.py in open(self, fn)
265 def open(self, fn):
266 “Open image in fn, subclass and overwrite for custom behavior.”
–> 267 return open_image(fn, convert_mode=self.convert_mode, after_open=self.after_open)
268
269 def get(self, i):

~/anaconda3/envs/devml/lib/python3.7/site-packages/fastai/vision/image.py in open_image(fn, div, convert_mode, cls, after_open)
391 with warnings.catch_warnings():
392 warnings.simplefilter(“ignore”, UserWarning) # EXIF warning from TiffPlugin
–> 393 x = PIL.Image.open(fn).convert(convert_mode)
394 if after_open: x = after_open(x)
395 x = pil2tensor(x,np.float32)

~/anaconda3/envs/devml/lib/python3.7/site-packages/PIL/Image.py in open(fp, mode)
2656 fp.seek(0)
2657 except (AttributeError, io.UnsupportedOperation):
-> 2658 fp = io.BytesIO(fp.read())
2659 exclusive_fp = True
2660

AttributeError: ‘Image’ object has no attribute ‘read’

Indeed, fastai’s ImageList expects filenames and not tensor as its items. As the learner you are loading seems to have been coded with an ImageList, you can’t just pass it a testlist that contains tensors. What you can do is create a databunch from your list of tensors, then do:

learn = load_learner(“models”, file=‘final-stage-328-fp32.pkl’)
learn.data = your_databunch

That is the easiest workaround I can think of, though I’m not too sure this will work. Fastai for sure works best with de datablock API, so maybe you would need to subclass ImageList, force your subclass to store the tensors in RAM and then create a databunch from it.

Thx @florobax. I’m working on a pytorch Tensor dataset to no avail. I’ll post code if o can get it to work.