[原创] 加快TensorFlow在树莓派上的执行速度——服务常驻内存

本文软硬件环境:
树莓派:3代 Model B V1.2,内存1GB
OS:Arch Linux ARM

上一篇文章中,我尝试了加快TensorFlow预测速度的一个方法——模型“预热”,实验证明它非常有效,但那仍然没有解决一个问题:每次运行程序,都要加载一次模型,然后预热N次,这个过程非常耗时,因此减少这部分时间也是非常关键的。把TensorFlow做成一个常驻内存的服务就可以解决这个问题。
解决这个问题的正确姿势是:TensorFlow已经提供了一个叫作 TensorFlow Serving 的library来实现这个需求。但麻烦的是,在树莓派上编译TensorFlow Serving会遇到很多问题,所以,在没有人搞出在树莓派上一键安装的Python wheel包之前,还是算了吧...
因此,下面我用一个很挫的办法来实现一个简陋的TensorFlow service。

『1』简单的思路
服务端,用Python实现一个web server,处理HTTP Get请求,通过解析URL中的参数(例如 http://127.0.0.1:8080/?image_path=/root/abc.jpg 中的 /root/abc.jpg),来获取待处理的图片的路径,处理完之后,把处理结果返回给客户端。
客户端,通过 curl 命令就可以调用服务了,例如:

curl http://127.0.0.1:8080/?image_path=/root/abc.jpg

这表示让服务端处理 /root/abc.jpg 这个文件。
当然,为了简单,这里的设定有一个局限:server和client都在同一个树莓派上,如果要跨机器,那么需要client把图片post到server端,server取出来之后再处理,但本文不涉及这种情况。
文章来源:http://www.codelast.com/
『2』简单Python web server的实现
不考虑什么并发,多线程之类的情况,我们可以用非常简单的一点代码就实现一个Python web server。

#!/usr/bin/python3.5


from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qsl

class MyRequestHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    # e.g. "/?image_path=/root/mobike.jpg"                                                                                                                   
    path = self.path
    # e.g. "/root/mobike.jpg"                                                                                                                                
    image_path = parse_qsl(path[2:])[0][1] + '\n'

    # send response status code                                                                                                                              
    self.send_response(200)

    # send headers                                                                                                                                           
    self.send_header('Content-type','text/html')
    self.end_headers()

    # send message back to client, write content as utf-8 data                                                                                               
    self.wfile.write(bytes(image_path, "utf8"))
    return

def start_web_server():
  print('Starting web server...')

  server_address = ('127.0.0.1'8080)
  httpd = HTTPServer(server_address, MyRequestHandler)
  httpd.serve_forever()


start_web_server()

其中,在 MyRequestHandler 这个类中,我们会处理每一个客户端的请求,这里只是把从URL中解析到的图片文件路径简单地发送回客户端。
此代码可在我的GitHub中下载。
文章来源:http://www.codelast.com/
『3』TensorFlow服务测试
按“模型加载1次,预热10次”的原则,再结合上面的简单web server代码,我们可以很容易地把TensorFlow做成服务。具体代码比较长,这里就不粘贴上来了,在我的GitHub可以下载到。

下面测试一下效果。
把service启动起来:

./run-tensorflow-service.sh

经历几十秒的漫长等待之后,模型加载&预热就完成了(命令行输出会有提示),此时,我们再在同一台树莓派上运行client,向server发送一个处理图片的请求:

./client.sh /root/raspberry-pi/ai/tensorflow-related/resource/test-images/mobike.jpg

大概4秒多之后,client端会打印出如下信息:

mountain bike, all-terrain bike, off-roader (score = 0.56671)
tricycle, trike, velocipede (score = 0.12035)
bicycle-built-for-two, tandem bicycle, tandem (score = 0.08768)
lawn mower, mower (score = 0.00651)
alp (score = 0.00387)
Prediction used time:4.171393394470215 Seconds
换一张大小相仿的图片来测试,消耗的时间也是差不多的,达到了我们预期的效果。至此,它距离“实用”又更近了一步。

文章来源:https://www.codelast.com/
➤➤ 版权声明 ➤➤ 
转载需注明出处:codelast.com 
感谢关注我的微信公众号(微信扫一扫):

wechat qrcode of codelast

发表评论