<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nicolas Jaccard</title>
    <description>The latest articles on Forem by Nicolas Jaccard (@nicjac).</description>
    <link>https://forem.com/nicjac</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F774288%2F4227a0da-d66d-4273-9bc2-4d2af5e35bf0.png</url>
      <title>Forem: Nicolas Jaccard</title>
      <link>https://forem.com/nicjac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nicjac"/>
    <language>en</language>
    <item>
      <title>How to Build a Machine Learning Demo in 2022</title>
      <dc:creator>Nicolas Jaccard</dc:creator>
      <pubDate>Sun, 16 Jan 2022 19:35:48 +0000</pubDate>
      <link>https://forem.com/nicjac/how-to-build-a-machine-learning-demo-in-2022-143c</link>
      <guid>https://forem.com/nicjac/how-to-build-a-machine-learning-demo-in-2022-143c</guid>
      <description>&lt;p&gt;Learn &lt;strong&gt;why&lt;/strong&gt; you should build demos for your Machine Learning models in 2022, and &lt;strong&gt;how&lt;/strong&gt; to do it in a way that fits your needs, skills, and audience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--myxH5r__--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6i4oqwnqcr5g2rebrso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--myxH5r__--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6i4oqwnqcr5g2rebrso.png" alt="Header Image" width="880" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✨✨✨&lt;br&gt;
If you like this content, please consider a follow and a ❤️ as I am trying to grow my audience on dev.to! Note that this post and more are available on my personal website (&lt;a href="https://nicjac.dev"&gt;nicjac.dev&lt;/a&gt;). Thanks! 🤗&lt;br&gt;
✨✨✨&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Demos Are Now Essential
&lt;/h2&gt;

&lt;p&gt;Interactive demos of machine learning models are getting increasingly popular. After all, just like a picture paints a thousand words, nothing beats letting others interact directly with your model to generate interest. If you are interested in keeping up with recent trends or are looking for inspiration for your own demos, I highly recommend following the &lt;a href="https://twitter.com/ak92501"&gt;@ak92501 twitter account&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;One example among many is a demo for a model transforming a portrait photograph into an illustration in the style used by the Netflix show Arcane. The ease of use of the demo and ability to quickly test the model with different input photographs was part of the reason why this project became so popular so quickly.&lt;/p&gt;


  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hCWmijgr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jmpu5jdd8s43jf65isq.png" width="880" height="512"&gt;Interactive demo for ArcaneGAN (using [Gradio](#gradio)). Screenshot by author, demo located at https://huggingface.co/spaces/akhaliq/ArcaneGAN"
  


&lt;p&gt;There are many reasons why you might want to build an interactive demo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting a model tested by colleagues during development&lt;/li&gt;
&lt;li&gt;Prototype to seek investment in a new idea&lt;/li&gt;
&lt;li&gt;Disseminate research, potentially as a companion to a research paper&lt;/li&gt;
&lt;li&gt;Build a portfolio of work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever your reason is, this article will provide some pointers and recommendations to make the most of this opportunity.&lt;/p&gt;
&lt;h2&gt;
  
  
  How To Build An Interactive Demo in 2022
&lt;/h2&gt;

&lt;p&gt;There are a variety of ways to build an interactive demo for your Machine Learning model in 2022. Which one you pick will depend on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your target audience&lt;/li&gt;
&lt;li&gt;Your software engineering skills&lt;/li&gt;
&lt;li&gt;Your monetary budget&lt;/li&gt;
&lt;li&gt;Your time budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article will cover three types of approaches: public notebook sharing, full-stack, and app libraries.&lt;/p&gt;
&lt;h3&gt;
  
  
  TLDR - Which Approach Should I Use?
&lt;/h3&gt;

&lt;p&gt;The rest of the article will cover in details what you need to know about these three approaches. If you want a quick answer, the following table should help!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &lt;/th&gt;
&lt;th&gt;Google Colab&lt;/th&gt;
&lt;th&gt;Full-Stack&lt;/th&gt;
&lt;th&gt;App Libraries&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Moderate to High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Target Audience&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Technical&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interactivity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low by Default&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Non-ML dev work required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Significant&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment / Sharing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Difficult&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Costs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Low to High&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time commitment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Small to Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Productization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Case by Case&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rule of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sharing with a technical audience where code visibility is useful and interactivity not critical? Use Google Colab (or equivalent)&lt;/li&gt;
&lt;li&gt;High likelihood for the demo to become a fully fledged product? Going the Full-Stack approach might save you time in the long run&lt;/li&gt;
&lt;li&gt;If none of the above, go with App Libraries and Hugging Face Spaces hosting
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Public Notebook Sharing (Google Colab)
&lt;/h3&gt;

&lt;p&gt;Jupyter notebooks (and iPython before it) played a big part in cementing Python as the leading programming language for machine learning. While not without their faults, by enabling interactive data exploration and iterative development, notebooks quickly became an essential tool for machine learning enthusiasts. However, setting up a Jupyter environment can be challenging and potentially costly if hosting is required for remote access.  &lt;/p&gt;

&lt;p&gt;&lt;a href="//colab.research.google.com"&gt;Google Colab&lt;/a&gt; was a significant disruptor in this area -- it democratized machine learning by offering a fully managed notebook experience without any setup or maintenance required, and provided free access to otherwise costly compute resources.&lt;/p&gt;

&lt;p&gt;Colab made it trivial to share a notebook and have others interact with it, even if it required GPU acceleration. For example, the &lt;a href="https://colab.research.google.com/github/fastai/fastai/blob/master/nbs/quick_start.ipynb"&gt;fastai documentation&lt;/a&gt; or even the recent &lt;a href="https://colab.research.google.com/github/fastai/fastbook/blob/master/01_intro.ipynb"&gt;fastai book&lt;/a&gt; are made available as Colab notebooks, allowing one to run and modify code as they go through the material.&lt;/p&gt;


  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yZOyQJNO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/livdhfwwua4tgryryzjp.png" width="880" height="973"&gt;Screenshot of the quick start notebook for fastai in Google Colab. Screenshot by author, notebook located at https://colab.research.google.com/github/fastai/fastai/blob/master/nbs/quick_start.ipynb
  


&lt;p&gt;Most notebooks can be made to work on Colab without much work required, and some widgets can be used to let users input their own data. If the notebook is versioned on a public Github repo, all it takes to share it is share a link with the following format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://colab.research.google.com/github/$ACCOUNT/$REPO/blob/$BRANCH/$PATH_TO_NOTEBOOK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;$ACCOUNT&lt;/code&gt; is the Github account, &lt;code&gt;$REPO&lt;/code&gt; the repository, &lt;code&gt;$BRANCH&lt;/code&gt; the branch, and &lt;code&gt;$PATH_TO_NOTEBOOK&lt;/code&gt; the full path the the &lt;code&gt;ipynb&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Colab notebooks are not the best option if you are interested in sharing your work with the general public. However, they are very powerful tools to easily convey ideas to technical peers. So much so that pretty much all new developments in machine learning tend to come with a companion Colab notebook as standard. As an example, I explored a brand new approach to &lt;a href="https://arxiv.org/abs/2111.06377"&gt;patch-based self-supervision&lt;/a&gt; using the &lt;a href="https://colab.research.google.com/github/facebookresearch/mae/blob/main/demo/mae_visualize.ipynb"&gt;Colab provided&lt;/a&gt; with my own input data (in this case, photographs of my cat Jasmine). It allowed me to get a much better understanding of this new research, at no cost to me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xzuK-xKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccfa471j5xjz59x5xozw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xzuK-xKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccfa471j5xjz59x5xozw.png" width="880" height="351"&gt;&lt;/a&gt;&lt;br&gt;Screenshot of a Google Colab for a new self-supervision method featuring my cat Jasmine, notebook located at &lt;a href="https://colab.research.google.com/github/facebookresearch/mae/blob/main/demo/mae_visualize.ipynb"&gt;https://colab.research.google.com/github/facebookresearch/mae/blob/main/demo/mae_visualize.ipynb&lt;/a&gt;
  &lt;/p&gt;

&lt;p&gt;Overall, interactivity is pretty limited. A possible way around this is the use of a library such as &lt;a href="https://gradio.app/"&gt;Gradio&lt;/a&gt;, which allows the creation of basic user interfaces directly in a notebook. Gradio will be covered in detail in the app libraries section.&lt;/p&gt;

&lt;p&gt;For completeness' sake, I should mention that Amazon Web Services announced &lt;a href="https://aws.amazon.com/sagemaker/studio-lab/"&gt;SageMaker Studio Lab&lt;/a&gt;, which is similar to Google Colab with some advantages such as persistent storage. I haven't had a chance to explore it yet, but it could in theory be used in a similar way to Google Colab. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pros of Colab notebooks&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free access to GPU compute&lt;/li&gt;
&lt;li&gt;Tight integration with Git to facilitate sharing&lt;/li&gt;
&lt;li&gt;Fully managed, no setup or maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cons of Colab notebooks&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited to technical audiences, no suitable for a lay audience&lt;/li&gt;
&lt;li&gt;Limited interactivity by default, can be improved with libraries such as Gradio&lt;/li&gt;
&lt;li&gt;GPU availability can be hit or miss&lt;/li&gt;
&lt;li&gt;Some external storage required (e.g. to store model artefacts)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Full-stack
&lt;/h3&gt;

&lt;p&gt;This approach to creating an interactive demo is the most demanding, but potentially one that will pay off in the long run. It is full-stack, because it involves two components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;back end&lt;/strong&gt; responsible for loading and serving the model as a REST API&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;front end&lt;/strong&gt; to provide UI elements to interact with the back-end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The obvious downside is that it requires to be comfortable working on both those components, or at least be willing to learn. &lt;strong&gt;However, this approach is the most flexible, and can be used as a stepping stone to deploy a fully fledged production environment without starting from scratch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before diving into the back and front end components below, let's have a look at the pros and cons of the full-stack approach.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pros of the full-stack approach&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As flexible as needed&lt;/li&gt;
&lt;li&gt;Can include additional features such as authentication&lt;/li&gt;
&lt;li&gt;Can be used as a basis for production deployment without starting from scratch&lt;/li&gt;
&lt;li&gt;Can be optimized for performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cons of the full-stack approach&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knowledge in back and front end development required&lt;/li&gt;
&lt;li&gt;Time consuming development and deployment&lt;/li&gt;
&lt;li&gt;Requires infrastructure for deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Back End
&lt;/h4&gt;

&lt;p&gt;An exhaustive discussion of the different technology stacks for back end development is out of scope of this article. However, given that most machine learning engineers working on machine learning applications are at least familiar with Python, we will focus on Python-based back end solutions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hWveyw11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrcpfd0f2z1oiveiduj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hWveyw11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mrcpfd0f2z1oiveiduj2.png" width="880" height="313"&gt;&lt;/a&gt;&lt;br&gt;Different tools for back end development: general-purpose web frameworks, serving libraries, and framework-specific serving libraries. Image by the author.
  &lt;/p&gt;

&lt;p&gt;The goal of the back end is to act as a wrapper for a model so that it can be queried via &lt;code&gt;HTTP&lt;/code&gt; requests from the front end, something referred to as &lt;em&gt;model serving&lt;/em&gt;. In order to do so, one would typically use a web framework. For a long time, &lt;a href="https://flask.palletsprojects.com/"&gt;Flask&lt;/a&gt; was the standard for Python-based web frameworks, and is indeed still very popular. However, &lt;a href="https://fastapi.tiangolo.com/"&gt;FastaAPI&lt;/a&gt; is quickly becoming the new favorite, thanks to impressive performance and native support for asynchronous operations. &lt;a href="https://towardsdatascience.com/how-you-can-quickly-deploy-your-ml-models-with-fastapi-9428085a87bf"&gt;This article&lt;/a&gt; is a good starting point to understand how a simple model can be deployed using FastAPI, while this &lt;a href="https://medium.com/@mingc.me/deploying-pytorch-model-to-production-with-fastapi-in-cuda-supported-docker-c161cca68bb8"&gt;tutorial&lt;/a&gt; provides a complete overview of all the steps required to serve a PyTorch model with GPU support.&lt;/p&gt;

&lt;p&gt;Using a general-purpose framework such as FastAPI involves writing a lot of boilerplate code just to get your API endpoint up and running. If deploying a model for a demo is the only thing you are interested in and you do not mind losing some flexibility, you might want to use a specialized serving framework instead. One example is &lt;a href="https://github.com/bentoml/BentoML"&gt;BentoML&lt;/a&gt;, which will allow you to get an optimized serving endpoint for your model up and running much faster and with less overhead than a generic web framework. Framework-specific serving solutions such as &lt;a href="https://www.tensorflow.org/tfx/guide/serving"&gt;Tensorflow Serving&lt;/a&gt; and &lt;a href="https://pytorch.org/serve/"&gt;TorchServe&lt;/a&gt; typically offer optimized performance but can only be used to serve models trained using Tensorflow or PyTorch, respectively.&lt;/p&gt;

&lt;h4&gt;
  
  
  Front End
&lt;/h4&gt;

&lt;p&gt;The front end is responsible for providing a user interface to interact with the back end serving the model. In most cases, it will be a mean to input data (such as text for natural language processing, or images for computer vision) and to display model outputs. Having this user interface live in a web browser makes your demo accessible without additional dependencies. &lt;/p&gt;

&lt;p&gt;Front end development is where you will likely have to leave Python behind. While libraries such as &lt;a href="https://skulpt.org/"&gt;Skulpt&lt;/a&gt; and &lt;a href="https://brython.info/"&gt;Brython&lt;/a&gt; enable the use of Python in the browser, I highly recommend using Javascript as the very large community means that tutorials are numerous, and it will be much easier to seek help if needed. The two most popular libraries to build user interfaces in Javascript are &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; (&lt;a href="https://hackernoon.com/frontend-dev-how-to-build-a-predictive-machine-learning-site-with-react-and-python-part-3"&gt;tutorial for ML demo&lt;/a&gt;) and &lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt; (&lt;a href="https://royleekiat.com/2020/11/05/how-to-build-a-vuejs-frontend-for-your-machine-learning-prediction-input-and-output/"&gt;tutorial for ML demo&lt;/a&gt;). Using a general-purpose framework will give the flexibility needed to tailor the UI to your exact requirements. &lt;/p&gt;

&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Once your back and front end components are ready, they must be deployed somewhere publicly accessible. Again, flexibility is the name of the game here. Services like &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt; offer a managed (and free, depending on usage) experience for deployment of applications. Public cloud providers such as Amazon Web Services, Azure, or Google Cloud could be an option and a small demo would likely fit nicely within their free tier offerings. &lt;/p&gt;

&lt;p&gt;Whatever path you decide to take, I recommend you consider containerization of your demo using Docker. This way, the same exact container image is used for local testing during development and for deployment on your hosting provider, helping avoid bad surprises due to changes in environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  App Libraries
&lt;/h3&gt;

&lt;p&gt;So what if you want something &lt;em&gt;almost&lt;/em&gt; as flexible as what is possible with the full-stack approach, but without the development requirements? Well, you are in luck because the past few years have seen the emergence of Python libraries that allow the creation of impressively interactive demos with only a few lines of code. In this article, we are going to focus on two of the most promising libraries: &lt;a href="https://gradio.app/"&gt;Gradio&lt;/a&gt; and &lt;a href="https://streamlit.io/"&gt;Streamlit&lt;/a&gt;. There are notable differences between the two that will be explored below, but the high level idea is the same: eliminate most of the painful back and front end work outlined in the full-stack section, albeit at the cost of some flexibility.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gradio
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://gradio.app/"&gt;Gradio&lt;/a&gt; was already mentioned in the Google Colab section as it can be used to add interactive elements to notebooks. As shown in the &lt;a href="https://gradio.app/getting_started/"&gt;library's getting started page&lt;/a&gt;, building an interface only takes a few lines of Python code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gradio&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!!"&lt;/span&gt;

&lt;span class="n"&gt;iface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;iface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are working in a notebook, the UI will show right there and then. If running from a script, a browser window will open and point to &lt;code&gt;http://localhost:7860&lt;/code&gt;. The reason why this works is that Gradio essentially runs an API server in the background for you, thus taking care of much of the work discussed in the full-stack section. It used to leverage Flask to create the local API server, but it very recently &lt;a href="https://twitter.com/abidlabs/status/1479895680219029516"&gt;switched to using FastAPI&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In the code snippet above, the &lt;code&gt;greet&lt;/code&gt; function would be replaced with the inference code for your model. Note that both &lt;code&gt;inputs&lt;/code&gt; and &lt;code&gt;outputs&lt;/code&gt; are set to text, so the UI will automatically default to the widgets necessary to handle text-based tasks. Similar widgets exist for most common use-cases, including computer vision and audio processing. In addition, Gradio offers very handy features such as the ability to take a screenshot or for the user to flag if the output shown is unexpected (e.g. if processing failed).&lt;/p&gt;

&lt;p&gt;If you want to share your user interface with the world, using the &lt;code&gt;share=True&lt;/code&gt; argument in the &lt;code&gt;launch&lt;/code&gt; method will provide you with a &lt;code&gt;gradio.app&lt;/code&gt; URL that points to your demo. Note that this is only forwarding request to your machine, so it will only work as long as your script or notebook is running, and the link automatically expires after 72 hours. See the section about hosting below as a way around those limitations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k8CtaKms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57ogoki5n3cdtimyhqzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k8CtaKms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57ogoki5n3cdtimyhqzo.png" width="880" height="192"&gt;&lt;/a&gt;&lt;br&gt;Default Gradio UI for text inputs and outputs produced by a few lines of code. Screenshot by the author.
  &lt;/p&gt;

&lt;p&gt;Gradio is laser-focused on building user interfaces for machine learning models, and this focus means that it will take care of almost everything for you and will work out of the box with very little configuration required. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pros of Gradio&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick and easy setup out of the box&lt;/li&gt;
&lt;li&gt;Runs directly in notebooks&lt;/li&gt;
&lt;li&gt;Absolutely no knowledge of web development required&lt;/li&gt;
&lt;li&gt;Apps are easily shared&lt;/li&gt;
&lt;li&gt;Good selection of built-in UI elements&lt;/li&gt;
&lt;li&gt;Features such as screenshots or output flagging are very handy for demos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cons of Gradio&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited control over the UI layout&lt;/li&gt;
&lt;li&gt;Not suitable for complex apps (e.g. state management, caching)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Streamlit
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://streamlit.io/"&gt;Streamlit&lt;/a&gt; is a library to build and share data apps. Their &lt;a href="https://streamlit.io/gallery"&gt;curated gallery&lt;/a&gt; showcases examples of data visualization apps, dashboards, interactive tutorials, and, of course, machine learning demos. &lt;/p&gt;

&lt;p&gt;Streamlit can be used to build complex applications, which comes at the cost of a higher barrier of entry compared to Gradio. For example, it cannot be run directly in a notebook -- a command line tool is used to start the application from a script. A live reload approach is adopted, whereby changes made to the code are automatically reflected in the application running in the browser, allowing for quick iterations.&lt;/p&gt;

&lt;p&gt;Streamlit comes with advanced features such as caching, which can help prevent long running tasks (for example downloading and preparing a model for inference) to not be ran multiple times unnecessarily and the ability to build stateful applications (where information is preserved for the duration of a user session). Those features enable use-cases beyond simple machine learning demos. On the UI side of things, the library has a large number of built-in widgets and can be further extended through the support of &lt;a href="https://streamlit.io/components"&gt;third-party components&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L5TbC31X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrkub22bl9dqgo26hohx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L5TbC31X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrkub22bl9dqgo26hohx.png" width="880" height="755"&gt;&lt;/a&gt;&lt;br&gt;A streamlit app converting portrait photographs to comic book characters. Screenshot by author, demo located at &lt;a href="https://share.streamlit.io/nathannguyen-dev/comic_me_v1/main.py"&gt;https://share.streamlit.io/nathannguyen-dev/comic_me_v1/main.py&lt;/a&gt;
  &lt;/p&gt;

&lt;p&gt;Streamlit offers a managed service for app sharing called &lt;a href="https://docs.streamlit.io/streamlit-cloud/get-started/deploy-an-app"&gt;Streamlit Cloud&lt;/a&gt;. &lt;a href="https://blog.streamlit.io/deploy-a-private-app-for-free/"&gt;As of this writing&lt;/a&gt;, one private (requiring authentication) and unlimited public apps can be deployed using Streamlit Cloud with the free plan. Alternatively, Streamlit apps are easily containerized and &lt;a href="https://towardsdatascience.com/create-an-awesome-streamlit-app-deploy-it-with-docker-a3d202a636e8"&gt;deployed using Docker&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you are interested in deploying both Gradio and Streamlit apps, Hugging Face Spaces might be the way to go.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pros of Streamlit&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick setup&lt;/li&gt;
&lt;li&gt;Advanced features such as caching and state management allow for complex apps to be built&lt;/li&gt;
&lt;li&gt;Large selection of built-in UI widgets&lt;/li&gt;
&lt;li&gt;Highly customizable UI layout&lt;/li&gt;
&lt;li&gt;Extensible through support for custom third-party components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cons of Streamlit&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sharing applications is not as trivial as it is using Gradio&lt;/li&gt;
&lt;li&gt;Complex apps require &lt;em&gt;some&lt;/em&gt; understanding of advanced web development concepts&lt;/li&gt;
&lt;li&gt;Not compatible with notebooks&lt;/li&gt;
&lt;li&gt;Lacking some basic built-in features for ML demos (e.g. flagging of unexpected inputs/outputs)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Hugging Face Spaces Revolution
&lt;/h4&gt;

&lt;p&gt;Deploying apps developed using either Gradio or Streamlit got a whole lot easier when &lt;a href="https://huggingface.co/"&gt;Hugging Face&lt;/a&gt; added &lt;a href="https://huggingface.co/spaces"&gt;Spaces&lt;/a&gt; to their ecosystem of ML products and tools. Spaces are similar to Github Pages -- code is committed to a repository, and the app is automatically build and served. When creating a space, you pick between Streamlit, Gradio, and Static (which more or less replicates Github Pages' static website hosting capabilities). The Space is then automatically setup to accommodate your library of choice. Useful features such as versioning and the ability for users to like a space make it a great experience for the deployment of a public machine learning demo.&lt;/p&gt;

&lt;p&gt;Similarly to how Google Colab democratized access to compute resources required for state-of-the-art machine learning models, Hugging Face Spaces allow anyone to host a demo for the world to check out. This means that the entire machine learning workflow, from model training to deployment of an interactive demo, can now be carried out for free and almost entirely in Python. &lt;/p&gt;

&lt;p&gt;✨✨✨&lt;br&gt;
If you like this content, please consider a follow and a ❤️ as I am trying to grow my audience on dev.to! Note that this post and more are available on my personal website (&lt;a href="https://nicjac.dev"&gt;nicjac.dev&lt;/a&gt;). Thanks! 🤗&lt;br&gt;
✨✨✨&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>deeplearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Good practices for neural network training: identify, save, and document best models</title>
      <dc:creator>Nicolas Jaccard</dc:creator>
      <pubDate>Tue, 04 Jan 2022 10:59:14 +0000</pubDate>
      <link>https://forem.com/nicjac/good-practices-for-neural-network-training-identify-save-and-document-best-models-47dp</link>
      <guid>https://forem.com/nicjac/good-practices-for-neural-network-training-identify-save-and-document-best-models-47dp</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article was originally posted on my &lt;a href="https://nicjac.dev/posts/identify-best-model/" rel="noopener noreferrer"&gt;personal blog&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preamble
&lt;/h2&gt;

&lt;p&gt;In this post, we are going to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduce the concept of &lt;em&gt;best model&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Discuss how the &lt;em&gt;best model&lt;/em&gt; can be identified, saved, and documented during training&lt;/li&gt;
&lt;li&gt;Explore how to leverage fastai and Weights &amp;amp; Biases to do all of this (almost) automatically and effortlessly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is a &lt;em&gt;best model&lt;/em&gt; and why should I care?
&lt;/h2&gt;

&lt;p&gt;Model training can be seen as the generation of subsequent versions of a model  --  after each batch, the model weights are adjusted, and as a result, a new version of the model is created. Each new version will have varying levels of performance (as evaluated against a validation set).&lt;/p&gt;

&lt;p&gt;If everything goes well, training and validation loss will decrease with the number of training epochs. However, the best performing version of a model (here abbreviated as &lt;em&gt;best model&lt;/em&gt;) is rarely the one obtained at the end of the training process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdr6v216aqboky9xqc1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdr6v216aqboky9xqc1u.png"&gt;&lt;/a&gt;&lt;br&gt;A somewhat typical example of overfitting training curves.
  &lt;/p&gt;

&lt;p&gt;Take a typical overfitting case  --  at first, both training and validation losses decrease as training progresses. At some point, the validation loss might start increasing, even though the training loss continues to decrease; from this point on, subsequent model versions produced during the training process are overfitting the training data. These model versions are less likely to generalize well to unseen data. In this case, the &lt;em&gt;best model&lt;/em&gt; would be the one obtained at the point where the validation loss started to diverge.&lt;/p&gt;

&lt;p&gt;Overfitting is a convenient example, but similar observations would also apply to other dynamics of model training, such as the presence of local maxima or minima.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying and saving the &lt;em&gt;best model&lt;/em&gt; during training
&lt;/h2&gt;

&lt;p&gt;The naive approach to the problem would be to save our model after every epoch during training and to retrospectively select the optimal version based on the training curves. This approach is associated with a couple of notable drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Storage space&lt;/strong&gt;: large models tend to occupy a significant amount of storage when saved, with file sizes reaching 100s of MBs to GBs. Multiply this by the number of epochs, and you end up with a pretty sizeable amount of storage dedicated to saving all versions of a model. This can quickly become problematic, especially when training models remotely. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Computational impact&lt;/strong&gt;: saving a model after every epoch will impact overall training time  --  serialization / export of some models can be computationally intensive and slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8w8hnz1wp6t3gaeay5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8w8hnz1wp6t3gaeay5h.png"&gt;&lt;/a&gt;&lt;br&gt;Naive approach where all model versions are persisted versus the best model only approach, where only the most recent best performing model is persisted.
  &lt;/p&gt;

&lt;p&gt;As an alternative to this brute force approach where all model versions are saved during training, one can be more selective. We know from the above that our &lt;em&gt;best model&lt;/em&gt; is likely one associated with a low validation loss. We can thus formulate a criterion for the selection of our &lt;em&gt;best model&lt;/em&gt;: it must have a lower validation loss than the previous candidate. As pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if current validation loss lower than candidate validation loss:
    save model to disk overwriting previous candidate
    set candidate validation loss to current validation loss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key advantages of this approach is that a) a new model is exported only when the validation loss is improved over the previous best candidate, and b) we only ever have one model version persisted to storage at any given time. As thus, we successfully addressed the two drawbacks of the naive approach. &lt;/p&gt;

&lt;p&gt;Maybe more importantly, only saving the &lt;em&gt;best model&lt;/em&gt; also encourages good practices by requiring the performance evaluation methodology to be decided before training starts, and it removes the temptation to retroactively evaluate other versions of the model on a separate test dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on validation loss, alternative metrics, and model documentation
&lt;/h2&gt;

&lt;p&gt;Up to this point, we used validation loss as our target metric to identify the &lt;em&gt;best model&lt;/em&gt; during training. Why validation loss you might ask? The fact that it is almost always computed during training made it a convenient example to illustrate the concepts discussed in this article. &lt;/p&gt;

&lt;p&gt;However, validation loss might not be that relevant to your particular use-case or domain, and any other metric can be used instead. For classification tasks, accuracy could be a good choice. Similarly, you can choose the target metric to ensure that the &lt;em&gt;best model&lt;/em&gt; is also one that will generalize well to unseen data, for example by using &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.metrics.matthews_corrcoef.html" rel="noopener noreferrer"&gt;Matthews Correlation Coefficient&lt;/a&gt; when dealing with severely imbalanced datasets.&lt;/p&gt;

&lt;p&gt;Whatever target metric you decide to use, it is also important to document other aspects of this particular version of the model. Typically, this would include all performance metrics tracked during training. Persisting this information together with the actual model artifact can be very useful later on, for example to rank models obtained from a hyperparameter search or to carry out integration testing when deploying in production (more on this in a future article!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Effortlessly save the &lt;em&gt;best model&lt;/em&gt; during training with fastai
&lt;/h2&gt;

&lt;p&gt;Implementation of best model saving requires alteration of the training loop in order to monitor the target metric and to trigger model saving when an improvement is detected. Many modern frameworks come with this capability built-in. Here, we will be focusing on a fastai implementation, but similar capabilities are likely available for your library of choice. You can still follow along to get an idea how this can be implemented in practice.&lt;/p&gt;

&lt;p&gt;If you are unaware of what fastai is, its &lt;a href="https://github.com/fastai/fastai" rel="noopener noreferrer"&gt;official description is&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;fastai simplifies training fast and accurate neural nets using modern best practices&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The fastai training loop can be modified and extended using &lt;a href="https://docs.fast.ai/callback.core.html" rel="noopener noreferrer"&gt;callback methods&lt;/a&gt; that are called at specific stages of training, for example after an epoch is completed, or at the end of training. Conveniently, the &lt;a href="https://docs.fast.ai/callback.tracker.html#SaveModelCallback" rel="noopener noreferrer"&gt;SaveModelCallback&lt;/a&gt; happens to do (almost) exactly what we need.&lt;/p&gt;

&lt;p&gt;Using the callback couldn't be easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;learner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_one_cycle&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cbs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[...,&lt;/span&gt; &lt;span class="nc"&gt;SaveModelCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;valid_loss&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;learner&lt;/code&gt; is a standard fastai &lt;a href="https://docs.fast.ai/learner.html#Learner" rel="noopener noreferrer"&gt;Learner object&lt;/a&gt;. By default, the callback will track the validation loss to determine when to save a new &lt;em&gt;best model&lt;/em&gt;. Use the &lt;code&gt;monitor&lt;/code&gt; argument to set it to any other metric tracked by your &lt;code&gt;learner&lt;/code&gt; object. Following each epoch during training, the current value for the target metric is compared to the previous best value - if it is an improvement, the model is persisted in the &lt;code&gt;models&lt;/code&gt; directory (and overwriting the previous best candidate, if present). &lt;/p&gt;

&lt;p&gt;Behind the scene, the callback tries to figure whether an improvement is a smaller value (if the target metric contains &lt;code&gt;loss&lt;/code&gt; or &lt;code&gt;error&lt;/code&gt;) or a larger value (everything else). This behavior can be overridden using the &lt;code&gt;comp&lt;/code&gt; argument. The model is persisted using fastai's &lt;a href="https://docs.fast.ai/learner.html#Learner.save" rel="noopener noreferrer"&gt;&lt;code&gt;save_model&lt;/code&gt;&lt;/a&gt; function, which is a wrapper for Pytorch's native &lt;a href="https://pytorch.org/docs/stable/generated/torch.save.html" rel="noopener noreferrer"&gt;&lt;code&gt;torch.save&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reason why the built-in callback is not &lt;em&gt;exactly&lt;/em&gt; what we need is that it will only log the target metric used to identify the &lt;em&gt;best model&lt;/em&gt;, and nothing else. It will not log other metrics (for example accuracy, if the &lt;em&gt;best model&lt;/em&gt; is determined based on validation loss). This might be fine, but given that our &lt;em&gt;best model&lt;/em&gt; might end up being used as part of a product somewhere, it would be a good idea to characterize it as much as possible. I put together a custom version of the &lt;code&gt;SaveModelCallback&lt;/code&gt; that will log all metrics tracked by fastai during training. The code for can be found &lt;a href="https://gist.github.com/nicjac/b363d2454ea253570a54e5e178e7666a" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This custom version of the callback can be used as a drop-in replacement. All it really does is to internally keep track of a dictionary of metrics (&lt;code&gt;last_saved_metadata&lt;/code&gt;) associated with the &lt;em&gt;best model&lt;/em&gt;. How to make use of this? All is to be revealed in the next section!&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatically document the &lt;em&gt;best model&lt;/em&gt; with Weights &amp;amp; Biases
&lt;/h2&gt;

&lt;p&gt;Saving the &lt;em&gt;best model&lt;/em&gt; locally is a good start, but it can quickly become unwieldy if you work remotely, or carry out large number of experiments. So how to keep track of the models created, and of their associated metrics? This is where &lt;a href="https://wandb.ai/site" rel="noopener noreferrer"&gt;Weights &amp;amp; Biases&lt;/a&gt; comes in. W&amp;amp;B is one of those tools that make you wonder how you have ever been able to properly function without them. While officially described as "The developer-first MLOps platform", I prefer to refer to it as the swiss army knife of MLOps. &lt;/p&gt;

&lt;p&gt;W&amp;amp;B is very useful to track and compare experiments. However, for the purpose of this article, we are mainly interested in its almost universal versioning capabilities. In the W&amp;amp;B ecosystem, &lt;a href="https://wandb.ai/site/artifacts" rel="noopener noreferrer"&gt;artifacts&lt;/a&gt; are components that can be versioned, possibly together with their lineage. Models can be versioned as artifacts.&lt;/p&gt;

&lt;p&gt;Conveniently, fastai has a built-in callback to integrate with W&amp;amp;B, aptly named &lt;a href="https://docs.fast.ai/callback.wandb.html#WandbCallback" rel="noopener noreferrer"&gt;&lt;code&gt;WandbCallback&lt;/code&gt;&lt;/a&gt;. To use it, one need to initialize a W&amp;amp;B run, and to add the callback to the learner object like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Import W&amp;amp;B package
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wandb&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize W&amp;amp;B run (can potentially set project name, run name, etc...)
&lt;/span&gt;&lt;span class="n"&gt;wandb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Add Callback to learner to track training metrics and log best models
&lt;/span&gt;&lt;span class="n"&gt;learn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;learner&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;cbs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;WandbCallback&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main purpose of the callback is to log useful telemetry regarding the training process to your W&amp;amp;B account, including environment information and metrics. The magic happens when it is used in combination with the &lt;code&gt;SaveModelCallback&lt;/code&gt; -- at the end of the training process, the best performing model will be automatically logged as an artifact of the W&amp;amp;B run.&lt;/p&gt;

&lt;p&gt;There is one major issue with the default &lt;code&gt;WandbCallback&lt;/code&gt;: the metadata associated with the model is recorded at the end of the run and not at the epoch when the &lt;em&gt;best model&lt;/em&gt; was saved. In other words, the metadata &lt;strong&gt;does not&lt;/strong&gt; correspond to the saved model at all, and can be misleading (for example when the tracked metric diverged towards the end of training due to overfitting).&lt;/p&gt;

&lt;p&gt;This is where the custom &lt;code&gt;SaveModelCallback&lt;/code&gt; that was discussed in the previous section comes in. It will save all the information needed to associate the model with its &lt;em&gt;actual&lt;/em&gt; metadata. To take advantage of this, it is also necessary to use a custom version of &lt;code&gt;WandbCallback&lt;/code&gt;, which can be found &lt;a href="https://gist.github.com/nicjac/9efb56cccd57f9c84910f02ccabf6fac" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The changes made in the custom callback are highlighted here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;after_fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_saved_path&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;WandbCallback could not retrieve a model to upload&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;log_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_saved_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_saved_metadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;metadata_key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_saved_metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;wandb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;best_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;metadata_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_saved_metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;metadata_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="sb"&gt;``&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result, the following will automatically happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model logged to the W&amp;amp;B run is associated with metadata containing the correct metric values&lt;/li&gt;
&lt;li&gt;The values for all metrics for the &lt;em&gt;best model&lt;/em&gt; are added to the run summary, with the prefix &lt;code&gt;best_&lt;/code&gt;. This allows runs to be sorted and compared based on the performance of their respective &lt;em&gt;best model&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhye8o2pt2okbelh44ctm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhye8o2pt2okbelh44ctm.png"&gt;&lt;/a&gt;&lt;br&gt;Best model logged in Weights and Biases. (Left) Model metadata including key metrics; (Right) Models in a W&amp;amp;B project sorted by the &lt;code&gt;best_matthews_corrcoef&lt;/code&gt; metadata associated with their respective &lt;em&gt;best models&lt;/em&gt;
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;So, what have we learned in this article?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only saving the &lt;em&gt;best model&lt;/em&gt; during training is efficient and encourages good practices&lt;/li&gt;
&lt;li&gt;The metadata, including key metrics associated with the &lt;em&gt;best model&lt;/em&gt;, is almost as important as the model artifact itself&lt;/li&gt;
&lt;li&gt;Using fastai and Weights &amp;amp; Biases, saving and documenting the &lt;em&gt;best model&lt;/em&gt; can be done automatically for you. Two custom callback functions were described to make this process even better (&lt;a href="https://gist.github.com/nicjac/b363d2454ea253570a54e5e178e7666a" rel="noopener noreferrer"&gt;SaveModelCallback&lt;/a&gt; and &lt;a href="https://gist.github.com/nicjac/9efb56cccd57f9c84910f02ccabf6fac" rel="noopener noreferrer"&gt;WandbCallback&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>ai</category>
      <category>python</category>
    </item>
  </channel>
</rss>
