解決tensorflow+gunicorn+flask的flag異常 UnrecognizedFlagError: Unknown command line flag

背景: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的註解功能提前實例化一個模型實例,最後通過報錯信息才知道問題癥結所在。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章