Repository: huggingface/transformers

Issue:
HfArgumentParser not support optional bools
## Environment info
<!-- You can run the command `transformers-cli env` and copy-and-paste its output below.
     Don't forget to fill out the missing fields in that output! -->
     
- `transformers` version: 3.3.1
- Platform: Linux-3.10.0
- Python version: 3.7.3
- PyTorch version (GPU?): 1.6.0 (True)
- Tensorflow version (GPU?): not installed (NA)
- Using GPU in script?: Yes
- Using distributed or parallel set-up in script?: No

### Who can help
<!-- Your issue will be replied to more quickly if you can figure out the right person to tag with @
 If you know how to use git blame, that is the easiest way, otherwise, here is a rough guide of **who to tag**.
 Please tag fewer than 3 people. -->

@sgugger

## Information

Model I am using (Bert, XLNet ...):

The problem arises when using:
* [x] the official example scripts: (give details below)
* [ ] my own modified scripts: (give details below)

The tasks I am working on is:
* [x] an official GLUE/SQUaD task: (give the name)
* [ ] my own task or dataset: (give details below)

Part of the code are copied from [examples/text-classification/run_glue.py](https://github.com/huggingface/transformers/blob/v3.3.1/examples/text-classification/run_glue.py)
## To reproduce

Steps to reproduce the behavior:

1.
Save the following code as 'test.py' then `python test.py --output_dir 123`
```python
from transformers import TrainingArguments, HfArgumentParser

parser = HfArgumentParser(TrainingArguments)
training_args, = parser.parse_args_into_dataclasses()
# All of the following fields has a default value of `None`
print(training_args.greater_is_better) # type=Optional[bool]
print(training_args.disable_tqdm) # type=Optional[bool]
print(training_args.metric_for_best_model) # type=Optional[str]
print(training_args.save_total_limit) # type=Optional[int]
```
2.
Got following output:

False
False
None
None

Notice the first two fields' default values are changed. They should be remain `None` as long as I don't pass the args from the cli.

<!-- If you have code snippets, error messages, stack traces please provide them here as well.
     Important! Use code tags to correctly format your code. See https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting
     Do not use screenshots, as they are hard to read and (more importantly) don't allow others to copy-and-paste your code.-->

## Expected behavior
It should be the following output:

None
None
None
None

Because all of these four fields are **Optional** and their default values are `None` (See [training_args.py](https://github.com/huggingface/transformers/blob/v3.3.1/src/transformers/training_args.py)).

Also, in 
https://github.com/huggingface/transformers/blob/1ba08dc221ff101a751c16462c3a256d726e7c85/src/transformers/training_args.py#L324
https://github.com/huggingface/transformers/blob/1ba08dc221ff101a751c16462c3a256d726e7c85/src/transformers/training_args.py#L342

both `greater_is_better` and `disable_tqdm` are detected whether they are None, which means the author intends them to be None when they are unspecific in passing args.

This may caused by 
https://github.com/huggingface/transformers/blob/1ba08dc221ff101a751c16462c3a256d726e7c85/src/transformers/hf_argparser.py#L67-L68
Since they have a type of `Optional[bool]`，their `kwargs["action"]` is set to `store_true`. So when I don't pass the args from the cli, they have a default value of `False` instead of `None`.

I'm not sure if this is a intended design or a mistake, sorry for disturbing.

<!-- A clear and concise description of what you would expect to happen. -->



Discussion:
Yes optional bools are not supported by the `HFArgumentParser` because it wants to either `store_true` or `store_false` them. I have fixed the `TrainingArguments` to work around that (e.g., the defaults that come from the parser are okay) but when I have a bit of time I'll try to fix this better.
Thanks. I want to report a related issue:

For the same reason above, the argument `evaluate_during_training` would be set to either `store_true` or `store_false`, so its default value of `None` doesn't work.
https://github.com/huggingface/transformers/blob/1ba08dc221ff101a751c16462c3a256d726e7c85/src/transformers/training_args.py#L188-L191

And this may lead to another problem:
https://github.com/huggingface/transformers/blob/1ba08dc221ff101a751c16462c3a256d726e7c85/src/transformers/training_args.py#L326-L335
Line 326 will always be `True`, and the `EvaluationStrategy` can only be chosen from `STEPS` and `NO`, but without `EPOCH`.

The final result is（I remove unimportant args):
`python main.py --evaluation_strategy epoch`
may lead to `evaluation_strategy=EvaluationStrategy.NO`
while
`python main.py --evaluate_during_training --evaluation_strategy epoch`
may lead to `evaluation_strategy=EvaluationStrategy.STEPS`

Resolving patch:
diff --git a/src/transformers/hf_argparser.py b/src/transformers/hf_argparser.py
--- a/src/transformers/hf_argparser.py
+++ b/src/transformers/hf_argparser.py
@@ -65,7 +65,8 @@ def _add_dataclass_arguments(self, dtype: DataClassType):
                 if field.default is not dataclasses.MISSING:
                     kwargs["default"] = field.default
             elif field.type is bool or field.type is Optional[bool]:
-                kwargs["action"] = "store_false" if field.default is True else "store_true"
+                if field.type is bool or (field.default is not None and field.default is not dataclasses.MISSING):
+                    kwargs["action"] = "store_false" if field.default is True else "store_true"
                 if field.default is True:
                     field_name = f"--no-{field.name}"
                     kwargs["dest"] = field.name
diff --git a/src/transformers/training_args.py b/src/transformers/training_args.py
--- a/src/transformers/training_args.py
+++ b/src/transformers/training_args.py
@@ -187,7 +187,7 @@ class TrainingArguments:
     do_eval: bool = field(default=None, metadata={"help": "Whether to run eval on the dev set."})
     do_predict: bool = field(default=False, metadata={"help": "Whether to run predictions on the test set."})
     evaluate_during_training: bool = field(
-        default=None,
+        default=False,
         metadata={"help": "Run evaluation during training at each logging step."},
     )
     evaluation_strategy: EvaluationStrategy = field(


Test patch:
diff --git a/examples/test_xla_examples.py b/examples/test_xla_examples.py
--- a/examples/test_xla_examples.py
+++ b/examples/test_xla_examples.py
@@ -59,7 +59,7 @@ def test_run_glue(self):
             --model_name_or_path=bert-base-cased
             --per_device_train_batch_size=64
             --per_device_eval_batch_size=64
-            --evaluate_during_training
+            --evaluation_strategy steps
             --overwrite_cache
             """.split()
         with patch.object(sys, "argv", testargs):