Repository: huggingface/transformers

Issue:
Object of type 'int64' is not JSON serializable in Trainer.save_checkpoint
I am using the recent run_ner.py example script to train an NER model. I want to evaluate the performance of the model during training and use the following command for training:

```
python3 run_ner.py 
--model_name_or_path bert-base-uncased                                                                                                                                     
--dataset_name conll2003                                                                                                                         
--return_entity_level_metrics                                                                                                                                               
--output_dir conll-tmp                                                                                                                                                    
--overwrite_output_dir                                                                                                                                                      
--do_train                                                                                                                                                                 
--do_eval                                                                                                                                                                   
--do_predict                                                                                                                                                                
--evaluation_strategy steps                                                                                                                                                
--logging_steps 10                                                                                                                                                         
--eval_steps 10                                                                                                                                                            
--load_best_model_at_end
```
I run the command in the current docker image huggingface/transformers-pytorch-gpu
However, I get the following error:
```
Traceback (most recent call last):                                                                                                                                             
File "run_ner.py", line 470, in main()                                                                                                                                                                     
File "run_ner.py", line 404, in main                                                                                                                              
train_result = trainer.train(resume_from_checkpoint=checkpoint)                                                                                                            File "/usr/local/lib/python3.6/dist-packages/transformers/trainer.py", line 983, in train                                                                                      self._maybe_log_save_evaluate(tr_loss, model, trial, epoch)                                                                                                                File "/usr/local/lib/python3.6/dist-packages/transformers/trainer.py", line 1062, in _maybe_log_save_evaluate                                                                  self._save_checkpoint(model, trial, metrics=metrics)                                                                                                                       
File "/usr/local/lib/python3.6/dist-packages/transformers/trainer.py", line 1126, in _save_checkpoint                                                                          self.state.save_to_json(os.path.join(output_dir, "trainer_state.json"))                                                                                                    File "/usr/local/lib/python3.6/dist-packages/transformers/trainer_callback.py", line 95, in save_to_json                                                                       json_string = json.dumps(dataclasses.asdict(self), indent=2, sort_keys=True) + "\n"                                                                                        File "/usr/lib/python3.6/json/__init__.py", line 238, in dumps                                                                                                                 **kw).encode(obj)                                                                                                                                                          
File "/usr/lib/python3.6/json/encoder.py", line 201, in encode                                                                                                                 chunks = list(chunks)                                                                                                                                                      
File "/usr/lib/python3.6/json/encoder.py", line 430, in _iterencode                                                                                                            yield from _iterencode_dict(o, _current_indent_level)                                                                                                                      
File "/usr/lib/python3.6/json/encoder.py", line 404, in _iterencode_dict                                                                                                       yield from chunks                                                                                                                                                          
File "/usr/lib/python3.6/json/encoder.py", line 325, in _iterencode_list                                                                                                       yield from chunks                                                                                                                                                          
File "/usr/lib/python3.6/json/encoder.py", line 404, in _iterencode_dict                                                                                                       yield from chunks                                                                                                                                                          
File "/usr/lib/python3.6/json/encoder.py", line 437, in _iterencode                                                                                                            o = _default(o)                                                                                                                                                            
File "/usr/lib/python3.6/json/encoder.py", line 180, in default                                                                                                                o.__class__.__name__)                                                                                                                                                    
TypeError: Object of type 'int64' is not JSON serializable
--
```





 


Discussion:
I too ran into this problem and its caused by turning on evaluation strategy which then adds metrics in the log_history of the models state, which is using numpy data types and causes the JSON encoder issue. That was the case with 4.3.3. There appear to be a bunch of changes in the trainer in the works, whether this has been fixed as a result of those i've not checked.
As a temporary work around you can modify trainer.py at line 1260 "output = {**logs, **{"step": self.state.global_step}}" and add the following three lines after. If the metrics are being calculated the same in the latest code as in 4.3.3 then something like this may also be needed going forward, or things calling the log method will need to ensure they safely cast data points beforehand if its going to be added to the trainer state still.

```
        for k,v in output.items():
            if isinstance(v, np.generic):
                output[k]=v.item()
```
I confirm I can reproduce in master. Will investigate more tomorrow.

Resolving patch:
diff --git a/src/transformers/trainer.py b/src/transformers/trainer.py
--- a/src/transformers/trainer.py
+++ b/src/transformers/trainer.py
@@ -98,6 +98,7 @@
     TrainOutput,
     default_compute_objective,
     default_hp_space,
+    denumpify_detensorize,
     get_last_checkpoint,
     set_seed,
     speed_metrics,
@@ -1824,6 +1825,9 @@ def prediction_loop(
         else:
             metrics = {}
 
+        # To be JSON-serializable, we need to remove numpy types or zero-d tensors
+        metrics = denumpify_detensorize(metrics)
+
         if eval_loss is not None:
             metrics[f"{metric_key_prefix}_loss"] = eval_loss.mean().item()
 
diff --git a/src/transformers/trainer_utils.py b/src/transformers/trainer_utils.py
--- a/src/transformers/trainer_utils.py
+++ b/src/transformers/trainer_utils.py
@@ -38,6 +38,13 @@
 )
 
 
+if is_torch_available():
+    import torch
+
+if is_tf_available():
+    import tensorflow as tf
+
+
 def set_seed(seed: int):
     """
     Helper function for reproducible behavior to set the seed in ``random``, ``numpy``, ``torch`` and/or ``tf`` (if
@@ -49,14 +56,10 @@ def set_seed(seed: int):
     random.seed(seed)
     np.random.seed(seed)
     if is_torch_available():
-        import torch
-
         torch.manual_seed(seed)
         torch.cuda.manual_seed_all(seed)
         # ^^ safe to call this function even if cuda is not available
     if is_tf_available():
-        import tensorflow as tf
-
         tf.random.set_seed(seed)
 
 
@@ -423,6 +426,21 @@ def stop_and_update_metrics(self, metrics=None):
             self.update_metrics(stage, metrics)
 
 
+def denumpify_detensorize(metrics):
+    """
+    Recursively calls `.item()` on the element of the dictionary passed
+    """
+    if isinstance(metrics, (list, tuple)):
+        return type(metrics)(denumpify_detensorize(m) for m in metrics)
+    elif isinstance(metrics, dict):
+        return type(metrics)({k: denumpify_detensorize(v) for k, v in metrics.items()})
+    elif isinstance(metrics, np.generic):
+        return metrics.item()
+    elif is_torch_available() and isinstance(metrics, torch.Tensor) and metrics.numel() == 1:
+        return metrics.item()
+    return metrics
+
+
 class ShardedDDPOption(ExplicitEnum):
     SIMPLE = "simple"
     ZERO_DP_2 = "zero_dp_2"


Test patch: