{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Create a Learner for inference" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "hide_input": true }, "outputs": [], "source": [ "from fastai.gen_doc.nbdoc import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we'll see how the same API allows you to create an empty [`DataBunch`](/basic_data.html#DataBunch) for a [`Learner`](/basic_train.html#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." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hide_input": true }, "outputs": [ { "data": { "text/markdown": [ "
Note: As usual, this page is generated from a notebook that you can find in the docs_src folder of the\n", "fastai repo. We use the saved models from this tutorial to\n", "have this notebook run quickly.
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "jekyll_note(\"\"\"As usual, this page is generated from a notebook that you can find in the docs_src folder of the\n", "fastai repo. We use the saved models from this tutorial to\n", "have this notebook run quickly.\"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vision" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To quickly get acces to all the vision functionality inside fastai, we use the usual import statements." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from fastai.vision import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A classification problem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's begin with our sample of the MNIST dataset." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mnist = untar_data(URLs.MNIST_TINY)\n", "tfms = get_transforms(do_flip=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's set up with an imagenet structure so we use it to split our training and validation set, then labelling." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (ImageList.from_folder(mnist)\n", " .split_by_folder() \n", " .label_from_folder()\n", " .add_test_folder('test')\n", " .transform(tfms, size=32)\n", " .databunch()\n", " .normalize(imagenet_stats)) " ] }, { "cell_type": "markdown", "metadata": { "hide_input": true }, "source": [ "Now that our data has been properly set up, we can train a model. We already did in the [look at your data tutorial](/tutorial.data.html) so we'll just load our saved results here." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18).load('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once everything is ready for inference, we just have to call `learn.export` to save all the information of our [`Learner`](/basic_train.html#Learner) object for inference: the stuff we need in the [`DataBunch`](/basic_data.html#DataBunch) (transforms, classes, normalization...), the model with its weights and all the callbacks our [`Learner`](/basic_train.html#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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "markdown", "metadata": { "hide_input": false }, "source": [ "To create the [`Learner`](/basic_train.html#Learner) for inference, you'll need to use the [`load_learner`](/basic_train.html#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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(mnist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can now get the predictions on any image via `learn.predict`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category 3, tensor(0), tensor([0.5275, 0.4725]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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`](/data_block.html#ItemList) to [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(mnist, test=ImageList.from_folder(mnist/'test'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tensor([[0.9866, 0.0134],\n", " [0.0019, 0.9981],\n", " [0.9721, 0.0279],\n", " [0.0067, 0.9933],\n", " [0.9966, 0.0034]])" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preds,y = learn.get_preds(ds_type=DatasetType.Test)\n", "preds[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A multi-label problem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "planet = untar_data(URLs.PLANET_TINY)\n", "planet_tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here each images is labelled in a file named `labels.csv`. We have to add [`train`](/train.html#train) as a prefix to the filenames, `.jpg` as a suffix and indicate that the labels are separated by spaces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (ImageList.from_csv(planet, 'labels.csv', folder='train', suffix='.jpg')\n", " .split_by_rand_pct()\n", " .label_from_df(label_delim=' ')\n", " .transform(planet_tfms, size=128)\n", " .databunch()\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, we load the model we saved in [look at your data tutorial](/tutorial.data.html)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18).load('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can export it before loading it for inference." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(planet)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we get the predictions on any image via `learn.predict`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(MultiCategory blooming;clear;habitation;haze;primary,\n", " tensor([0., 0., 0., 1., 1., 0., 0., 1., 1., 0., 1., 0., 0., 0.]),\n", " tensor([0.1906, 0.3646, 0.3146, 0.6931, 0.6352, 0.3982, 0.3114, 0.5396, 0.5245,\n", " 0.3933, 0.6069, 0.1630, 0.4260, 0.2641]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(MultiCategory artisinal_mine;bare_ground;blooming;clear;cloudy;cultivation;habitation;haze;partly_cloudy;primary;selective_logging,\n", " tensor([0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 0.]),\n", " tensor([0.1906, 0.3646, 0.3146, 0.6931, 0.6352, 0.3982, 0.3114, 0.5396, 0.5245,\n", " 0.3933, 0.6069, 0.1630, 0.4260, 0.2641]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict(img, thresh=0.3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A regression example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the next example, we are going to use the [BIWI head pose](https://data.vision.ee.ethz.ch/cvl/gfanelli/head_pose/head_forest.html#db) 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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "biwi = untar_data(URLs.BIWI_SAMPLE)\n", "fn2ctr = pickle.load(open(biwi/'centers.pkl', 'rb'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To grab our data, we use this dictionary to label our items. We also use the [`PointsItemList`](/vision.data.html#PointsItemList) class to have the targets be of type [`ImagePoints`](/vision.image.html#ImagePoints) (which will make sure the data augmentation is properly applied to them). When calling [`transform`](/tabular.transform.html#tabular.transform) we make sure to set `tfm_y=True`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (PointsItemList.from_folder(biwi)\n", " .split_by_rand_pct(seed=42)\n", " .label_from_func(lambda o:fn2ctr[o.name])\n", " .transform(get_transforms(), tfm_y=True, size=(120,160))\n", " .databunch()\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As before, the road to inference is pretty straightforward: load the model we trained before, export the [`Learner`](/basic_train.html#Learner) then load it for production." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = cnn_learner(data, models.resnet18, lin_ftrs=[100], ps=0.05).load('mini_train');" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(biwi)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can a prediction on an image." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(ImagePoints (120, 160),\n", " tensor([[ 2.2184, -0.3693]]),\n", " tensor([ 2.2184, -0.3693]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "img = data.valid_ds[0][0]\n", "learn.predict(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To visualize the predictions, we can use the [`Image.show`](/vision.image.html#Image.show) method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img.show(y=learn.predict(img)[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A segmentation example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we are going to look at the [camvid dataset](http://mi.eng.cam.ac.uk/research/projects/VideoRec/CamVid/) (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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "camvid = untar_data(URLs.CAMVID_TINY)\n", "path_lbl = camvid/'labels'\n", "path_img = camvid/'images'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We read the classes in 'codes.txt' and the function maps each image filename with its corresponding mask filename." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "codes = np.loadtxt(camvid/'codes.txt', dtype=str)\n", "get_y_fn = lambda x: path_lbl/f'{x.stem}_P{x.suffix}'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The data block API allows us to quickly get everything in a [`DataBunch`](/basic_data.html#DataBunch) and then we can have a look with `show_batch`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (SegmentationItemList.from_folder(path_img)\n", " .split_by_rand_pct()\n", " .label_from_func(get_y_fn, classes=codes)\n", " .transform(get_transforms(), tfm_y=True, size=128)\n", " .databunch(bs=16, path=camvid)\n", " .normalize(imagenet_stats))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As before, we load our model, export the [`Learner`](/basic_train.html#Learner) then create a new one with [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = unet_learner(data, models.resnet18).load('mini_train');\n", "learn.export()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(camvid)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can a prediction on an image." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "img = data.train_ds[0][0]\n", "learn.predict(img);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To visualize the predictions, we can use the [`Image.show`](/vision.image.html#Image.show) method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "img.show(y=learn.predict(img)[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next application is text, so let's start by importing everything we'll need." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from fastai.text import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Language modelling" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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](/tutorial.data.html), we load the [`DataBunch`](/basic_data.html#DataBunch) used there." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "imdb = untar_data(URLs.IMDB_SAMPLE)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_lm = load_data(imdb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like in vision, we just have to type `learn.export()` after loading our pretrained model to save all the information inside the [`Learner`](/basic_train.html#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)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = language_model_learner(data_lm, AWD_LSTM, pretrained=False).load('mini_train_lm', with_opt=False);" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export(file = 'export_lm.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's define our inference learner." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(imdb, file = 'export_lm.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can predict with the usual method, here we can specify how many words we want the model to predict." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'This is a simple test of the critique made out of the concerns on the consequences of it and the called Sub Cooper comparisons'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict('This is a simple test of', n_words=20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use beam search to generate text." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'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'" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.beam_search('This is a simple test of', n_words=20, beam_sz=200)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classification" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_clas = (TextList.from_csv(imdb, 'texts.csv', cols='text', vocab=data_lm.vocab)\n", " .split_from_df(col='is_valid')\n", " .label_from_df(cols='label')\n", " .databunch(bs=42))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again we export the [`Learner`](/basic_train.html#Learner) where we load our pretrained model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = text_classifier_learner(data_clas, AWD_LSTM, pretrained=False).load('mini_train_clas', with_opt=False);\n", "learn.export(file = 'export_clas.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's use [`load_learner`](/basic_train.html#load_learner)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(imdb, file = 'export_clas.pkl')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can predict with the usual method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category negative, tensor(0), tensor([0.8878, 0.1122]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict('I really loved that movie!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.data.add_test([\"That movie was terrible!\", \n", " \"I'm a big fan of all movies with Hal 3000.\"])\n", "\n", "preds,y = learn.get_preds(ds_type=DatasetType.Test)\n", "preds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tabular" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Last application brings us to tabular data. First let's import everything we'll need." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from fastai.tabular import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll use a sample of the [adult dataset](https://archive.ics.uci.edu/ml/datasets/adult) 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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "adult = untar_data(URLs.ADULT_SAMPLE)\n", "df = pd.read_csv(adult/'adult.csv')\n", "dep_var = 'salary'\n", "cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country']\n", "cont_names = ['education-num', 'hours-per-week', 'age', 'capital-loss', 'fnlwgt', 'capital-gain']\n", "procs = [FillMissing, Categorify, Normalize]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we can use the data block API to grab everything together." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data = (TabularList.from_df(df, path=adult, cat_names=cat_names, cont_names=cont_names, procs=procs)\n", " .split_by_idx(valid_idx=range(800,1000))\n", " .label_from_df(cols=dep_var)\n", " .databunch())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define a [`Learner`](/basic_train.html#Learner) object that we fit and then save the model." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
epochtrain_lossvalid_lossaccuracytime
00.3374450.3604880.84500000:04
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "learn = tabular_learner(data, layers=[200,100], metrics=accuracy)\n", "learn.fit(1, 1e-2)\n", "learn.save('mini_train')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn.export()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we create a [`Learner`](/basic_train.html#Learner) for inference like before." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = load_learner(adult)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can predict on a row of dataframe that has the right `cat_names` and `cont_names`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Category >=50k, tensor(1), tensor([0.1976, 0.8024]))" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "learn.predict(df.iloc[0])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "jekyll": { "keywords": "fastai", "summary": "Intermediate tutorial, explains how to create a Learner for inference", "title": "Inference Learner" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.2" } }, "nbformat": 4, "nbformat_minor": 2 }