Keras+TF的Flask开发经验

Task

  • 理解 Keras+TF 项目部署
  • 使用Keras+TFFalsk中部署
  • Flask使用进阶
  • Flask托管和部署

Reference

Start

  • 一份程序为了区分主动执行还是被调用,Python引入了变量__name__,当文件是被调用时,__name__的值为模块名,当文件被执行时,__name____main__

  • 如果使用from A import B,其实等于import A,b=A.b·。其中A内非函数代码也会执行

  • 介绍globe。首先看一个变量作用域的错误示例

    1
    2
    3
    4
    5
    6
    n=0
    def func():
    print n
    n+=1

    func()

    报错:UnboundLocalError: local variable 'xxx' referenced before assignment,即函数内部不能修改局域变量,使用globe

    1
    2
    3
    4
    5
    6
    7
    8
    n=0
    def func():
    global n
    print n
    n+=1

    func()
    print n

    这时,n就成为了全局变量,在函数内部修改该变量,也就没有问题了。

  • 通常定义:Lib为依赖库;Bin类似通常定义默认程序集缓存,可理解为优先级高代码目录

  • Cython: 将Python代码( .py .pyx )翻译为C( .c )代码,去掉指令解释这个阶段,直接进入C代码层,效率就比较高了.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Cython一般出现于“python setup.py build_ext --inplace”
    其中“setup.py”内大致出现如下:
    ===========================
    from distutils.core import setup
    from Cython.Build import cythonize

    setup(ext_modules = cythonize("test.py"))
    ========================================
    #test.c是test.py转化后的C代码文件,test.c非常大
    #test.pyd是python的动态链接库,我们在使用import test时会加载, 若是Liuix则是(.so)文件而不是(.pyd)
    #build目录编译过程中生成的临时文件
  • Makefile:通常情况下,它们用于编写C程序,来减轻代码可以作为程序使用前所需要做的所有东西。在Python项目中使用makefile,其实说白了就是一个shell脚本。放在makefile中的一个规则下,使其他人很容易地运行对项目的测试。示例见

  • 模块module,库lib,包package

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    module:一个 .py 文件就是个 modulelib:抽象概念,和另外两个不是一类,只要你喜欢,什么都是
    以下放上详细的:
    ============================================================
    模块(module):Python中可复用的基本代码单元,可由其他代码import的一块代码,这里我们只关
    注三种类型的模块:纯python模块,扩展模块和包。
    纯python模块(pure Python module): 由python编写的模块,包含在单独的py文件中(或者是pyc/pyo文件)。
    扩展模块(extension module):由实现Python的底层语言编写的模块(C/C++ for Python, Java for Jython)。通常包含在单独的动态加载文件中,比如Unix中的so文件,windows中的DLL文件,或者是Jython扩展的java类文件。(注意,目前为止Distutils只能处理Python的C/C++扩展)
    =============================================================

    lib,就算只有个 hello world,通常称依赖库

    package:就是个带 __init__.py 的文件夹,并不在乎里面有什么,不过一般来讲会包含一些 packages/modules

    scrapy、flask、Django、numpy、scipy、NLTK、jieba 在你的语境下,一般都被认为是 lib,因为关注点不是他们的代码是怎么组织的。
    简单讲,Package是由很多module组成,来实现某种功能,modules由函数和类组成。库是抽象概念,也可以是各种模块组成。
  • setup.py本地安装包。不安装可以直接运行包源码吗?答案是可以,不过得首先编译Cython代码,即执行python setup.py build_ext --inplace。详细setup.py解析见

    举两个具体例子,串起之前知识点,并说明setup.py的工作:

    ①Keras+TF

    在某个Keras+TF项目里,模型的TF部分的实现部分通过调用其内Lib实现,目录如下:

    Lib

    但直接form lib import xxx可能会报错,那为什么要执行make.sh呢?

    查看mask.sh源码:

    make

  • 编译pyx文件——Lib库内模型需要;提速;

    若不执行则报错:ImportError: cannot import name 'bbox',对应GithubIssue

    issue

    (哈哈哈哈哈哈哈哈哈。。。不过这里还真有老哥搞定了)

  • 执行python setup.py build_ext --inplace

  • 移动文件

  • 删除文件

    好了,进入setup.py:

  • 配置CUDA

    setup_cuda

  • Distutils发布Python模块——扩展模块

    setup_ext

    Extension是纯Python的扩展模块,构造Extension指定扩展名、源码文件以及其他编译/链接需要的参数(需要包含的目录,需要连接的库等等)。其中第二个参数为指定的源码文件。

    nms(非极大值抑制)和bbox(Bounding box)都是物体侦测相关的,属于faster-rcnn,具体可见

  • 执行setup

    ext_modules

    ext_modulesExtension实例的列表,每一个Extension实例描述了一个独立的扩展模块。这里可理解为部署faster-rcnn。到此,整个mask.sh执行完毕,用户可方便使用项目代码。

    ②Keras

    在某个Keras项目里,作者代码没传Pypi,而是提供了包的形式供安装。安装即

  • cd进目录

  • pip install .或者python setup.py

    查看setup.py:

    setup_retina

    比较规范的写法~规范可见

    其中

  • cmdclass: 添加自定义命令,我的理解就是解析命令行的初始化媒介。这里传入是构造类;找的一个扩展

    BuildExtension

  • entry_points: entry_points中: console_scripts* 指明了命令行工具的名称;在retinanet-train=keras_retinanet.bin.train:main中,等号前面指明了工具包的名称,等号后面的内容指明了程序的入口地址

With Flask

start部分学习了解了Keras+TF项目的安装部署,方便出错解决。接下来让我们来学习在Flask中如何部署Keras+TF

tensorflow程序一般分为两个阶段:

1
2
3
1、定义计算图所有的计算

2、在session中执行计算

tensorflow程序中,系统会自动维护一个默认的计算图,可以通过tf.get_default_graph()函数获取。

然后我们进入Flask中去。

####

因为重复生成session浪费时间和资源。如何使Keras+TF的计算图在Flask中不变呢?那就是不写进函数,提前实例化出来~每次再把session和模型喂入识别函数~

注:代码中是TF模型结果传给Keras。我的理解是Keras一个计算图,TF一个计算图。

Tensorflow中:

sess_tf

Keras中:

sess_keras

####

可以这么理解:张量Tensor的计算图要和session中的计算图相同。当前session里的图和模型中的图的各种参数不匹配就报错,所以得定义了一个全局的图,每次都用这个图

Flask自身存在Bug,不详细展开,这里写一下解决方案

  • 保证TF模型单线程

在调用keras的tensorflow的应用程序中,保证tensorflow的模型是单线程加载的。如果多线程加载模型的话,可能需要人为指定不同的Graph,具体还没有研究。

保证方法:①实例化加载;②Flaskapp.run()内设置debugFalse,因为debug开启了Tensorflow线程,使Tensorflow线程从单变多

  • session中还有其他模型数据

    这个错也可以说叫,当前session里的图和模型中的图的各种参数不匹配,这是Keras的自身Bug

    • 首先,在Keras预测模块,可以这么写:

      predict

      即,使用globe导入实例化后的Keras模型,然后函数内with _GRAPH_MA.as_default():内进行预测,其中_GRAPH是函数外实例化的Graph

    • 然后,在app.py主函数__main__内,在app.run()之前,预先跑一遍模型,导通SessionGraph

    • 题外话

      Keras训练时:

      train_sess

      然后K.set_session(get_session()) 即可。

      Tensorflow训练时:

      train_tf

      然后 加载预训练

      1
      2
      3
      4
      5
      6
      7
      8
      9
      saver = tf.train.Saver()

      try:
      ckpt = tf.train.get_checkpoint_state(cfg.TEST.checkpoints_path)
      print('Restoring from {}...'.format(ckpt.model_checkpoint_path), end=' ')
      saver.restore(sess, ckpt.model_checkpoint_path)
      print('done')
      except:
      raise 'Check your pretrained {:s}'.format(ckpt.model_checkpoint_path)
**训练**时`sess.run(...)`即可。

TODO

————Edit By Kevin