02: Production

Taking football classifier from previous exercise, improving it and putting it into production.

Can see app live here on hugging faceopen in new window and here's the iframe:

Setup

Import fastbook and patch IPython for VS Code

from fastbook import *
from fastai.vision.widgets import * 
from IPython.display import clear_output, DisplayHandle
def update_patch(self, obj):
    clear_output(wait=True)
    self.display(obj)
DisplayHandle.update = update_patch

Use the same dataset from previous exercise

data_path = Path('data')/'01'
data_path.mkdir(parents=True,exist_ok=True)

Download Dataset

searches = "rugby","afl","nfl","soccer"
dataset_path = data_path/"datasets"

Build Data Block

failed = verify_images(get_image_files(dataset_path))
failed.map(Path.unlink)
(#0) []
football = DataBlock(
    blocks=(ImageBlock, CategoryBlock),
    get_items=get_image_files,
    splitter=RandomSplitter(valid_pct=0.2, seed=42),
    get_y=parent_label,
    item_tfms=[Resize(192, method='squish')]
)

dls = football.dataloaders(dataset_path)
dls.valid.show_batch(max_n=4, nrows=1)

png

Augment Images

football = football.new(
    item_tfms=RandomResizedCrop(192, min_scale=0.5),
    batch_tfms=aug_transforms()
)
dls = football.dataloaders(dataset_path)
dls.train.show_batch(max_n=4, nrows=1, unique=True)

png

Train Model

learn = vision_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(8)
epochtrain_lossvalid_losserror_ratetime
01.8927161.6072850.55172400:00
11.7838881.2935170.44827600:00
21.5534031.1017680.39655200:00
31.3867931.0800310.34482800:00
41.2143101.0752270.32758600:00
51.0764311.0766230.31034500:00
60.9650851.0752640.27586200:00
70.8829931.0807410.25862100:00

Confusion Matrix

interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()

png

Show examples of what's causing problems

interp.plot_top_losses(5, nrows=1, figsize=(17,4))

png

sport,_,probs = learn.predict(PILImage.create(data_path/'nfl.jpg'))
print(f"this is {sport}")
print("\n--probabilities--")
for i, o in enumerate(dls.vocab):
    print(f"{o}: {probs[i]:.4f}")
this is nfl

--probabilities--
afl: 0.0000
nfl: 1.0000
rugby: 0.0000
soccer: 0.0000

Export the model

learn.export("football-classifier/model.pkl")
learn.export("model.pkl")

Build script to put it into production on HuggingFace

#|default_exp app
#|export
from fastai.vision.all import *
import gradio as gr
#|export
learn = load_learner('model.pkl')
#|export
categories = ('afl', 'nfl', 'rugby', 'soccer')

def classify_image(img):
    _,_,probs = learn.predict(img)
    return dict(zip(categories, map(float,probs)))
im = PILImage.create('data/01/afl.jpg')
im.thumbnail((192,192))
im

png

classify_image(im)
{'afl': 0.9970560073852539,
 'nfl': 0.0002015349455177784,
 'rugby': 0.0019157134229317307,
 'soccer': 0.0008266967488452792}
#|export
image = gr.inputs.Image(shape=(192,192))
label = gr.outputs.Label()
examples = [f'data/01/{i}.jpg' for i in categories]

intf = gr.Interface(fn=classify_image, inputs=image, outputs=label, examples=examples)
intf.launch(inline=False)
/home/j/src/fastai-course/.venv/lib/python3.11/site-packages/gradio/inputs.py:259: UserWarning: Usage of gradio.inputs is deprecated, and will not be supported in the future, please import your component from gradio.components
  warnings.warn(
/home/j/src/fastai-course/.venv/lib/python3.11/site-packages/gradio/inputs.py:262: UserWarning: `optional` parameter is deprecated, and it has no effect
  super().__init__(
/home/j/src/fastai-course/.venv/lib/python3.11/site-packages/gradio/outputs.py:197: UserWarning: Usage of gradio.outputs is deprecated, and will not be supported in the future, please import your components from gradio.components
  warnings.warn(
/home/j/src/fastai-course/.venv/lib/python3.11/site-packages/gradio/outputs.py:200: UserWarning: The 'type' parameter has been deprecated. Use the Number component instead.
  super().__init__(num_top_classes=num_top_classes, type=type, label=label)


Running on local URL:  http://127.0.0.1:7861

To create a public link, set `share=True` in `launch()`.

Export the script ready to push to Hugging Face

from nbdev import export

export.nb_export('02-exercise.ipynb', 'football-classifier')