Django网页服务解决TensorFlow模型重复加载问题,并完成启动时完成预热加载

前言

这个一个项目上遇到的问题,我有一个很大的人脸识别模型,每一次Http request请求,这个模型就会像以前一样在一次会话中执行一次模型加载。在以前的应用场景下,要么是模型较小,根本感受不到加载;要么就是根本就没有考虑过速度。但这次需要提供一个网页的服务,很明显得发现,响应速度很慢,经过分析发现,80%的时间都消耗在模型加载上了。

因此提出两个疑问:

  1. 能不能不要重复加载模型呢?
  2. 模型加载很耗时,能不能再开启服务的时候就完成加载呢?

思路

经过讨论后发现,这两个疑问有合理的解决方案,当然我这个方法不一定是最为合理和有效的,欢迎大家批评指正。
流程如下:

Queue线程等待避免重复加载

这篇Python线程教程给了我一定的思路,我可以使用queue库中的队列完成。原文说到:

从一个线程向另一个线程发送数据最安全的方式可能就是使用 queue 库中的队列了。创建一个被多个线程共享的 Queue 对象,这些线程通过使用put() 和 get() 操作来向队列中添加或者删除元素。

所以改写之前模型加载,整理思路就是:使用线程的方式,在图片服务初始化后就完成加载,然后对queue进行监听,一旦queue队列传入了数据,while True循环的阻塞就解除,继续执行下面的代码。完成解析之后,将结果放入结果队列进行值返回(因为不能直接return),如此循环等待。

class detectFace_service(Thread):
    def __init__(self, img_queue, result_queue):
        super().__init__()
        self.img_queue = img_queue
        self.result_queue = result_queue
        self.sess = tf.Session()
        self.graph = tf.get_default_graph()
        # self.graph.as_default()
        facenet.load_model_sess(model, self.sess)

    def run(self):
        while True:
            # 从共享队列中获取传入的信息
            img_url = self.img_queue.get()
            print("传来了一张照片" + img_url)
            # 传入结果队列中
            result = detectFace2(self.sess, self.graph, img_url)
            self.result_queue.put(result)

因为涉及到tf的特性,session和graph需要传入,当然这也要看你的函数是怎么写的了。

然后启动线程函数就可以像下面这样写了,传入全局的队列变量

def start_img_service():
    img_thread = detectFace_service(img_queue=IMG_QUEUE, result_queue=RESULT_QUEUE)
    print("图片服务线程启动")
    img_thread.start()

接下来,就按照Django项目正常提供网页服务,这部分就不介绍了,只写一下启动对应的函数,只需要将图片路径丢到全局队列就行了。

def gerUserImgName2(img_path):
    print("触发了人脸函数")
    IMG_QUEUE.put(img_path)
    print("开始等待处理")
    result = RESULT_QUEUE.get()
    print("结果是:", result)
    return result

项目启动时开启线程

讨论1讨论2
上面两个链接的讨论也挺不错的,给了不少思路。

我们避免了模型的重复加载之后,就需要将这个服务在项目启动时开启,这样模型就能提前加载好,完成加速。

这里我放入urls.py中,而不是model.py中,这是Django的机制,我还不是很懂,等有空研究了来这边补充,留个TODO,也欢迎大家提出。放入urls.py可以直接启动时加载,model.py发现会重复加载两次,显然消耗了内存。

直接将上面start_img_service写在urls.py中,然后运行。

def start_img_service():
    img_thread = detectFace_service(img_queue=IMG_QUEUE, result_queue=RESULT_QUEUE)
    print("图片服务线程启动")
    img_thread.start()

start_img_service()

系统就会在启动时自动运行

模型预热

这篇文章得到的启示。

在处理图片的时候还发现一个问题,在上传第一张图片进行处理的时候,大概是因为函数还没加载到内存里面,第一张处理得速度很慢,但是第二张的速度有显著提升,大概从10s提升到2s左右。

因此,开机启动时直接处理一张图片,完成模型的预热。

def start_img_service():
    img_thread = detectFace_service(img_queue=IMG_QUEUE, result_queue=RESULT_QUEUE)
    print("图片服务线程启动")
    img_thread.start()

start_img_service()
IMG_QUEUE.put(os.path.join(settings.MEDIA_ROOT,"WechatIMG760.jpg"))
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值