Inference Learner
Intermediate tutorial, explains how to create a Learner for inference
Create a Learner for inference
In this tutorial, we’ll see how the same API allows you to create an empty DataBunch
for a Learner
at inference time (once you have trained your model) and how to call the predict
method to get the predictions on a single item.
Note: As usual, this page is generated from a notebook that you can find in the docs_src
folder of the fastai repo. We use the saved models from this tutorial to have this notebook run quickly.
Vision
To quickly get acces to all the vision functionality inside fastai, we use the usual import statements.
from fastai.vision import *
A classification problem
Let’s begin with our sample of the MNIST dataset.
mnist = untar_data(URLs.MNIST_TINY)
tfms = get_transforms(do_flip=False)
It’s set up with an imagenet structure so we use it to split our training and validation set, then labelling.
data = (ImageList.from_folder(mnist)
.split_by_folder()
.label_from_folder()
.add_test_folder('test')
.transform(tfms, size=32)
.databunch()
.normalize(imagenet_stats))
Now that our data has been properly set up, we can train a model. We already did in the look at your data tutorial so we’ll just load our saved results here.
learn = cnn_learner(data, models.resnet18).load('mini_train')
Once everything is ready for inference, we just have to call learn.export
to save all the information of our Learner
object for inference: the stuff we need in the DataBunch
(transforms, classes, normalization…), the model with its weights and all the callbacks our Learner
was using. Everything will be in a file named export.pkl
in the folder learn.path
. If you deploy your model on a different machine, this is the file you’ll need to copy.
learn.export()
To create the Learner
for inference, you’ll need to use the load_learner
function. Note that you don’t have to specify anything: it remembers the classes, the transforms you used or the normalization in the data, the model, its weigths… The only argument needed is the folder where the ‘export.pkl’ file is.
learn = load_learner(mnist)
You can now get the predictions on any image via learn.predict
.
img = data.train_ds[0][0]
learn.predict(img)
(Category 3, tensor(0), tensor([0.5275, 0.4725]))
It returns a tuple of three things: the object predicted (with the class in this instance), the underlying data (here the corresponding index) and the raw probabilities. You can also do inference on a larger set of data by adding a test set. This is done by passing an ItemList
to load_learner
.
learn = load_learner(mnist, test=ImageList.from_folder(mnist/'test'))
preds,y = learn.get_preds(ds_type=DatasetType.Test)
preds[:5]
tensor([[0.9866, 0.0134],
[0.0019, 0.9981],
[0.9721, 0.0279],
[0.0067, 0.9933],
[0.9966, 0.0034]])
A multi-label problem
Now let’s try these on the planet dataset, which is a little bit different in the sense that each image can have multiple tags (and not just one label).
planet = untar_data(URLs.PLANET_TINY)
planet_tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)
Here each images is labelled in a file named labels.csv
. We have to add train
as a prefix to the filenames, .jpg
as a suffix and indicate that the labels are separated by spaces.
data = (ImageList.from_csv(planet, 'labels.csv', folder='train', suffix='.jpg')
.split_by_rand_pct()
.label_from_df(label_delim=' ')
.transform(planet_tfms, size=128)
.databunch()
.normalize(imagenet_stats))
Again, we load the model we saved in look at your data tutorial.
learn = cnn_learner(data, models.resnet18).load('mini_train')
Then we can export it before loading it for inference.
learn.export()
learn = load_learner(planet)
And we get the predictions on any image via learn.predict
.
img = data.train_ds[0][0]
learn.predict(img)
(MultiCategory blooming;clear;habitation;haze;primary,
tensor([0., 0., 0., 1., 1., 0., 0., 1., 1., 0., 1., 0., 0., 0.]),
tensor([0.1906, 0.3646, 0.3146, 0.6931, 0.6352, 0.3982, 0.3114, 0.5396, 0.5245,
0.3933, 0.6069, 0.1630, 0.4260, 0.2641]))
Here we can specify a particular threshold to consider the predictions to be correct or not. The default is 0.5
, but we can change it.
learn.predict(img, thresh=0.3)
(MultiCategory artisinal_mine;bare_ground;blooming;clear;cloudy;cultivation;habitation;haze;partly_cloudy;primary;selective_logging,
tensor([0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 0.]),
tensor([0.1906, 0.3646, 0.3146, 0.6931, 0.6352, 0.3982, 0.3114, 0.5396, 0.5245,
0.3933, 0.6069, 0.1630, 0.4260, 0.2641]))
A regression example
For the next example, we are going to use the BIWI head pose dataset. On pictures of persons, we have to find the center of their face. For the fastai docs, we have built a small subsample of the dataset (200 images) and prepared a dictionary for the correspondance filename to center.
biwi = untar_data(URLs.BIWI_SAMPLE)
fn2ctr = pickle.load(open(biwi/'centers.pkl', 'rb'))
To grab our data, we use this dictionary to label our items. We also use the PointsItemList
class to have the targets be of type ImagePoints
(which will make sure the data augmentation is properly applied to them). When calling transform
we make sure to set tfm_y=True
.
data = (PointsItemList.from_folder(biwi)
.split_by_rand_pct(seed=42)
.label_from_func(lambda o:fn2ctr[o.name])
.transform(get_transforms(), tfm_y=True, size=(120,160))
.databunch()
.normalize(imagenet_stats))
As before, the road to inference is pretty straightforward: load the model we trained before, export the Learner
then load it for production.
learn = cnn_learner(data, models.resnet18, lin_ftrs=[100], ps=0.05).load('mini_train');
learn.export()
learn = load_learner(biwi)
And now we can a prediction on an image.
img = data.valid_ds[0][0]
learn.predict(img)
(ImagePoints (120, 160),
tensor([[ 2.2184, -0.3693]]),
tensor([ 2.2184, -0.3693]))
To visualize the predictions, we can use the Image.show
method.
img.show(y=learn.predict(img)[0])
A segmentation example
Now we are going to look at the camvid dataset (at least a small sample of it), where we have to predict the class of each pixel in an image. Each image in the ‘images’ subfolder has an equivalent in ‘labels’ that is its segmentations mask.
camvid = untar_data(URLs.CAMVID_TINY)
path_lbl = camvid/'labels'
path_img = camvid/'images'
We read the classes in ‘codes.txt’ and the function maps each image filename with its corresponding mask filename.
codes = np.loadtxt(camvid/'codes.txt', dtype=str)
get_y_fn = lambda x: path_lbl/f'{x.stem}_P{x.suffix}'
The data block API allows us to quickly get everything in a DataBunch
and then we can have a look with show_batch
.
data = (SegmentationItemList.from_folder(path_img)
.split_by_rand_pct()
.label_from_func(get_y_fn, classes=codes)
.transform(get_transforms(), tfm_y=True, size=128)
.databunch(bs=16, path=camvid)
.normalize(imagenet_stats))
As before, we load our model, export the Learner
then create a new one with load_learner
.
learn = unet_learner(data, models.resnet18).load('mini_train');
learn.export()
learn = load_learner(camvid)
And now we can a prediction on an image.
img = data.train_ds[0][0]
learn.predict(img);
To visualize the predictions, we can use the Image.show
method.
img.show(y=learn.predict(img)[0])
Text
Next application is text, so let’s start by importing everything we’ll need.
from fastai.text import *
Language modelling
First let’s look a how to get a language model ready for inference. Since we’ll load the model trained in the visualize data tutorial, we load the DataBunch
used there.
imdb = untar_data(URLs.IMDB_SAMPLE)
data_lm = load_data(imdb)
Like in vision, we just have to type learn.export()
after loading our pretrained model to save all the information inside the Learner
we’ll need. In this case, this includes all the vocabulary we created. The only difference is that we will specify a filename, since we have several model in the same path (language model and classifier).
learn = language_model_learner(data_lm, AWD_LSTM, pretrained=False).load('mini_train_lm', with_opt=False);
learn.export(file = 'export_lm.pkl')
Now let’s define our inference learner.
learn = load_learner(imdb, file = 'export_lm.pkl')
Then we can predict with the usual method, here we can specify how many words we want the model to predict.
learn.predict('This is a simple test of', n_words=20)
'This is a simple test of the critique made out of the concerns on the consequences of it and the called Sub Cooper comparisons'
You can also use beam search to generate text.
learn.beam_search('This is a simple test of', n_words=20, beam_sz=200)
'This is a simple test of This is a simple test of the quality of the English version of the English version . n n The English version is'
Classification
Now let’s see a classification example. We have to use the same vocabulary as for the language model if we want to be able to use the encoder we saved.
data_clas = (TextList.from_csv(imdb, 'texts.csv', cols='text', vocab=data_lm.vocab)
.split_from_df(col='is_valid')
.label_from_df(cols='label')
.databunch(bs=42))
Again we export the Learner
where we load our pretrained model.
learn = text_classifier_learner(data_clas, AWD_LSTM, pretrained=False).load('mini_train_clas', with_opt=False);
learn.export(file = 'export_clas.pkl')
Now let’s use load_learner
.
learn = load_learner(imdb, file = 'export_clas.pkl')
Then we can predict with the usual method.
learn.predict('I really loved that movie!')
(Category negative, tensor(0), tensor([0.8878, 0.1122]))
If we’re performing inference on a larger dataset, we can add it as a test set. This will batch up the items and make inference much faster.
learn.data.add_test(["That movie was terrible!",
"I'm a big fan of all movies with Hal 3000."])
preds,y = learn.get_preds(ds_type=DatasetType.Test)
preds
Tabular
Last application brings us to tabular data. First let’s import everything we’ll need.
from fastai.tabular import *
We’ll use a sample of the adult dataset here. Once we read the csv file, we’ll need to specify the dependant variable, the categorical variables, the continuous variables and the processors we want to use.
adult = untar_data(URLs.ADULT_SAMPLE)
df = pd.read_csv(adult/'adult.csv')
dep_var = 'salary'
cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country']
cont_names = ['education-num', 'hours-per-week', 'age', 'capital-loss', 'fnlwgt', 'capital-gain']
procs = [FillMissing, Categorify, Normalize]
Then we can use the data block API to grab everything together.
data = (TabularList.from_df(df, path=adult, cat_names=cat_names, cont_names=cont_names, procs=procs)
.split_by_idx(valid_idx=range(800,1000))
.label_from_df(cols=dep_var)
.databunch())
We define a Learner
object that we fit and then save the model.
learn = tabular_learner(data, layers=[200,100], metrics=accuracy)
learn.fit(1, 1e-2)
learn.save('mini_train')
epoch | train_loss | valid_loss | accuracy | time |
---|---|---|---|---|
0 | 0.337445 | 0.360488 | 0.845000 | 00:04 |
As in the other applications, we just have to type learn.export()
to save everything we’ll need for inference (here it includes the inner state of each processor).
learn.export()
Then we create a Learner
for inference like before.
learn = load_learner(adult)
And we can predict on a row of dataframe that has the right cat_names
and cont_names
.
learn.predict(df.iloc[0])
(Category >=50k, tensor(1), tensor([0.1976, 0.8024]))
©2021 fast.ai. All rights reserved.
Site last generated: Jan 5, 2021