当我们为一个Python应用程序编写命令行参数时,我们经常会使用argparse库。可是,如何处理那些在我们应用程序中有多个层次结构,或者有多个组件需要一些参数的情况呢?TensorFlow的tf.app.flags
就是来处理这样的问题的,它提供了一种基于命令行参数的配置框架,可以方便、灵活地管理多个参数。
一、界面介绍
tf.app.flags
模块有5个部分:部分1是定义所有的flag参数;部分2定义了各个参数的默认值;部分3是从命令行读入参数和使用默认值来初始化FLAGS;部分4用于处理多余的不属于FLAGS的命令行参数;部分5用于打印使用方法和flag当前值。
下面让我们来看看这些部分的详细介绍:
1. 定义flag参数
flags.DEFINE_XXXX()
函数是创建flag参数的主要方法,其中XXXX是flag的数据类型。可以通过这些方法定义整数、字符串、布尔等类型的参数。例如,以下是定义一些字符串和布尔类型flag的示例:
import tensorflow as tf
flags = tf.app.flags
flags.DEFINE_string('input', './data/input.txt', 'input data path')
flags.DEFINE_string('output', './data/output.txt', 'output data path')
flags.DEFINE_bool('verbose', False, 'display log messages')
以上代码定义了三个flag:input
、output
和verbose
。输入文件路径默认值为"./data/input.txt"
,输出文件路径的默认值为"./data/output.txt"
,verbose
参数默认为False
。
2. 定义默认flag参数
在tf.app.flags
中,所有flag都具有默认值。你可以通过调用flags.FLAGS.xxx
来获取FLAG参数xxx
的默认值,但是在没有完全初始化FLAGS之前,这是无法完成的。为了确保我们始终可以访问FLAGS中的所有flag的值,我们需要为所有flag制定默认值。以下是设置默认值的示例:
import tensorflow as tf
flags = tf.app.flags
flags.DEFINE_string('input', './data/input.txt', 'input data path')
flags.DEFINE_string('output', './data/output.txt', 'output data path')
flags.DEFINE_bool('verbose', False, 'display log messages')
flags.DEFINE_integer('max_steps', 10000, 'maximum number of steps for training') # 追加一行代码
flags.DEFINE_float('learning_rate', 0.1, 'initial learning rate for training') # 追加一行代码
以上代码增加了两个默认的参数:max_steps
和learning_rate
。
3. 从命令行读入参数和使用默认值来初始化FLAGS
在程序的运行期间,我们可以从命令行读取参数。例如,以下命令行指定了3个参数的值:
python my_program.py --input='./new_input.txt' --output='./new_output.txt' --verbose=True
使用以下代码将flags(即FLAGS)初始化,这里假设用户没有提供这些flag,这意味着它们将使用默认值。
import tensorflow as tf
flags = tf.app.flags
flags.DEFINE_string('input', './data/input.txt', 'input data path')
flags.DEFINE_string('output', './data/output.txt', 'output data path')
flags.DEFINE_bool('verbose', False, 'display log messages')
flags.DEFINE_integer('max_steps', 10000, 'maximum number of steps for training')
flags.DEFINE_float('learning_rate', 0.1, 'initial learning rate for training')
FLAGS = flags.FLAGS
FLAGS.__dict__['__flags'].update(flags.FLAGS.__flags) # 将默认值添加到FLAGS.__dict__中
以上代码中使用flags.FLAGS
命令从命令行获取它们的参数值,如果用户没有特别指定参数,程序会将参数的值设置为默认值。FLAGS.__dict__['__flags'].update(flags.FLAGS.__flags)
的作用是将默认值添加到FLAGS.__dict__
中,这意味着我们可以通过FLAGS.xxx
访问flag。
4. 处理多余的不属于FLAGS的命令行参数
如果用户提供了多余的参数(不属于FLAGS),则需要在应用程序代码中处理这些额外的命令行参数。可以使用以下代码示例将它们存储到额外的变量中:
import sys
import tensorflow as tf
flags = tf.app.flags
# 如前所述,指定参数以及参数默认值
FLAGS = flags.FLAGS
FLAGS.__dict__['__flags'].update(flags.FLAGS.__flags)
# 处理多余的非FLAG命令行参数
if len(sys.argv) > 1:
for i in range(1, len(sys.argv)):
if not sys.argv[i].startswith('--'):
sys.exit('Invalid argument: ' + sys.argv[i])
5. 打印使用方法和flag当前值
以下代码演示了如何打印使用方法和flag当前值:
import tensorflow as tf
flags = tf.app.flags
flags.DEFINE_string('input', './data/input.txt', 'input data path')
flags.DEFINE_string('output', './data/output.txt', 'output data path')
flags.DEFINE_bool('verbose', False, 'display log messages')
flags.DEFINE_integer('max_steps', 10000, 'maximum number of steps for training')
flags.DEFINE_float('learning_rate', 0.1, 'initial learning rate for training')
FLAGS = flags.FLAGS
FLAGS.__dict__['__flags'].update(flags.FLAGS.__flags)
# 打印使用方法和flag当前值
flags.mark_flag_as_required('input') # 声明必须项
print("input=" + FLAGS.input) # 输出:./data/input.txt
print("output=" + FLAGS.output) # 输出:./data/output.txt
print("verbose=" + str(FLAGS.verbose)) # 输出:False
print("max_steps=" + str(FLAGS.max_steps)) # 输出:10000
print("learning_rate=" + str(FLAGS.learning_rate)) # 输出:0.1
二、优缺点分析
1. 优点
tf.app.flags
模块提供了一种简单、快速的方式来管理应用程序的参数。其主要优点如下:
- 可维护性更好:团队使用这种配置框架后,可维护性将会更好。因为不存在与"魔术值"或"硬编码常数"相关的问题。所有参数值全部通过标志传递。
- 风格一致性:如果一个团队使用
tf.app.flags
模块来管理程序的参数,那么每个组件的所有参数都将遵循相同的命令行接口标准,也就是说,每个参数都将由--flag
、--flag=value
或--flag value
这几个标准的命令行参数值指定。 - 易于使用:作为Python库的一部分,它需要很少的代码来配置和使用标志参数。它对于Python开发人员来说,非常容易使用。
2. 缺点
然而,tf.app.flags
模块的缺点是,这种方法需要在每个组件的启动代码中维护标志。当应用程序由大量组件和参数时,必须维护大量重复的代码,导致代码冗长,并增加了出错的风险。
三、总结
在本篇文章中,我们介绍了tf.app.flags
模块,并看了看如何定义flag参数、如何设置默认flag参数、如何从命令行读入参数并初始化FLAGS、如何处理多余的不属于FLAGS的命令行参数,以及如何打印使用方法和flag当前值。还分析了tf.app.flags
模块的优缺点,这将有助于了解如何更好地使用tf.app.flags
模块。