tensorflow tfserving + django,搭建图像分类预测web服务

tensorflow tfserving + django,搭建图像分类预测web服务

前面介绍了使用docker和tfserving搭建一个预测服务,但是有时候需要对输入到网络的数据做一些预处理的工作,虽然可以在本地使用如Python代码处理完成后再请求预测,但是使用起来会不方便。有时候也可能有将预测的过程作为一个web服务,实现在网页上填写图片的地址信息,然后返回预测结果的需求。本篇主要基于之前搭建的tfserving预测服务,使用django (一个开源的python web框架,详细信息见官网 django) 搭建一个web服务,作为一个中转服务器,接受用户的输入,完成一些预处理工作,然后向tfserving请求预测结果,最后返回结果。全部源代码放在 github。

另:使用docker+django+SSD搭建目标检测服务

先来看结果,下图为最终的页面:
tensorflow tfserving + django,搭建图像分类预测web服务_第1张图片
点击这里访问,可以先试一试效果。输入图片的URL,点击predict,等待返回结果。

下面介绍主要的流程:

0. tfserving准备

这里使用的是TensorFlow官方给的一个关于tfserving的教程所带的模型,具体的Docker安装和tfserving容器搭建流程可以参考使用docker和tfserving搭建预测服务。该步骤为基础步骤,如果要完整实现该demo,需要首先完成此步骤。

1.获取django镜像

$docker pull django

2.启动一个django容器

将容器的8000端口映射到宿主机的8080端口(后面请求的时候用的就是8080端口),并进入终端

$docker run -p 8080:8000 -it django bash

在这里插入图片描述

3.创建一个django工程

$django-admin startproject app

在/usr/src/路径下执行该命令,会在当前目录下创建一个app文件夹及相关文件,此时的目录结构为:
tensorflow tfserving + django,搭建图像分类预测web服务_第2张图片
其中:
manage.py是一个命令行工具,可以通过该工具与django工程进行交互;
__init__.py标识这是一个python package;
setting.py包含了当前工程的配置信息;
urls.py包含了当前工程的url声明;
wsgi.py是WSGI web服务入口点;

4.修改,增加相关代码

4.1 新建 search.py文件,这个文件主要用来请求的处理。获取到网页上填写的图片地址之后,进行图片下载,编码,向tfserving 服务发送请求,获得分类结果,再返回结果到页面。

from django.http import HttpResponse
from django.shortcuts import render_to_response
import base64
import requests
import imagenet_id_to_name

# send encoded image to tfserving
def request_classification(image_url):
    SERVER_URL = 'http://localhost:8501/v1/models/resnet:predict'
    IMAGE_URL = image_url
    # Download the image
    print("download image...")
    try:
        dl_request = requests.get(IMAGE_URL, stream=True)
        dl_request.raise_for_status()    

        # Compose a JSON Predict request (send JPEG image in base64).
        print("Compose a JSON Predict request")
        predict_request = '{"instances" : [{"b64": "%s"}]}' % base64.b64encode(dl_request.content).decode('ascii')

        # Send few requests to warm-up the model.
        #print("warm-up the model")
        #for _ in range(3):
            #response = requests.post(SERVER_URL, data=predict_request)
            #response.raise_for_status()

        # Send few actual requests and report average latency.
        print("send requests")
        total_time = 0
        num_requests = 1
        for _ in range(num_requests):
            response = requests.post(SERVER_URL, data=predict_request)
            response.raise_for_status()
            total_time += response.elapsed.total_seconds()
            prediction = response.json()['predictions'][0]

        print('Prediction class: {},class name: {}, avg latency: {} ms'.format( prediction['classes'],imagenet_id_to_name.imagenet_name_dict[prediction['classes']], (total_time*1000)/num_requests))
    
        return imagenet_id_to_name.imagenet_name_dict[prediction['classes']] 
    except:
        return 'something wrong happend'

# start page
def search_form(request):
    return render_to_response('search_form.html')

# result page
def search(request):
    request.encoding = 'utf-8'
    print(request.GET)
    if len(request.GET)>0:
        message = request.GET['info']+'\n\n'+ request_classification(request.GET['info'])
        #return HttpResponse(message)
        image_url = request.GET['info']
        predict_name = request_classification(request.GET['info'])
        return render_to_response('search_result.html',{'image_url':image_url,'predict_name':predict_name})
    else:
        return render_to_response('search_result.html',{'image_url':'incorrect','predict_name':'Please input right image URL'})

这里定义了三个函数:
search_form 是渲染初始的页面,具体的html代码在search_form.html文件中;
search是结果的展示页面,显示图片和识别结果;
request_classification用于根据用户填写的URL下载对应的图片,进行编码后,向tfserving 发送请求,得到预测结果后,将类别id转换为name,返回。这里有一点需要注意一下,由于base64在python2.x和Python3.x中的编码方式有差异,而我们使用的tfserving镜像用的是是Python2.x版本,所以如果我们使用的是Python3.x发送编码的图片,那么在编码的时候需要处理一下,增加一个decode的操作,即base64.b64encode(dl_request.content).decode(‘ascii’),否则会因为编码不一致导致出错。

4.2manage.py同级目录下新建一个名为templates文件夹,用于存放html文件。新建两个html文件,分别为search_form.html和search_result.html文件。
内容分别为:
(1) search_form.html



    
    image recognition


    
        

This is a demo of image recognition task using Django and tfserving.

Type your image URL in the input box below,and cilck the predict button,it will gives a prediction result.

(2) search_result.html



    
    image recognition


    
        

This is a demo of image recognition task using Django and tfserving.

Type your image URL in the input box below,and cilck the predict button,it will gives a prediction result.

The image of your input image URL is:
img


predict result: {{ predict_name }}

4.3 修改urls.py文件

from django.conf.urls import url
from django.contrib import admin
from . import search
urlpatterns = [
    url(r'^search-form$', search.search_form),
    url(r'^search$', search.search),
]

4.4 修改setting.py文件
修改其中的TEMPALTES中的DIR为:'DIRS': [BASE_DIR+"/templates"],也就是刚刚的.html文件所在目录;
tensorflow tfserving + django,搭建图像分类预测web服务_第3张图片
4.5 新建一个imagenet_id_to_name.py文件
这个文件是一个从类别id到类别名称的映射,是将模型预测的id转换为可读的类别名称,文件内容较长,具体内容可以见imagenet_id_to_name.py

完成上述步骤后,最终得到的文件目录结构为:
tensorflow tfserving + django,搭建图像分类预测web服务_第4张图片
这里面几个文件的关系简要描述如下:
1. 从urls.py开始,这里定义了一个urlpatterns的列表,定义了请求过来执行什么样的对应动作(函数);
如 url(r’^search$’, search.search),请求的URL是search,会执行search.py中的search函数

2. search.py是一个Python代码文件,里面定义了一些函数操作:
如:
def search_form(request):
return render_to_response(‘search_form.html’)
根据urls.py里面定义的接受到的请求,执行对应的函数里面的内容

3. 执行的可以是return一个HttpResponse(message),或者是渲染一个页面,比如render_to_response,参数是一个.html文件及相关参数,不同的操作可以渲染不同的页面。

整个过程中可能还会遇到一些比如requests模块没有安装的情况,手动安装即可。

最后运行server:

$ python manage.py runserver 0:8000

正常情况下应有如下结果:
tensorflow tfserving + django,搭建图像分类预测web服务_第5张图片
然后在浏览器中访问:http://localhost:8080/search-form
Done!

你可能感兴趣的:(TensorFlow)