Large-Scale Serverless Machine Learning Inference with Azure Functions
Tags: python, serverless, machinelearning, showdev
Published: 2019-09-05 16:30:35

---
title: "Large-Scale Serverless Machine Learning Inference with Azure Functions"
published: true
description: How to use Python Azure Functions with TensorFlow to perform image classification at large scale
tags: python, serverless, machinelearning, showdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/5ghd4555k0hck2ueoq7x.png
series: Serverless September
canonical_url: https://anthonychu.ca/post/serverless-machine-learning-inference-azure-functions/
---

> This article is part of [#ServerlessSeptember]( https://dev.to/azure/serverless-september-content-collection-2fhb). You'll find other helpful articles, detailed tutorials, and videos in this all-things-Serverless content collection. New articles are published every day — that's right, every day — from community members and cloud advocates in the month of September.
>
> Find out more about how Microsoft Azure enables your Serverless functions at [https://docs.microsoft.com/azure/azure-functions/](https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=servsept_devto-blog-cxa).

Azure Functions recently [announced](https://azure.microsoft.com/blog/announcing-the-general-availability-of-python-support-in-azure-functions/?WT.mc_id=servsept_devto-blog-antchu) the general availability of their Python language support. We can use Python 3.6 and Python's large ecosystem of packages, such as TensorFlow, to build serverless functions. Today, we'll look at how we can use TensorFlow with Python Azure Functions to perform large-scale machine learning inference.

## Overview

A common machine learning task is the classification of images. Image classification is a compute-intensive task that can be slow to execute. And if we need to perform classification on a stream of images, such as those coming from an IoT camera, we would need to provision a lot of infrastructure to get enough computational power to keep up with the volume and velocity of images that are being generated.

Because serverless platforms like Azure Functions automatically scale out with demand, we can use them to perform machine learning inferencing and be confident that they can keep up with high-volume workloads.

Without scaling, this is how slowly our app currently runs:

![GIF](https://thepracticaldev.s3.amazonaws.com/i/ri9cmt68ywkxt66qyv5h.gif)

<!--more-->

The application is pretty straightforward. Here are the key parts:

- [**Azure Storage Queue**](https://docs.microsoft.com/azure/storage/queues/storage-queues-introduction?WT.mc_id=servsept_devto-blog-antchu) is a low-cost but highly scalable message queue. We're create a message on the queue with the URL for each image that we want to classify.
- [**Azure Functions**](https://docs.microsoft.com/azure/azure-functions/functions-overview?WT.mc_id=servsept_devto-blog-antchu) is Azure's serverless functions platform. For each image URL in the queue, a Python function will run a TensorFlow model and classify the image. Azure Functions is able to scale out and parallelize this work.
- [**Azure SignalR Service**](https://docs.microsoft.com/azure/azure-signalr/?WT.mc_id=servsept_devto-blog-antchu) is a fully managed real-time message service that supports protocols like WebSockets. Each classification result is broadcast to a status page running in one or more browsers using SignalR Service.

![Overview](https://thepracticaldev.s3.amazonaws.com/i/9fjprwmzjrm0w2hbhlmp.png)

## Build the app

The app we're building will run an image through a TensorFlow model to predict if it contains a cat or a dog. It consists of the Azure services above. We will first build and run the function app locally.

### Create the Azure services

We start by provisioning the following Azure services in the Azure portal.

1. Create an Azure Function app with the following parameters:
    - Linux consumption plan
    - Python
    - New Storage account (we'll also create our queue in this account)
2. Create an Azure SignalR Service account with the following parameters:
    - Same region as your function app
    - Free tier

### Create the function app

Next, we'll create a Python function app using the Azure Functions CLI. For the complete details, take a look at this [Python Azure Functions machine learning tutorial](https://docs.microsoft.com/azure/azure-functions/functions-machine-learning-tensorflow?WT.mc_id=servsept_devto-blog-antchu).

```bash
func init --worker-runtime python
```

Next, we'll create a function named `classifyimage` that triggers whenever there's a message in our queue.

```bash
func new --template AzureQueueStorageTrigger --name classifyimage
```

A function is created in a folder named `classifyimage`.

To broadcast images using Azure SignalR Service using its Azure Functions bindings, we need to add the extension to our function app. One way to do that is by running this command.

```bash
func extensions install -p Microsoft.Azure.WebJobs.Extensions.SignalRService -v 1.0.0
```

We'll edit our function in a bit. But first, we need to import a TensorFlow model that we'll use to classify the images.

### Import a TensorFlow model

For this app, we import a TensorFlow model that we've trained using Azure Custom Vision Service that classifies images as "cat" or "dog". For information on how to train and export your own model to recognize almost anything you can think of, check out [these instructions](https://github.com/Azure-Samples/functions-python-tensorflow-tutorial/blob/master/train-custom-vision-model.md).

The model consists of `model.pb` and `labels.txt`. There's a model [here](https://github.com/Azure-Samples/functions-python-tensorflow-tutorial/tree/master/resources/model) that has already been trained. We can copy the files into the folder that contains the `classifyimage` function. 

### Use the model in the function

We'll need some packages such as TensorFlow. Add them to `requirements.txt` and install them:

```txt
azure-functions
tensorflow
Pillow
requests
```

```bash
pip install --no-cache-dir -r requirements.txt
```

`classifyimage/function.json` describes the trigger, inputs, and outputs of the function. We'll update the queue name to `images` and add a SignalR Service output binding to the function.

```json
{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "msg",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "images",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "signalR",
      "direction": "out",
      "name": "$return",
      "hubName": "imageclassification"
    }
  ]
}
```

Then we'll update the body of our function (`classifyimage/__init__.py`) to download the image using the URL from the queue message, run the TensorFlow model, and return the result.

```python
import logging
import azure.functions as func
import json
from .predict import predict_image_from_url

def main(msg: func.QueueMessage) -> str:
    image_url = msg.get_body().decode('utf-8')
    results = predict_image_from_url(image_url)
    logging.info(f"{results['predictedTagName']} {image_url}")
    return json.dumps({
        'target': 'newResult',
        'arguments': [{
            'predictedTagName': results['predictedTagName'],
            'url': image_url
        }]
    })
```

Most of the work is done by the helper functions in `predict.py` which can be [found here](https://github.com/Azure-Samples/functions-python-tensorflow-tutorial/blob/master/resources/predict.py) and copied into our function app. The function also returns a message that is broadcast over Azure SignalR Service. The message consists of the image URL and the prediction ("cat" or "dog").

### Configure and run the app locally

We configure an Azure Functions app locally using `local.settings.json`. Add the connection strings to our Storage account and SignalR Service.

```json
{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsStorage": "<STORAGE_CONNECTION_STRING>",
    "AzureSignalRConnectionString": "<SIGNALR_CONNECTION_STRING>"
  }
}
```

Now we run the function app.

```bash
func start
```

Using a tool like [Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/?WT.mc_id=servsept_devto-blog-antchu), we create a queue named `images` in our Storage account and add a message containing an image URL. We should see our function execute.

![function logs](https://thepracticaldev.s3.amazonaws.com/i/1tu04m6yvn5iukkr3w64.png)

![function logs](https://thepracticaldev.s3.amazonaws.com/i/ia3e8g2q6p3mef2q658s.png)

## Deploy and run the app at scale

Now that the app runs locally, it's time to deploy it to the cloud!

Run the following Azure Functions Core Tools command to deploy our app to the Azure Function app we created earlier. We're using remote build so that it brings in the proper dependencies required to run on Linux.

```bash
func azure functionapp publish <FUNCTION_APP_NAME> -b remote
```

We also need to configure the Storage account and SignalR Service connection strings in our function app's configuration settings.

To add a lot of image URLs to the queue, run a load generator script like [this one](https://github.com/anthonychu/functions-python-queue-imageclassifier/blob/master/src/generateload/generate_load.py).

> The sample app also contains a [status page](https://github.com/anthonychu/functions-python-queue-imageclassifier/blob/master/src/functionapp/www/index.html) that connects to Azure SignalR Service, receives the classification results, and displays them in real-time. To deploy this page to Azure, check out the details on the [SignalR Service Serverless Developer Guide](https://docs.microsoft.com/azure/azure-signalr/signalr-concept-serverless-development-config?WT.mc_id=servsept_devto-blog-antchu).

With the status page opened in the browser, each time a function executes and classifies an image, it'll push the result to the status page. As more and more messages are added to the queue and the Azure Functions platform detects that the queue length is growing, the function app scales out to more and more instances. The number of images classified per second will go up as the function app scales out.

![GIF](https://thepracticaldev.s3.amazonaws.com/i/vo9sa50y8itobx4in0ma.gif)

## Summary

In this article, we saw that Azure Functions supports Python and its many popular packages, including TensorFlow. It allows us to run machine learning inferencing tasks at a large scale. To learn more, check out these resources:

- [GitHub repo for the sample](https://github.com/anthonychu/functions-python-queue-imageclassifier)
- [Using TensorFlow with Azure Functions](https://docs.microsoft.com/azure/azure-functions/functions-machine-learning-tensorflow?WT.mc_id=servsept_devto-blog-antchu)
- [Azure SignalR Service Serverless Developer Guide](https://docs.microsoft.com/azure/azure-signalr/signalr-concept-serverless-development-config?WT.mc_id=servsept_devto-blog-antchu)