fastai is a nice library for quickly getting started with a deep learning project. It was developed for interactive environments (i.e., Jupyter Notebooks) and using interactive environments, see nbdev. This is nice for most use-cases, however, we eventually run all of our scripts on a headless server without an interactive environment.

This means that we lose some of fastai’s functionality. For example, the ability to display the top loss images during image classification. We would still like this information, though, and we’ve figured out a way to make it work in a non-interactive environment.

Here is some code that causes problems (see the computer vision intro for more information):

interp = Interpretation.from_learner(learn)
interp.plot_top_losses(9)

This works fine in an interactive environment, but does not produce an output that we can save in a script. Other functions, like interp.plot_confusion_matrix(), work fine because they create a matplotlib figure that can be saved. Digging into interp.plot_top_losses() leads us to display_df, which I’ve copied below.

def display_df(df):
    "Display `df` in a notebook or defaults to print"
    try: from IPython.display import display, HTML
    except: return print(df)
    display(HTML(df.to_html()))

display_df calls display, which, as far as I was able to determine, does not produce an output that is easy to consume in a script. So, I created this simplified, two-file example to demonstrate and work on the problem.

# fake.py
def fake_plot_top_losses():
    from IPython.display import HTML, display
    display(HTML("<div>df</div>"))
# mocking_ipython.py
from unittest.mock import MagicMock, patch

from fake import fake_plot_top_losses


def my_HTML(html):
    my_HTML.html = html


ipython_display_mock = MagicMock()
ipython_display_mock.HTML = my_HTML

with patch.dict("sys.modules", {"IPython.display": ipython_display_mock}):
    fake_plot_top_losses()

print(my_HTML.html)

Using the patch.dict context manager, we can replace the IPython.display module with our own mock. We then provide a replacement for the HTML function, which is passed the raw HTML that we want to save.

We are going to adapt this to our wandb logging setup and add an example below once we have it working.