Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to clean flags ? #36

Closed
DEKHTIARJonathan opened this issue Feb 1, 2018 · 8 comments
Closed

How to clean flags ? #36

DEKHTIARJonathan opened this issue Feb 1, 2018 · 8 comments

Comments

@DEKHTIARJonathan
Copy link

DEKHTIARJonathan commented Feb 1, 2018

Hello dear friends,

A few weeks ago, Tensorflow have moved to this library to manage flags using tf.app.flags.
Link to file: https://github.com/tensorflow/tensorflow/blob/r1.5/tensorflow/python/platform/flags.py

I can't manage to find any way to "reset" the flags state with this library. Is there any way to do this ?

I would like to remove every flags created and return to a blank state as if it was just created.

Thanks a lot.

@yilei
Copy link
Contributor

yilei commented Feb 1, 2018

If "blank state" means "reset all flag values to the default values", you can call absl.flags.FLAGS.unparse_flags(). This returns FLAGS to the state before flags are parsed from command line.

If "blank state" means "remove all flags as if no flags are defined", you can do something like:

from absl import flags

for name in list(flags.FLAGS):
  delattr(flags.FLAGS, name)

But this means if you call other libraries that uses the flags they have defined previously, they won't work anymore (unless you define the same flags again). So I'm curious, what is your use case? I assume you already have some code that does this before Tensorflow switch to this library, do you have an example?

And if you just want a separate FLAGS instance, you can create a new one:

from absl import flags

MY_FLAGS = flags.FlagValues()  # This is a separate "blank" instance different from the "global" flags.FLAGS instance.

@DEKHTIARJonathan
Copy link
Author

DEKHTIARJonathan commented Feb 2, 2018

@yilei thanks for your answer.

Your snippet did perfectly the job.

from absl import flags

for name in list(flags.FLAGS):
  delattr(flags.FLAGS, name)

For your question about the use-case, resetting the flags is actually the only way I found to achieve my objective.

Let's take a simple example, I want to create a GAN network composed of it's Generator and Discriminator or a VAE with its decoder and encoder. I want to create unittests for each part of the network namely the Encoder, Decoder and full VAE network or the Generator, Discriminator and full GAN network.

The problem is that the tests for each sub-part is written in different files and when I create master_test file calling all of the others I have flag collisions. Each test file creates its own set of flags with different conditions and then I initialize everything from this. It works perfectly when I call each test file separately, however, when I want to call all of them from the same master file and execute them in a row. I need to reset my flags each time I switch to a test in a different test file.

I would be very curious how you do this at google, I'm convinced there's a far better way doing this.
As soon as I can open-source my repository I will let you know.

@gpshead
Copy link
Contributor

gpshead commented Feb 2, 2018

I would ordinarily point out absl.testing.flagsaver for use when testing things each with different sets of flag values.

That you seem to be wanting to redefine conflicting sets of flags from your test files themselves makes me think that you are not doing your flag definitions in the "right" place. A test file should not be defining flags. Flag definitions should happen in top level of each library that is going to use them (or for widely shared flags, in a shared library that everything expected to use such a flag depends on).

When you've done it that way, they are defined in only one place, and you can use flagsaver to restore values to defaults after each test so that you can setup whatever set of values you need them to have in the next test by simply assigning values to to them. It is highly unusual to want to undefine flags within a process.

Hopefully I'm making sense here.

@yilei
Copy link
Contributor

yilei commented Feb 2, 2018

Usually each of our test files is run as separate binaries, so different flags from different test files don't interact. (This is done via bazel.)

In your case, each test file is imported master_test, so you can think of each test is a library, and only the master_test is a binary. It isn't a good case to define conflict flags in libraries shared in a single binary.

Do you need to specify the flags defined in individual test files on the command line?

  • If not, they sound more like global variables, not flags to me.
  • If yes, then I assume they are shared across the tests and only parsed inside the master_test. So I suggest to define the flag in master_test only, and pass the flag values to each individual tests. Or, as @gpshead pointed out, you can use absl.testing.flagsaver in your tests, but you still define the same flag in one place. Example:
# File: shared_flags.py
flags.DEFINE_string('encoder', None, 'The encoder to use')
# File: test_a.py
def test_a():
  encoder = create(FLAGS.encoder)
  ...
# File: test_b.py
def test_b():
  encoder = create(FLAGS.encoder)
  ...
# File: master_test.py
from absl import app
from absl import flags
from absl.testing import flagsaver
import shared_flags  # Import to define --encoder.
import test_a
import test_b

FLAGS = flags.FLAGS

def main(argv):
  test_cases = [('encoder a', test_a.test_a), ('encoder b', test_b.test_b)]
  for encoder, test_func in test_funcs:
    with flagsaver.flagsaver():
      FLAGS.encoder = encoder
      test_func()

if __name__ == '__main__':
  app.run(main)

@AI-ML-Enthusiast
Copy link

@yilei

Thanks for your writing.
I want to delete or reset or clean flags. I used your code:
from absl import flags

for name in list(flags.FLAGS):
  delattr(flags.FLAGS, name)

but it gives the following error:

from absl import flags

AttributeError: pdb_post_mortem

How can I solve it? otherwise, when I run again my code it give the error:
DuplicateFlagError: The flag 'input_model' is defined twice.

Is there any suggestion please? thanks

@yilei
Copy link
Contributor

yilei commented Dec 18, 2019

That snippets will delete all defined flags, so that FLAGS.pdb_post_mortem will no longer be defined and that's expected. And probably you don't want to do this.

What do you really want by saying "delete or reset or clean flags"? Do you mean to reset all flag values, but keep the definitions? Or do you really want to delete them, since

this means if you call other libraries that uses the flags they have defined previously, they won't work anymore

When you say "I run again my code", how did you run again your code? Is this a function call? module reload? a new process?

Sorry without more context/details it's really hard to know what's going on.

@AI-ML-Enthusiast
Copy link

@yilei
Thank you very much.
Sorry I am new at this topic. Let us clear my question:
I ran the following code:

from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
  print('Happy Birthday', FLAGS.name)

if __name__ == '__main__':
  app.run(main)

It gives the following output with exception:

Happy Birthday Jane Random
An exception has occurred, use %tb to see the full traceback.
SystemExit

\site-packages\IPython\core\interactiveshell.py:3304: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)

When I ran in second time, it gives the following error:

DuplicateFlagError: The flag 'name' is defined twice.

How can I solve it? I would like to run the program several times as I wish?

Thanks

@yilei
Copy link
Contributor

yilei commented Dec 19, 2019

Looks like you are using IPython, I'm not very familiar with IPython but app.run here is supposed to be run as a standalone application started by the python interpreter, not imported by another python module (some IPython internals, the interactiveshell.py module?). The exception is probably because app.run calls sys.exit at the end here:

sys.exit(main(argv))
and IPython is not happy.

And DuplicateFlagError is because IPython probably just reloads the module so flags.DEFINE_string is called the second time but FLAGS is global and persists during the entire life cycle.

So the conclusion is probably that this won't work with your IPython workflow. If you have the code:

from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
  print('Happy Birthday', FLAGS.name)

if __name__ == '__main__':
  app.run(main)

In a file called main.py, then running something like:

python main.py

will work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants