README.md 3.52 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# Adding Abseil (absl) flags quickstart
## Defining a flag
absl flag definitions are similar to argparse, although they are defined on a global namespace.

For instance defining a string flag looks like:
```$xslt
from absl import flags
flags.DEFINE_string(
    name="my_flag",
    default="a_sensible_default",
    help="Here is what this flag does."
)
```

All three arguments are required, but default may be `None`. A common optional argument is
short_name for defining abreviations. Certain `DEFINE_*` methods will have other required arguments.
For instance `DEFINE_enum` requires the `enum_values` argument to be specified.

## Key Flags
absl has the concept of a key flag. Any flag defined in `__main__` is considered a key flag by
default. Key flags are displayed in `--help`, others only appear in `--helpfull`. In order to
handle key flags that are defined outside the module in question, absl provides the
`flags.adopt_module_key_flags()` method. This adds the key flags of a different module to one's own
key flags. For example:
```$xslt
File: flag_source.py
---------------------------------------

from absl import flags
flags.DEFINE_string(name="my_flag", default="abc", help="a flag.")
```

```$xslt
File: my_module.py
---------------------------------------

from absl import app as absl_app
from absl import flags

import flag_source

flags.adopt_module_key_flags(flag_source)

def main(_):
  pass

absl_app.run(main, [__file__, "-h"]
```

when `my_module.py` is run it will show the help text for `my_flag`. Because not all flags defined
in a file are equally important, `official/utils/flags/core.py` (generally imported as flags_core)
provides an abstraction for handling key flag declaration in an easy way through the
`register_key_flags_in_core()` function, which allows a module to make a single
`adopt_key_flags(flags_core)` call when using the util flag declaration functions.

## Validators
Often the constraints on a flag are complicated. absl provides the validator decorator to allow
one to mark a function as a flag validation function. Suppose we want users to provide a flag
which is a palindrome.

```$xslt
from absl import flags

flags.DEFINE_string(name="pal_flag", short_name="pf", default="", help="Give me a palindrome")

@flags.validator("pal_flag")
def _check_pal(provided_pal_flag):
  return provided_pal_flag == provided_pal_flag[::-1]

```

Validators take the form that returning True (truthy) passes, and all others 
(False, None, exception) fail.

## Common Flags
Common flags (i.e. batch_size, model_dir, etc.) are provided by various flag definition functions,
and channeled through `official.utils.flags.core`. For instance to define common supervised
learning parameters one could use the following code:

```$xslt
from absl import app as absl_app
from absl import flags

from official.utils.flags import core as flags_core


def define_flags():
  flags_core.define_base()
  flags.adopt_key_flags(flags_core)
  
  
def main(flags_obj):
  pass
  
  
if __name__ == "__main__"
  absl_app.run(main)
```

## Testing
To test using absl, simply declare flags in the setupClass method of TensorFlow's TestCase.

```$xslt
from absl import flags
import tensorflow as tf

def define_flags():
  flags.DEFINE_string(name="test_flag", default="abc", help="an example flag")


class BaseTester(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    super(BaseTester, cls).setUpClass()
    define_flags()
    
  def test_trivial(self):
    flags_core.parse_flags([__file__, "test_flag", "def"])
    self.AssertEqual(flags.FLAGS.test_flag, "def")
    
```