I am a complete nub, but couldn’t you just write a very basic fuction that masks the fact that you are passing in the training and test that are empty, but have the same data bunch characteristics as what you are trying to classify. Please keep in mind I am just learning, I am thinking that they are needed to create the computation graph. Just a thought.
I was just watching lesson 2 and saw this (and you being mentioned) too
classes = ['black', 'grizzly', 'teddys'] data2 = ImageDataBunch.single_from_classes(path, classes, tfms=get_transforms(), size=224).normalize(imagenet_stats) learn = create_cnn(data2, models.resnet34).load('stage-2') pred_class,pred_idx,outputs = learn.predict(img) pred_class
But after watching half of lesson 2, I come to the conclusion that the scenario encountered by Nick seldom happens. it’s a good-to-have. Sorry Nick
Most of the time you only need to serve one image for prediction
Hey, yeah it’s not massively common I guess. And you could hack it. Something in me really hates doing hacks though!! I just think if we could get the attention of somebody from fastai they’ll just tell us which bit of the API to use. I’ve reverted back to Pytorch + torchvision and used the similar settings and learning rate annealing and its got me to pretty much the same place. I think fastai v1 is still very new so there’s pieces missing. Honestly though, some of the utilities they have for cleaning data etc. are awesome and I haven’t seen them anywhere else. Everything is very long winded in native Pytorch so you end up writing your own helper functions. I think this is where fastai was born out of, them making a friendly API for Pytorch. At this point it’s still probably easier to do some stuff from scratch such as combining image and tabular data.
That said, there’s some really neat tricks built in to fastai such as the differential learning rates which I’ve figured out how to do in Pytorch now but again it is long winded.
I haven’t tested yet but I guess this post can help you. https://forums.fast.ai/t/how-to-get-an-empty-convlearner-for-single-image-prediction/28245/50 . This is for single image but I think I will work with a batch of image too. Load the model you have trained and predict your images in pure Pytorch .
I am facing a similar problem and so do many people. I guess fastai will make a friendly API for this soon
The correct way to do this is to use a test set (it’s literally what test sets are for in fastai). You’ll just have an empty train and validation set in your databunch - which is fine, since you won’t be using them.
DataBunch handles all the serialization for you now of your preprocessors (such as your list of classes), and makes life far easier than doing things manually with Pytorch.
Thanks for the clarification here – That’s what I suspected after reading as much as possible on the forums, but I wasn’t sure
After the course we’ll be simplifying this further, by serializing data processing/metadata with the learner. But I just added some tiny tweaks to make it a bit simpler, as well as adding some docs to the inference tutorial to show an example. https://docs.fast.ai/tutorial.inference.html#A-classification-problem
That’s literally perfect
Great, thanks this is what I was after. I seem to remember trying with an empty train, val dataset but it threw an index out of range error. This looks much simpler. Will give it a shot!
@jeremy that’s working great thanks. One small request though…
LabelLists seems to be taking the path from the location of the original training data, despite me trying to override it. This forces me to replicate the folder structure used to train the model in order to load my test set. This happens even if I explicity set the path of the LabelList object i.e.
sd = LabelLists.load_empty(test_path/'export.pkl', tfms=get_transforms(), size=224).add_test_folder('test') sd.path = test_path empty_data = sd.databunch().normalize(imagenet_stats)
I think the problem lies in this method:
@classmethod def load_empty(cls, fn:PathOrStr, tfms:TfmList=None, tfm_y:bool=False, **kwargs): train_ds = LabelList.load_empty(fn, tfms=tfms, tfm_y=tfm_y, **kwargs) valid_ds = LabelList.load_empty(fn, tfms=tfms, tfm_y=tfm_y, **kwargs) return LabelLists(valid_ds.path, train=train_ds, valid=valid_ds)
Suggest changing it to something like:
def load_empty(cls, fn:PathOrStr, tfms:TfmList=None, tfm_y:bool=False, **kwargs): path = os.path.dirname(fn) train_ds = LabelList.load_empty(fn, tfms=tfms, tfm_y=tfm_y, **kwargs) valid_ds = LabelList.load_empty(fn, tfms=tfms, tfm_y=tfm_y, **kwargs) return LabelLists(path, train=train_ds, valid=valid_ds)
EDIT: My bad, if I override the path before before I add_test_folder then it works. But my suggestion stands…
Just pushed a fix, you should now pass path and fn (defaults to
export.pkl) separately and the path you give will override the one of the training.
Not the most elegant way, but it may be useful to others, so here’s how I did it.
P.S. I don’t classify vans for fun, this is actually for work!
Sorry to hijack this thread, but version 1.034 of the library doesn’t have load_empty under LabelLists
Hey, it’s definitely there. See https://github.com/fastai/fastai/blob/master/fastai/data_block.py#L460
Although I have a feeling (not sure) they may have moved ItemLists to a different file so your error could be a red herring. You might just need to restart your kernel.
import fastai.utils show_install()
Make sure you are in fact using 1.0.34. I haven’t testing the load_empty stuff yet, but it seems like a good way to go about it.
load_empty isn’t available until 1.0.36 according to this: https://github.com/fastai/fastai/blob/master/CHANGES.md#1036-2018-12-08
Major kudos for using CHANGES.md!
As a minor related question, is there a way to ensure that your image transforms are actually being applied? Because I followed @safekidda 's screenshot but my classifier labeled everything as a single class - but if I shuffled the images into my test set things worked fine. The only explanation I can think of is that the images are different dimensions than the transformed training images and that the LabelList method is enforcing a different set of transformations even though my parameters to get_transforms() are the same.
It’s probably not the transforms. Most likely the image size. Also, I don’t know if you followed my code exactly, but I only had two classes so I just sliced the tensor that was returned. You’ll obviously need to do something else such as a max if you have more than two classes.
EDIT: Just read your post again, and I’m not sure what you’re doing. Best post an example. But usually you wouldn’t augment your Val/test set so I don’t think it’s transforms.
On a side note I just looked at the docs for transforms and they’re awesome. Loads of work has gone into this - really nice.
I am a beginner and using fastai ‘1.0.41’ but @jeremy suggestions approach does not work for the Unet Learner. I am bit confuse about it and these are problems:
- The LabelLists.loadempty reads the state x_cls which is not available the exported file from Unet Learner
~/anaconda3/envs/fastaiV1/lib/python3.7/site-packages/fastai/data_block.py in load_state(cls, state)
600 def load_state(cls, state:dict) -> ‘LabelList’:
601 “Create a
–> 602 x = state[‘x_cls’](, path=state[‘path’], processor=state[‘x_proc’], ignore_empty=True)
If I read it normally by
state = pickle.load(open(PATH/‘export.pkl’, ‘rb’))
Then the state’s keys are
dict_keys([‘opt_func’, ‘loss_func’, ‘metrics’, ‘true_wd’, ‘bn_wd’, ‘wd’, ‘train_bn’, ‘model_dir’, ‘callback_fns’, ‘cb_state’, ‘model’, ‘data’, ‘cls’])
- That problem could be from the Unet model description as there are no classes.
- Then, I read the docs and start to use a Data_block API which is really impressive. But the second problem is from the label_empty() function.
- I want to create a general way to get ‘test’ images, without label, in the tensor shape with batch, normalized by imagenet_stats. This is the code
data = (ImageItemList.from_folder(path_img)
~/anaconda3/envs/fastaiV1/lib/python3.7/site-packages/fastai/data_block.py in _inner(*args, **kwargs)
420 assert isinstance(self.train, LabelList)
421 kwargs[‘label_cls’] = self.train.y.class
–> 422 self.valid = fv(*args, **kwargs)
423 self.class = LabelLists
TypeError: label_empty() got an unexpected keyword argument ‘label_cls’
- This may be come from no validation set but I have no idea to fix it.
It is a long reply but hope we can find a way to fix this for Unet learner.