Deploy Multi-label classifier into production

Hey!

I was wondering if anyone has tried to deploy a multi-label classifier as a web app. There are many great instances of single-label classifiers. e.g. https://towardsdatascience.com/building-web-app-for-computer-vision-model-deploying-to-production-in-10-minutes-a-detailed-ec6ac52ec7e4

I completed the lesson walkthrough for the planet dataset. I was wondering if anyone else had tried to deploy a web app and if so, is there a code sample I can use as a reference? :slight_smile:

Thanks heaps!

Adi

I’m working on deploying every model :slight_smile: The Render walkthrough is a great way to deploy most every type of vision model I’ve found, as they all rely on the same bit of boilerplate code. Let’s take a look at what would be different from our analyze function between the two.
First, single classification based on the example from the course:

@app.route('/analyze', methods=["POST"])
  data = await request.form()
  bytes = await (data['file'].read())
  pred = learn.predict(bytes)[0]
  return JSONResponse({'result':str(pred)})

Now, how do we modify this for multi-label? The only thing that needs to be changed is what happens with our predictions, as our multi-labels (From the planets example) now have a _. All we have to do is something like so:

    for p in pred: p.replace('_', ' ')
    for p in pred: p.title()
    if pred == '[]':
		pred = 'Could not recognize any classes, perhaps try another photo?'
    return JSONResponse({
		'result' : pred
		})

All we changed was making it more readable for the end product. This is using Starlette based on the Render example: Documentation tutorial code

As you can see, the predict function of fastai is what makes this possible :slight_smile:

1 Like

Thanks a lot @muellerzr. I will try and let you know :smiley:

Hey @muellerzr,

I tried deploying the app. Here’s the change I made. Does this look right to you? Sorry if my questions are very basic. :slight_smile:

I left the remaining code as the same except for the modification you suggested. Thank you!

@app.route('/analyze', methods=['POST'])
async def analyze(request):
    img_data = await request.form()
    img_bytes = await (img_data['file'].read())
    img = open_image(BytesIO(img_bytes))
    pred = learn.predict(img)[0]
    for p in pred:
        p.replace('_', ' ')
    for p in pred:
        p.title()
    if pred == '[]':
        pred = 'Could not recognize any classes, perhaps try another photo?'
    return JSONResponse({
        'result': pred
    })

Update**

I reverted to the original walkthrough and it works. :slight_smile:

It looks like the only change was making the output more readable. I can muddle through that no worries!

The good news is I’ll use this approach to deploy apps as it is more approachable than GCP, especially for a newbie like me. Thanks again!

1 Like

Great job :slight_smile:

1 Like

Tried this … My web app gets stuck at ‘Analyzing’. Dont know any web to figure out why.
Any help would be appreciated

What does your console/log say? (the terminal)

May 3 12:13:31 AM INFO: (‘10.104.85.3’, 48262) - “GET / HTTP/1.1” 200
May 3 12:13:32 AM INFO: (‘10.104.85.3’, 48262) - “GET /static/client.js HTTP/1.1” 200
May 3 12:13:32 AM INFO: (‘10.104.85.3’, 48290) - “GET /static/style.css HTTP/1.1” 304
May 3 12:13:32 AM INFO: (‘10.104.85.3’, 48262) - “GET /favicon.ico HTTP/1.1” 404
May 3 12:13:47 AM INFO: (‘10.104.85.3’, 48758) - “POST /analyze HTTP/1.1” 500
May 3 12:13:47 AM ERROR: Exception in ASGI application
May 3 12:13:47 AM Traceback (most recent call last):
File “/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py”, line 368, in run_asgi
result = await app(self.scope, self.receive, self.send)
File “/usr/local/lib/python3.7/site-packages/starlette/applications.py”, line 133, in call
await self.error_middleware(scope, receive, send)
File “/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py”, line 122, in call
raise exc from None
File “/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py”, line 100, in call
await self.app(scope, receive, _send)
File “/usr/local/lib/python3.7/site-packages/starlette/middleware/cors.py”, line 84, in call
await self.simple_response(scope, receive, send, request_headers=headers)
File “/usr/local/lib/python3.7/site-packages/starlette/middleware/cors.py”, line 140, in simple_response
await self.app(scope, receive, send)
File “/usr/local/lib/python3.7/site-packages/starlette/exceptions.py”, line 73, in call
raise exc from None
File “/usr/local/lib/python3.7/site-packages/starlette/exceptions.py”, line 62, in call
await self.app(scope, receive, sender)
File “/usr/local/lib/python3.7/site-packages/starlette/routing.py”, line 585, in call
await route(scope, receive, send)
File “/usr/local/lib/python3.7/site-packages/starlette/routing.py”, line 207, in call
await self.app(scope, receive, send)
File “/usr/local/lib/python3.7/site-packages/starlette/routing.py”, line 40, in app
response = await func(request)
File “app/server.py”, line 66, in analyze
for p in pred:
TypeError: ‘MultiCategory’ object is not iterable

Try converting it to a string? (I’d recommend testing this in a notebook first). Simply do learn.predict()

It wouldn’t let me loop (for p in pred) so I just used the same code which I used for Teddy bears. This worked just fine.

@app.route(’/analyze’, methods=[‘POST’])
async def analyze(request):
data = await request.form()
img_bytes = await (data[‘file’].read())
img = open_image(BytesIO(img_bytes))
return JSONResponse({‘result’: str(learn.predict(img)[0])})

1 Like