欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

解决tensorflow+gunicorn+flask的flag异常 UnrecognizedFlagError: Unknown command line flag

程序员文章站 2022-07-14 17:09:18
...

背景:TextCnn模型用tensorflow+flask+gunicorn搭建模型预测并发API生产环境,模型调用抛异常。

报错代码

#模型代码处:

# Misc Parameters
tf.flags.DEFINE_boolean("allow_soft_placement", True, "Allow device soft device placement")
tf.flags.DEFINE_boolean("log_device_placement", False, "Log placement of ops on devices")

FLAGS = tf.flags.FLAGS
FLAGS.flag_values_dict()

FLAGS.set_default("checkpoint_dir",checkpoint_dir)

# Map data into vocabulary
vocab_path = os.path.join(FLAGS.checkpoint_dir, "..", "vocab")
self.vocab_processor = learn.preprocessing.VocabularyProcessor.restore(vocab_path)
#tensorflow的flags.py代码处:
class _FlagValuesWrapper(object):
  """Wrapper class for absl.flags.FLAGS.

  The difference is that tf.flags.FLAGS implicitly parses flags with sys.argv
  when accessing the FLAGS values before it's explicitly parsed,
  while absl.flags.FLAGS raises an exception.
  """

  def __init__(self, flags_object):
    self.__dict__['__wrapped'] = flags_object

  def __getattribute__(self, name):
    if name == '__dict__':
      return super(_FlagValuesWrapper, self).__getattribute__(name)
    return self.__dict__['__wrapped'].__getattribute__(name)

  def __getattr__(self, name):
    wrapped = self.__dict__['__wrapped']
    # To maintain backwards compatibility, implicitly parse flags when reading
    # a flag.
    if not wrapped.is_parsed():
      wrapped(_sys.argv)
    return wrapped.__getattr__(name)

报错信息

  File "/usr/local/lib/python3.6/site-packages/tensorflow/python/platform/flags.py", line 86, in __getattr__
    wrapped(_sys.argv)
  File "/usr/local/lib/python3.6/site-packages/absl/flags/_flagvalues.py", line 633, in __call__
    name, value, suggestions=suggestions)
absl.flags._exceptions.UnrecognizedFlagError: Unknown command line flag 'c'

问题原因:

gunicorn的如下两种命令行启动方式都会通过命令行带配置参数(gunicorn自己用的),被flask文件带到了模型调用处,tensorflow解析sys.argv的时候不认识了,对于这种情况tensorflow代码里是有注释说明的。

#gunicorn -c gun.py evalute:app

#gunicorn -w 4 -b 127.0.0.1:5000 evalute:app

#tensorflow的代码注释说明:

"""Wrapper class for absl.flags.FLAGS.

The difference is that tf.flags.FLAGS implicitly parses flags with sys.argv
when accessing the FLAGS values before it's explicitly parsed,
while absl.flags.FLAGS raises an exception.
"""

解决办法

1. 修改tensorflow的flags.py代码

参考 https://blog.csdn.net/qq_35240640/article/details/103632902 加两行代码,不让tensorflow解读sys.argv。

百度的时候也有推荐修改tensorflow版本的,太麻烦,没试。

def __getattr__(self, name):
  wrapped = self.__dict__['__wrapped']
  # To maintain backwards compatibility, implicitly parse flags when reading
  # a flag.
  if not wrapped.is_parsed():
    while len(sys.argv) > 1:
      sys.argv.pop()
    wrapped(_sys.argv)
  return wrapped.__getattr__(name)

2. 修改工程模型代码

提前定义,让tensorflow认识,虽然它也用不到。

#debug Parameters
tf.flags.DEFINE_integer("w", 3, "gunicorn workers' number")
tf.flags.DEFINE_string("b", "", "gunicorn workers' ip and port")
tf.flags.DEFINE_string("c", "", "gunicorn workers' config address")

FLAGS = tf.flags.FLAGS

显然第2中方式更合理。

详细追查过程:

其实在定位到上面的报错之前还有一步。

第一步:

flask的启用入口我涉及到两种,一种是开发环境main函数入口;一种是生产环境gunicorn入口。

我最初模型的实例化放到了main函数里,所以在通过gunicorn调用的时候就找不到模型了,通过给flask的app入口文件打log看报错信息,定位了问题。

解决办法就是把实例化代码放到flask app文件的公用代码处。

第二步:

在哪查看报错信息:

1. 在通过配置文件启动gunicorn的时候报错信息查看debug文件。

2. 在通过-w -b直接启动gunicorn的时候报错信息在控制台。

走的弯路:

在第二步排查的时候,我一度以为是因为gunicorn多进程实例化了多个模型而不该实例化多个模型所以报错了。

于是试图通过gunicorn提供的preload功能或flask的@app.before_request的注解功能提前实例化一个模型实例,最后通过报错信息才知道问题症结所在。