tornado多线程keras模型加载问题及解决方案

3 篇文章 0 订阅
2 篇文章 0 订阅

  最近,在尝试利用tornado、tensorflow以及keras完成一个短文本分类模型训练及预测的服务。具体的逻辑是这样的:利用tornado封装一个server,然后主要提供三个API,train、apply以及predict。其中train用来传入一些参数进行模型训练,apply用于配置一个分类模型用于短文本预测,predict用来进行短文本的类别预测。因此需要有一个线程监听当前的模型配置,然后实时加载,在predict时调用新模型。

  这里主要踩了两个坑:1. 原生keras多线程调用的问题;2. tensorflow封装的keras的问题。首先给出解决方案:

  • 请使用原生keras,而不是tensorflow封装的keras
  • 在模型加载时,请添加如下语句
keras.backend.clear_session()
self.model = keras.models.load_model(MODEL_PATH)
self.model._make_predict_function()

  环境说明

mac os 10.14.2
python 3.7
tornado 5.1.1
tensorflow 1.13.1
keras 2.2.4

  完整的多线程使用keras进行多线程模型调用的示例如下,其中build_model方法用于创建两个基础的keras模型,类Test用于进行多线程间模型加载及同步的测试,Test.reload_model用于动态加载模型,Test.predict将会调用最新模型并进行预测。在build_model中,我们将会创建一个模型,但保存为两个不同的模型文件。在reload_model方法中,i = numpy.random.choice([0, 1])随机选择0或1,用于选择加载的模型,并进行模型加载。在predict方法中,将会随机生成一个10维的向量x,然后调用当前的模型进行预测,并将模型名称及预测结果进行打印。

import time
import threading


import numpy
import keras


def build_model():
    inp = keras.layers.Input(shape=(10,))
    h = keras.layers.Dense(8, activation='relu')(inp)
    outp = keras.layers.Dense(1)(h)

    model = keras.models.Model(inputs=inp, outputs=outp)
    model.compile(optimizer='rmsprop',
                  loss='mse',
                  metrics=['accuracy'])
    model.save('./test_model0.h5')
    model.save('./test_model1.h5')


class Test(object):
    def __init__(self):
        self.model = None
        self.moel_name = 0
        t1 = threading.Thread(target=self.reload_model, name='load')
        t2 = threading.Thread(target=self.predict, name='predict')
        t1.start()
        time.sleep(2)
        t2.start()

    def reload_model(self):
        while True:
            i = numpy.random.choice([0, 1])
            keras.backend.clear_session()
            self.model = keras.models.load_model('./test_model%d.h5' % i)
            self.moel_name = i
            self.model._make_predict_function()
            print('reload successful')
            time.sleep(10)

    def predict(self):
        while True:
            x = numpy.random.normal(size=(1, 10))
            print("system", x)
            print(self.moel_name)
            try:
                print(self.moel_name, self.model.predict(x))
            except Exception as exc:
                print(exc)
            time.sleep(3)


if __name__ == "__main__":
    build_model()
    t = Test()

运行结果:在这里插入图片描述

踩坑之路

非原生keras踩坑

  在加载keras时,如果将import keras修改为import tensorflow.keras as keras,将会得到如下错误结果:Tensor(“Placeholder:0”, shape=(), dtype=float32) must be from the same graph as Tensor(“total:0”, shape=(), dtype=resource)

在加载模型时未执行前述两行代码

  如果在模型加载部分,将如下两行代码注释

# keras.backend.clear_session()
self.model = keras.models.load_model(MODEL_PATH)
# self.model._make_predict_function()

则将得到如下错误结果:
TypeError: Cannot interpret feed_dict key as Tensor: Tensor Tensor(“Placeholder:0”, shape=(10, 8), dtype=float32) is not an element of this graph.

原因分析

  受限于博主能力,尚未能明确具体原因,大致猜测模型加载不完整,期待其他同行可以一起探讨。

结论

  本文结合博主个人实践,给出了多线程使用keras的一种正确方法,并给出了两种错误示例及错误结果。

交流

欢迎添加公众号与我继续交流!
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值