We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Stats precision of FileTrainLogger
Now, all the stats logged by a FileTrainLogger have the precision 2 after their decimal points. In some training scenarios, precision 2 is not enough for some stats. I suggest allowing users to decide precision for each stats or adding precision number to 4 or 5 uniformly.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `speechbrain/utils/train_logger.py`
Content:
```
1 """
2 Loggers for experiment monitoring
3 
4 Authors
5  * Peter Plantinga 2020
6 """
7 import logging
8 from speechbrain.utils.edit_distance import wer_summary
9 
10 logger = logging.getLogger(__name__)
11 
12 
13 class TrainLogger:
14     """Abstract class defining an interface for training loggers."""
15 
16     def log_stats(
17         self,
18         stats_meta,
19         train_stats=None,
20         valid_stats=None,
21         test_stats=None,
22         verbose=False,
23     ):
24         """Log the stats for one epoch.
25 
26         Arguments
27         ---------
28         stats_meta : dict of str:scalar pairs
29             Meta information about the stats (e.g. epoch, learning-rate, etc.)
30         train_stats : dict of str:list pairs
31             Each loss type is represented with a str : list pair including
32             all the values for the training pass.
33         valid_stats : dict of str:list pairs
34             Each loss type is represented with a str : list pair including
35             all the values for the validation pass.
36         test_stats : dict of str:list pairs
37             Each loss type is represented with a str : list pair including
38             all the values for the test pass.
39         verbose : bool
40             Whether to also put logging information to the standard logger.
41         """
42         raise NotImplementedError
43 
44 
45 class FileTrainLogger(TrainLogger):
46     """Text logger of training information
47 
48     Arguments
49     ---------
50     save_file : str
51         The file to use for logging train information.
52     summary_fns : dict of str:function pairs
53         Each summary function should take a list produced as output
54         from a training/validation pass and summarize it to a single scalar.
55     """
56 
57     def __init__(self, save_file, summary_fns=None):
58         self.save_file = save_file
59         self.summary_fns = summary_fns or {}
60 
61     def _item_to_string(self, key, value, dataset=None):
62         """Convert one item to string, handling floats"""
63         if isinstance(value, float) and 0.01 < value < 100.0:
64             value = f"{value:.2f}"
65         elif isinstance(value, float):
66             value = f"{value:.2e}"
67         if dataset is not None:
68             key = f"{dataset} {key}"
69         return f"{key}: {value}"
70 
71     def _stats_to_string(self, stats, dataset=None):
72         """Convert all stats to a single string summary"""
73         return ", ".join(
74             [self._item_to_string(k, v, dataset) for k, v in stats.items()]
75         )
76 
77     def log_stats(
78         self,
79         stats_meta,
80         train_stats=None,
81         valid_stats=None,
82         test_stats=None,
83         verbose=True,
84     ):
85         """See TrainLogger.log_stats()"""
86         string_summary = self._stats_to_string(stats_meta)
87         for dataset, stats in [
88             ("train", train_stats),
89             ("valid", valid_stats),
90             ("test", test_stats),
91         ]:
92             if stats is None:
93                 continue
94             summary = {}
95             for stat, value_list in stats.items():
96                 if stat in self.summary_fns:
97                     summary[stat] = self.summary_fns[stat](value_list)
98                 else:
99                     summary[stat] = summarize_average(value_list)
100             string_summary += " - " + self._stats_to_string(summary, dataset)
101 
102         with open(self.save_file, "a") as fout:
103             print(string_summary, file=fout)
104         if verbose:
105             logger.info(string_summary)
106 
107 
108 class TensorboardLogger(TrainLogger):
109     """Logs training information in the format required by Tensorboard.
110 
111     Arguments
112     ---------
113     save_dir : str
114         A directory for storing all the relevant logs
115 
116     Raises
117     ------
118     ImportError if Tensorboard is not installed.
119     """
120 
121     def __init__(self, save_dir):
122         self.save_dir = save_dir
123 
124         # Raises ImportError if TensorBoard is not installed
125         from torch.utils.tensorboard import SummaryWriter
126 
127         self.writer = SummaryWriter(self.save_dir)
128         self.global_step = {"train": {}, "valid": {}, "meta": 0}
129 
130     def log_stats(
131         self,
132         stats_meta,
133         train_stats=None,
134         valid_stats=None,
135         test_stats=None,
136         verbose=False,
137     ):
138         """See TrainLogger.log_stats()"""
139         self.global_step["meta"] += 1
140         for name, value in stats_meta.items():
141             self.writer.add_scalar(name, value, self.global_step["meta"])
142 
143         for dataset, stats in [
144             ("train", train_stats),
145             ("valid", valid_stats),
146             ("test", test_stats),
147         ]:
148             if stats is None:
149                 continue
150             for stat, value_list in stats.items():
151                 if stat not in self.global_step[dataset]:
152                     self.global_step[dataset][stat] = 0
153                 tag = f"{stat}/{dataset}"
154                 for value in value_list:
155                     new_global_step = self.global_step[dataset][stat] + 1
156                     self.writer.add_scalar(tag, value, new_global_step)
157                     self.global_step[dataset][stat] = new_global_step
158 
159 
160 def summarize_average(stat_list):
161     return float(sum(stat_list) / len(stat_list))
162 
163 
164 def summarize_error_rate(stat_list):
165     summary = wer_summary(stat_list)
166     return summary["WER"]
167
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/speechbrain/utils/train_logger.py b/speechbrain/utils/train_logger.py
--- a/speechbrain/utils/train_logger.py
+++ b/speechbrain/utils/train_logger.py
@@ -49,21 +49,24 @@
     ---------
     save_file : str
         The file to use for logging train information.
+    precision : int
+        Number of decimal places to display. Default 2, example: 1.35e-5
     summary_fns : dict of str:function pairs
         Each summary function should take a list produced as output
         from a training/validation pass and summarize it to a single scalar.
     """
 
-    def __init__(self, save_file, summary_fns=None):
+    def __init__(self, save_file, precision=2, summary_fns=None):
         self.save_file = save_file
+        self.precision = precision
         self.summary_fns = summary_fns or {}
 
     def _item_to_string(self, key, value, dataset=None):
         """Convert one item to string, handling floats"""
-        if isinstance(value, float) and 0.01 < value < 100.0:
-            value = f"{value:.2f}"
+        if isinstance(value, float) and 1.0 < value < 100.0:
+            value = f"{value:.{self.precision}f}"
         elif isinstance(value, float):
-            value = f"{value:.2e}"
+            value = f"{value:.{self.precision}e}"
         if dataset is not None:
             key = f"{dataset} {key}"
         return f"{key}: {value}"

{"golden_diff": "diff --git a/speechbrain/utils/train_logger.py b/speechbrain/utils/train_logger.py\n--- a/speechbrain/utils/train_logger.py\n+++ b/speechbrain/utils/train_logger.py\n@@ -49,21 +49,24 @@\n     ---------\n     save_file : str\n         The file to use for logging train information.\n+    precision : int\n+        Number of decimal places to display. Default 2, example: 1.35e-5\n     summary_fns : dict of str:function pairs\n         Each summary function should take a list produced as output\n         from a training/validation pass and summarize it to a single scalar.\n     \"\"\"\n \n-    def __init__(self, save_file, summary_fns=None):\n+    def __init__(self, save_file, precision=2, summary_fns=None):\n         self.save_file = save_file\n+        self.precision = precision\n         self.summary_fns = summary_fns or {}\n \n     def _item_to_string(self, key, value, dataset=None):\n         \"\"\"Convert one item to string, handling floats\"\"\"\n-        if isinstance(value, float) and 0.01 < value < 100.0:\n-            value = f\"{value:.2f}\"\n+        if isinstance(value, float) and 1.0 < value < 100.0:\n+            value = f\"{value:.{self.precision}f}\"\n         elif isinstance(value, float):\n-            value = f\"{value:.2e}\"\n+            value = f\"{value:.{self.precision}e}\"\n         if dataset is not None:\n             key = f\"{dataset} {key}\"\n         return f\"{key}: {value}\"\n", "issue": "Stats precision of FileTrainLogger\nNow, all the stats logged by a FileTrainLogger have the precision 2 after their decimal points. In some training scenarios, precision 2 is not enough for some stats. I suggest allowing users to decide precision for each stats or adding precision number to 4 or 5 uniformly.\n", "before_files": [{"content": "\"\"\"\nLoggers for experiment monitoring\n\nAuthors\n * Peter Plantinga 2020\n\"\"\"\nimport logging\nfrom speechbrain.utils.edit_distance import wer_summary\n\nlogger = logging.getLogger(__name__)\n\n\nclass TrainLogger:\n    \"\"\"Abstract class defining an interface for training loggers.\"\"\"\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=False,\n    ):\n        \"\"\"Log the stats for one epoch.\n\n        Arguments\n        ---------\n        stats_meta : dict of str:scalar pairs\n            Meta information about the stats (e.g. epoch, learning-rate, etc.)\n        train_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the training pass.\n        valid_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the validation pass.\n        test_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the test pass.\n        verbose : bool\n            Whether to also put logging information to the standard logger.\n        \"\"\"\n        raise NotImplementedError\n\n\nclass FileTrainLogger(TrainLogger):\n    \"\"\"Text logger of training information\n\n    Arguments\n    ---------\n    save_file : str\n        The file to use for logging train information.\n    summary_fns : dict of str:function pairs\n        Each summary function should take a list produced as output\n        from a training/validation pass and summarize it to a single scalar.\n    \"\"\"\n\n    def __init__(self, save_file, summary_fns=None):\n        self.save_file = save_file\n        self.summary_fns = summary_fns or {}\n\n    def _item_to_string(self, key, value, dataset=None):\n        \"\"\"Convert one item to string, handling floats\"\"\"\n        if isinstance(value, float) and 0.01 < value < 100.0:\n            value = f\"{value:.2f}\"\n        elif isinstance(value, float):\n            value = f\"{value:.2e}\"\n        if dataset is not None:\n            key = f\"{dataset} {key}\"\n        return f\"{key}: {value}\"\n\n    def _stats_to_string(self, stats, dataset=None):\n        \"\"\"Convert all stats to a single string summary\"\"\"\n        return \", \".join(\n            [self._item_to_string(k, v, dataset) for k, v in stats.items()]\n        )\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=True,\n    ):\n        \"\"\"See TrainLogger.log_stats()\"\"\"\n        string_summary = self._stats_to_string(stats_meta)\n        for dataset, stats in [\n            (\"train\", train_stats),\n            (\"valid\", valid_stats),\n            (\"test\", test_stats),\n        ]:\n            if stats is None:\n                continue\n            summary = {}\n            for stat, value_list in stats.items():\n                if stat in self.summary_fns:\n                    summary[stat] = self.summary_fns[stat](value_list)\n                else:\n                    summary[stat] = summarize_average(value_list)\n            string_summary += \" - \" + self._stats_to_string(summary, dataset)\n\n        with open(self.save_file, \"a\") as fout:\n            print(string_summary, file=fout)\n        if verbose:\n            logger.info(string_summary)\n\n\nclass TensorboardLogger(TrainLogger):\n    \"\"\"Logs training information in the format required by Tensorboard.\n\n    Arguments\n    ---------\n    save_dir : str\n        A directory for storing all the relevant logs\n\n    Raises\n    ------\n    ImportError if Tensorboard is not installed.\n    \"\"\"\n\n    def __init__(self, save_dir):\n        self.save_dir = save_dir\n\n        # Raises ImportError if TensorBoard is not installed\n        from torch.utils.tensorboard import SummaryWriter\n\n        self.writer = SummaryWriter(self.save_dir)\n        self.global_step = {\"train\": {}, \"valid\": {}, \"meta\": 0}\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=False,\n    ):\n        \"\"\"See TrainLogger.log_stats()\"\"\"\n        self.global_step[\"meta\"] += 1\n        for name, value in stats_meta.items():\n            self.writer.add_scalar(name, value, self.global_step[\"meta\"])\n\n        for dataset, stats in [\n            (\"train\", train_stats),\n            (\"valid\", valid_stats),\n            (\"test\", test_stats),\n        ]:\n            if stats is None:\n                continue\n            for stat, value_list in stats.items():\n                if stat not in self.global_step[dataset]:\n                    self.global_step[dataset][stat] = 0\n                tag = f\"{stat}/{dataset}\"\n                for value in value_list:\n                    new_global_step = self.global_step[dataset][stat] + 1\n                    self.writer.add_scalar(tag, value, new_global_step)\n                    self.global_step[dataset][stat] = new_global_step\n\n\ndef summarize_average(stat_list):\n    return float(sum(stat_list) / len(stat_list))\n\n\ndef summarize_error_rate(stat_list):\n    summary = wer_summary(stat_list)\n    return summary[\"WER\"]\n", "path": "speechbrain/utils/train_logger.py"}], "after_files": [{"content": "\"\"\"\nLoggers for experiment monitoring\n\nAuthors\n * Peter Plantinga 2020\n\"\"\"\nimport logging\nfrom speechbrain.utils.edit_distance import wer_summary\n\nlogger = logging.getLogger(__name__)\n\n\nclass TrainLogger:\n    \"\"\"Abstract class defining an interface for training loggers.\"\"\"\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=False,\n    ):\n        \"\"\"Log the stats for one epoch.\n\n        Arguments\n        ---------\n        stats_meta : dict of str:scalar pairs\n            Meta information about the stats (e.g. epoch, learning-rate, etc.)\n        train_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the training pass.\n        valid_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the validation pass.\n        test_stats : dict of str:list pairs\n            Each loss type is represented with a str : list pair including\n            all the values for the test pass.\n        verbose : bool\n            Whether to also put logging information to the standard logger.\n        \"\"\"\n        raise NotImplementedError\n\n\nclass FileTrainLogger(TrainLogger):\n    \"\"\"Text logger of training information\n\n    Arguments\n    ---------\n    save_file : str\n        The file to use for logging train information.\n    precision : int\n        Number of decimal places to display. Default 2, example: 1.35e-5\n    summary_fns : dict of str:function pairs\n        Each summary function should take a list produced as output\n        from a training/validation pass and summarize it to a single scalar.\n    \"\"\"\n\n    def __init__(self, save_file, precision=2, summary_fns=None):\n        self.save_file = save_file\n        self.precision = precision\n        self.summary_fns = summary_fns or {}\n\n    def _item_to_string(self, key, value, dataset=None):\n        \"\"\"Convert one item to string, handling floats\"\"\"\n        if isinstance(value, float) and 1.0 < value < 100.0:\n            value = f\"{value:.{self.precision}f}\"\n        elif isinstance(value, float):\n            value = f\"{value:.{self.precision}e}\"\n        if dataset is not None:\n            key = f\"{dataset} {key}\"\n        return f\"{key}: {value}\"\n\n    def _stats_to_string(self, stats, dataset=None):\n        \"\"\"Convert all stats to a single string summary\"\"\"\n        return \", \".join(\n            [self._item_to_string(k, v, dataset) for k, v in stats.items()]\n        )\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=True,\n    ):\n        \"\"\"See TrainLogger.log_stats()\"\"\"\n        string_summary = self._stats_to_string(stats_meta)\n        for dataset, stats in [\n            (\"train\", train_stats),\n            (\"valid\", valid_stats),\n            (\"test\", test_stats),\n        ]:\n            if stats is None:\n                continue\n            summary = {}\n            for stat, value_list in stats.items():\n                if stat in self.summary_fns:\n                    summary[stat] = self.summary_fns[stat](value_list)\n                else:\n                    summary[stat] = summarize_average(value_list)\n            string_summary += \" - \" + self._stats_to_string(summary, dataset)\n\n        with open(self.save_file, \"a\") as fout:\n            print(string_summary, file=fout)\n        if verbose:\n            logger.info(string_summary)\n\n\nclass TensorboardLogger(TrainLogger):\n    \"\"\"Logs training information in the format required by Tensorboard.\n\n    Arguments\n    ---------\n    save_dir : str\n        A directory for storing all the relevant logs\n\n    Raises\n    ------\n    ImportError if Tensorboard is not installed.\n    \"\"\"\n\n    def __init__(self, save_dir):\n        self.save_dir = save_dir\n\n        # Raises ImportError if TensorBoard is not installed\n        from torch.utils.tensorboard import SummaryWriter\n\n        self.writer = SummaryWriter(self.save_dir)\n        self.global_step = {\"train\": {}, \"valid\": {}, \"meta\": 0}\n\n    def log_stats(\n        self,\n        stats_meta,\n        train_stats=None,\n        valid_stats=None,\n        test_stats=None,\n        verbose=False,\n    ):\n        \"\"\"See TrainLogger.log_stats()\"\"\"\n        self.global_step[\"meta\"] += 1\n        for name, value in stats_meta.items():\n            self.writer.add_scalar(name, value, self.global_step[\"meta\"])\n\n        for dataset, stats in [\n            (\"train\", train_stats),\n            (\"valid\", valid_stats),\n            (\"test\", test_stats),\n        ]:\n            if stats is None:\n                continue\n            for stat, value_list in stats.items():\n                if stat not in self.global_step[dataset]:\n                    self.global_step[dataset][stat] = 0\n                tag = f\"{stat}/{dataset}\"\n                for value in value_list:\n                    new_global_step = self.global_step[dataset][stat] + 1\n                    self.writer.add_scalar(tag, value, new_global_step)\n                    self.global_step[dataset][stat] = new_global_step\n\n\ndef summarize_average(stat_list):\n    return float(sum(stat_list) / len(stat_list))\n\n\ndef summarize_error_rate(stat_list):\n    summary = wer_summary(stat_list)\n    return summary[\"WER\"]\n", "path": "speechbrain/utils/train_logger.py"}]}