We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
fastai: wandb not logging fastai validation loss with default args
`wandb --version && python --version && uname`

* Weights and Biases version: 0.8.5
* Python version: 3.7.3
* Operating System: Linux
* fast.ai version: 1.0.55

### Description

When you use the `fastai` callback `WandbCallback` with the default arguments you get some errors and the validation loss is not logged.

### What I Did

1. Run the following code in a jupyter notebook
```
import wandb
import fastai
from wandb.fastai import WandbCallback
from fastai.vision import *
from functools import partial
print(f'wandb version: {wandb.__version__}, fastai version: {fastai.__version__}')
wandb.init(project="fastai-test")
path = untar_data(URLs.MNIST_SAMPLE)
data = ImageDataBunch.from_folder(path)
learn = cnn_learner(data, models.resnet18, metrics=accuracy, callback_fns=WandbCallback)
learn.fit_one_cycle(1, 1e-2)
```

2. You'll get the following error:

![image](https://user-images.githubusercontent.com/38154/61618701-b7d63080-acb0-11e9-9eb1-9de4addaa9cd.png)

```
/home/fastai/anaconda3/envs/wandbtest/lib/python3.7/site-packages/fastai/callbacks/tracker.py:50: UserWarning: <class 'wandb.fastai.WandbCallback'> conditioned on metric `val_loss` which is not available. Available metrics are: train_loss, valid_loss, accuracy
  warn(f'{self.__class__} conditioned on metric `{self.monitor}` which is not available. Available metrics are: {", ".join(map(str, self.learn.recorder.names[1:-1]))}')
```

3. To fix it you can tell it to monitor `valid_loss` by changing the callback to be:

``` python
learn = cnn_learner(data, models.resnet18, metrics=accuracy, callback_fns=partial(WandbCallback, monitor='valid_loss'))
```

I'm guessing that the name of the loss changed with fast.ai at some point.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wandb/fastai/__init__.py`
Content:
```
1 '''W&B Callback for fast.ai
2 
3 This module hooks fast.ai Learners to Weights & Biases through a callback.
4 Requested logged data can be configured through the callback constructor.
5 
6 Examples:
7     WandbCallback can be used when initializing the Learner::
8 
9         from wandb.fastai import WandbCallback
10         [...]
11         learn = Learner(data, ..., callback_fns=WandbCallback)
12         learn.fit(epochs)
13     
14     Custom parameters can be given using functools.partial::
15 
16         from wandb.fastai import WandbCallback
17         from functools import partial
18         [...]
19         learn = Learner(data, ..., callback_fns=partial(WandbCallback, ...))
20         learn.fit(epochs)
21 
22     Finally, it is possible to use WandbCallback only when starting
23     training. In this case it must be instantiated::
24 
25         learn.fit(..., callbacks=WandbCallback())
26 
27     or, with custom parameters::
28 
29         learn.fit(..., callbacks=WandBCallback(learn, ...))
30 '''
31 import wandb
32 from fastai.callbacks import TrackerCallback
33 from pathlib import Path
34 import random
35 try:
36     import matplotlib
37     matplotlib.use('Agg')  # non-interactive backend (avoid tkinter issues)
38     import matplotlib.pyplot as plt
39 except:
40     print('Warning: matplotlib required if logging sample image predictions')
41 
42 
43 class WandbCallback(TrackerCallback):
44 
45     # Record if watch has been called previously (even in another instance)
46     watch_called = False
47 
48     def __init__(self,
49                  learn,
50                  log="gradients",
51                  save_model=True,
52                  monitor='val_loss',
53                  mode='auto',
54                  input_type=None,
55                  validation_data=None,
56                  predictions=36):
57         """WandB fast.ai Callback
58 
59         Automatically saves model topology, losses & metrics.
60         Optionally logs weights, gradients, sample predictions and best trained model.
61 
62         Args:
63             learn (fastai.basic_train.Learner): the fast.ai learner to hook.
64             log (str): "gradients", "parameters", "all", or None. Losses & metrics are always logged.
65             save_model (bool): save model at the end of each epoch.
66             monitor (str): metric to monitor for saving best model.
67             mode (str): "auto", "min" or "max" to compare "monitor" values and define best model.
68             input_type (str): "images" or None. Used to display sample predictions.
69             validation_data (list): data used for sample predictions if input_type is set.
70             predictions (int): number of predictions to make if input_type is set and validation_data is None.
71         """
72 
73         # Check if wandb.init has been called
74         if wandb.run is None:
75             raise ValueError(
76                 'You must call wandb.init() before WandbCallback()')
77 
78         # Adapted from fast.ai "SaveModelCallback"
79         super().__init__(learn, monitor=monitor, mode=mode)
80         self.save_model = save_model
81         self.model_path = Path(wandb.run.dir) / 'bestmodel.pth'
82 
83         self.log = log
84         self.input_type = input_type
85         self.best = None
86 
87         # Select items for sample predictions to see evolution along training
88         self.validation_data = validation_data
89         if input_type and not self.validation_data:
90             predictions = min(predictions, len(learn.data.valid_ds))
91             indices = random.sample(range(len(learn.data.valid_ds)),
92                                     predictions)
93             self.validation_data = [learn.data.valid_ds[i] for i in indices]
94 
95     def on_train_begin(self, **kwargs):
96         "Call watch method to log model topology, gradients & weights"
97 
98         # Set self.best, method inherited from "TrackerCallback" by "SaveModelCallback"
99         super().on_train_begin()
100 
101         # Ensure we don't call "watch" multiple times
102         if not WandbCallback.watch_called:
103             WandbCallback.watch_called = True
104 
105             # Logs model topology and optionally gradients and weights
106             wandb.watch(self.learn.model, log=self.log)
107 
108     def on_epoch_end(self, epoch, smooth_loss, last_metrics, **kwargs):
109         "Logs training loss, validation loss and custom metrics & log prediction samples & save model"
110 
111         if self.save_model:
112             # Adapted from fast.ai "SaveModelCallback"
113             current = self.get_monitor_value()
114             if current is not None and self.operator(current, self.best):
115                 print(
116                     'Better model found at epoch {} with {} value: {}.'.format(
117                         epoch, self.monitor, current))
118                 self.best = current
119 
120                 # Save within wandb folder
121                 with self.model_path.open('wb') as model_file:
122                     self.learn.save(model_file)
123 
124         # Log sample predictions
125         if self.validation_data:
126             pred_log = []
127 
128             for x, y in self.validation_data:
129                 pred = self.learn.predict(x)
130 
131                 # scalar -> likely to be a category
132                 if not pred[1].shape:
133                     pred_log.append(
134                         wandb.Image(
135                             x.data,
136                             caption='Ground Truth: {}\nPrediction: {}'.format(
137                                 y, pred[0])))
138 
139                 # most vision datasets have a "show" function we can use
140                 elif hasattr(x, "show"):
141                     # log input data
142                     pred_log.append(
143                         wandb.Image(x.data, caption='Input data', grouping=3))
144 
145                     # log label and prediction
146                     for im, capt in (y, "Ground Truth"), (pred[0],
147                                                           "Prediction"):
148                         # Resize plot to image resolution
149                         # from https://stackoverflow.com/a/13714915
150                         my_dpi = 100
151                         fig = plt.figure(frameon=False, dpi=my_dpi)
152                         h, w = x.size
153                         fig.set_size_inches(w / my_dpi, h / my_dpi)
154                         ax = plt.Axes(fig, [0., 0., 1., 1.])
155                         ax.set_axis_off()
156                         fig.add_axes(ax)
157 
158                         # Superpose label or prediction to input image
159                         x.show(ax=ax, y=im)
160                         pred_log.append(wandb.Image(fig, caption=capt))
161                         plt.close(fig)
162 
163                 # likely to be an image
164                 elif hasattr(y, "shape") and (
165                     (len(y.shape) == 2) or
166                     (len(y.shape) == 3 and y.shape[0] in [1, 3, 4])):
167 
168                     pred_log.extend([
169                         wandb.Image(x.data, caption='Input data', grouping=3),
170                         wandb.Image(y.data, caption='Ground Truth'),
171                         wandb.Image(pred[0].data, caption='Prediction')
172                     ])
173 
174                 # we just log input data
175                 else:
176                     pred_log.append(wandb.Image(x.data, caption='Input data'))
177 
178             wandb.log({"Prediction Samples": pred_log}, commit=False)
179 
180         # Log losses & metrics
181         # Adapted from fast.ai "CSVLogger"
182         logs = {
183             name: stat
184             for name, stat in list(
185                 zip(self.learn.recorder.names, [epoch, smooth_loss] +
186                     last_metrics))[1:]
187         }
188         wandb.log(logs)
189 
190     def on_train_end(self, **kwargs):
191         "Load the best model."
192 
193         if self.save_model:
194             # Adapted from fast.ai "SaveModelCallback"
195             if self.model_path.is_file():
196                 with self.model_path.open('rb') as model_file:
197                     self.learn.load(model_file, purge=False)
198                     print('Loaded best saved model from {}'.format(
199                         self.model_path))
200
```
--- 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/wandb/fastai/__init__.py b/wandb/fastai/__init__.py
--- a/wandb/fastai/__init__.py
+++ b/wandb/fastai/__init__.py
@@ -29,6 +29,7 @@
         learn.fit(..., callbacks=WandBCallback(learn, ...))
 '''
 import wandb
+import fastai
 from fastai.callbacks import TrackerCallback
 from pathlib import Path
 import random
@@ -49,7 +50,7 @@
                  learn,
                  log="gradients",
                  save_model=True,
-                 monitor='val_loss',
+                 monitor=None,
                  mode='auto',
                  input_type=None,
                  validation_data=None,
@@ -63,7 +64,7 @@
             learn (fastai.basic_train.Learner): the fast.ai learner to hook.
             log (str): "gradients", "parameters", "all", or None. Losses & metrics are always logged.
             save_model (bool): save model at the end of each epoch.
-            monitor (str): metric to monitor for saving best model.
+            monitor (str): metric to monitor for saving best model. None uses default TrackerCallback monitor value.
             mode (str): "auto", "min" or "max" to compare "monitor" values and define best model.
             input_type (str): "images" or None. Used to display sample predictions.
             validation_data (list): data used for sample predictions if input_type is set.
@@ -76,7 +77,11 @@
                 'You must call wandb.init() before WandbCallback()')
 
         # Adapted from fast.ai "SaveModelCallback"
-        super().__init__(learn, monitor=monitor, mode=mode)
+        if monitor is None:
+            # use default TrackerCallback monitor value
+            super().__init__(learn, mode=mode)
+        else:
+            super().__init__(learn, monitor=monitor, mode=mode)
         self.save_model = save_model
         self.model_path = Path(wandb.run.dir) / 'bestmodel.pth'

{"golden_diff": "diff --git a/wandb/fastai/__init__.py b/wandb/fastai/__init__.py\n--- a/wandb/fastai/__init__.py\n+++ b/wandb/fastai/__init__.py\n@@ -29,6 +29,7 @@\n         learn.fit(..., callbacks=WandBCallback(learn, ...))\n '''\n import wandb\n+import fastai\n from fastai.callbacks import TrackerCallback\n from pathlib import Path\n import random\n@@ -49,7 +50,7 @@\n                  learn,\n                  log=\"gradients\",\n                  save_model=True,\n-                 monitor='val_loss',\n+                 monitor=None,\n                  mode='auto',\n                  input_type=None,\n                  validation_data=None,\n@@ -63,7 +64,7 @@\n             learn (fastai.basic_train.Learner): the fast.ai learner to hook.\n             log (str): \"gradients\", \"parameters\", \"all\", or None. Losses & metrics are always logged.\n             save_model (bool): save model at the end of each epoch.\n-            monitor (str): metric to monitor for saving best model.\n+            monitor (str): metric to monitor for saving best model. None uses default TrackerCallback monitor value.\n             mode (str): \"auto\", \"min\" or \"max\" to compare \"monitor\" values and define best model.\n             input_type (str): \"images\" or None. Used to display sample predictions.\n             validation_data (list): data used for sample predictions if input_type is set.\n@@ -76,7 +77,11 @@\n                 'You must call wandb.init() before WandbCallback()')\n \n         # Adapted from fast.ai \"SaveModelCallback\"\n-        super().__init__(learn, monitor=monitor, mode=mode)\n+        if monitor is None:\n+            # use default TrackerCallback monitor value\n+            super().__init__(learn, mode=mode)\n+        else:\n+            super().__init__(learn, monitor=monitor, mode=mode)\n         self.save_model = save_model\n         self.model_path = Path(wandb.run.dir) / 'bestmodel.pth'\n", "issue": "fastai: wandb not logging fastai validation loss with default args\n`wandb --version && python --version && uname`\r\n\r\n* Weights and Biases version: 0.8.5\r\n* Python version: 3.7.3\r\n* Operating System: Linux\r\n* fast.ai version: 1.0.55\r\n\r\n### Description\r\n\r\nWhen you use the `fastai` callback `WandbCallback` with the default arguments you get some errors and the validation loss is not logged.\r\n\r\n### What I Did\r\n\r\n1. Run the following code in a jupyter notebook\r\n```\r\nimport wandb\r\nimport fastai\r\nfrom wandb.fastai import WandbCallback\r\nfrom fastai.vision import *\r\nfrom functools import partial\r\nprint(f'wandb version: {wandb.__version__}, fastai version: {fastai.__version__}')\r\nwandb.init(project=\"fastai-test\")\r\npath = untar_data(URLs.MNIST_SAMPLE)\r\ndata = ImageDataBunch.from_folder(path)\r\nlearn = cnn_learner(data, models.resnet18, metrics=accuracy, callback_fns=WandbCallback)\r\nlearn.fit_one_cycle(1, 1e-2)\r\n```\r\n\r\n2. You'll get the following error:\r\n\r\n![image](https://user-images.githubusercontent.com/38154/61618701-b7d63080-acb0-11e9-9eb1-9de4addaa9cd.png)\r\n\r\n```\r\n/home/fastai/anaconda3/envs/wandbtest/lib/python3.7/site-packages/fastai/callbacks/tracker.py:50: UserWarning: <class 'wandb.fastai.WandbCallback'> conditioned on metric `val_loss` which is not available. Available metrics are: train_loss, valid_loss, accuracy\r\n  warn(f'{self.__class__} conditioned on metric `{self.monitor}` which is not available. Available metrics are: {\", \".join(map(str, self.learn.recorder.names[1:-1]))}')\r\n```\r\n\r\n3. To fix it you can tell it to monitor `valid_loss` by changing the callback to be:\r\n\r\n``` python\r\nlearn = cnn_learner(data, models.resnet18, metrics=accuracy, callback_fns=partial(WandbCallback, monitor='valid_loss'))\r\n```\r\n\r\nI'm guessing that the name of the loss changed with fast.ai at some point.\r\n\n", "before_files": [{"content": "'''W&B Callback for fast.ai\n\nThis module hooks fast.ai Learners to Weights & Biases through a callback.\nRequested logged data can be configured through the callback constructor.\n\nExamples:\n    WandbCallback can be used when initializing the Learner::\n\n        from wandb.fastai import WandbCallback\n        [...]\n        learn = Learner(data, ..., callback_fns=WandbCallback)\n        learn.fit(epochs)\n    \n    Custom parameters can be given using functools.partial::\n\n        from wandb.fastai import WandbCallback\n        from functools import partial\n        [...]\n        learn = Learner(data, ..., callback_fns=partial(WandbCallback, ...))\n        learn.fit(epochs)\n\n    Finally, it is possible to use WandbCallback only when starting\n    training. In this case it must be instantiated::\n\n        learn.fit(..., callbacks=WandbCallback())\n\n    or, with custom parameters::\n\n        learn.fit(..., callbacks=WandBCallback(learn, ...))\n'''\nimport wandb\nfrom fastai.callbacks import TrackerCallback\nfrom pathlib import Path\nimport random\ntry:\n    import matplotlib\n    matplotlib.use('Agg')  # non-interactive backend (avoid tkinter issues)\n    import matplotlib.pyplot as plt\nexcept:\n    print('Warning: matplotlib required if logging sample image predictions')\n\n\nclass WandbCallback(TrackerCallback):\n\n    # Record if watch has been called previously (even in another instance)\n    watch_called = False\n\n    def __init__(self,\n                 learn,\n                 log=\"gradients\",\n                 save_model=True,\n                 monitor='val_loss',\n                 mode='auto',\n                 input_type=None,\n                 validation_data=None,\n                 predictions=36):\n        \"\"\"WandB fast.ai Callback\n\n        Automatically saves model topology, losses & metrics.\n        Optionally logs weights, gradients, sample predictions and best trained model.\n\n        Args:\n            learn (fastai.basic_train.Learner): the fast.ai learner to hook.\n            log (str): \"gradients\", \"parameters\", \"all\", or None. Losses & metrics are always logged.\n            save_model (bool): save model at the end of each epoch.\n            monitor (str): metric to monitor for saving best model.\n            mode (str): \"auto\", \"min\" or \"max\" to compare \"monitor\" values and define best model.\n            input_type (str): \"images\" or None. Used to display sample predictions.\n            validation_data (list): data used for sample predictions if input_type is set.\n            predictions (int): number of predictions to make if input_type is set and validation_data is None.\n        \"\"\"\n\n        # Check if wandb.init has been called\n        if wandb.run is None:\n            raise ValueError(\n                'You must call wandb.init() before WandbCallback()')\n\n        # Adapted from fast.ai \"SaveModelCallback\"\n        super().__init__(learn, monitor=monitor, mode=mode)\n        self.save_model = save_model\n        self.model_path = Path(wandb.run.dir) / 'bestmodel.pth'\n\n        self.log = log\n        self.input_type = input_type\n        self.best = None\n\n        # Select items for sample predictions to see evolution along training\n        self.validation_data = validation_data\n        if input_type and not self.validation_data:\n            predictions = min(predictions, len(learn.data.valid_ds))\n            indices = random.sample(range(len(learn.data.valid_ds)),\n                                    predictions)\n            self.validation_data = [learn.data.valid_ds[i] for i in indices]\n\n    def on_train_begin(self, **kwargs):\n        \"Call watch method to log model topology, gradients & weights\"\n\n        # Set self.best, method inherited from \"TrackerCallback\" by \"SaveModelCallback\"\n        super().on_train_begin()\n\n        # Ensure we don't call \"watch\" multiple times\n        if not WandbCallback.watch_called:\n            WandbCallback.watch_called = True\n\n            # Logs model topology and optionally gradients and weights\n            wandb.watch(self.learn.model, log=self.log)\n\n    def on_epoch_end(self, epoch, smooth_loss, last_metrics, **kwargs):\n        \"Logs training loss, validation loss and custom metrics & log prediction samples & save model\"\n\n        if self.save_model:\n            # Adapted from fast.ai \"SaveModelCallback\"\n            current = self.get_monitor_value()\n            if current is not None and self.operator(current, self.best):\n                print(\n                    'Better model found at epoch {} with {} value: {}.'.format(\n                        epoch, self.monitor, current))\n                self.best = current\n\n                # Save within wandb folder\n                with self.model_path.open('wb') as model_file:\n                    self.learn.save(model_file)\n\n        # Log sample predictions\n        if self.validation_data:\n            pred_log = []\n\n            for x, y in self.validation_data:\n                pred = self.learn.predict(x)\n\n                # scalar -> likely to be a category\n                if not pred[1].shape:\n                    pred_log.append(\n                        wandb.Image(\n                            x.data,\n                            caption='Ground Truth: {}\\nPrediction: {}'.format(\n                                y, pred[0])))\n\n                # most vision datasets have a \"show\" function we can use\n                elif hasattr(x, \"show\"):\n                    # log input data\n                    pred_log.append(\n                        wandb.Image(x.data, caption='Input data', grouping=3))\n\n                    # log label and prediction\n                    for im, capt in (y, \"Ground Truth\"), (pred[0],\n                                                          \"Prediction\"):\n                        # Resize plot to image resolution\n                        # from https://stackoverflow.com/a/13714915\n                        my_dpi = 100\n                        fig = plt.figure(frameon=False, dpi=my_dpi)\n                        h, w = x.size\n                        fig.set_size_inches(w / my_dpi, h / my_dpi)\n                        ax = plt.Axes(fig, [0., 0., 1., 1.])\n                        ax.set_axis_off()\n                        fig.add_axes(ax)\n\n                        # Superpose label or prediction to input image\n                        x.show(ax=ax, y=im)\n                        pred_log.append(wandb.Image(fig, caption=capt))\n                        plt.close(fig)\n\n                # likely to be an image\n                elif hasattr(y, \"shape\") and (\n                    (len(y.shape) == 2) or\n                    (len(y.shape) == 3 and y.shape[0] in [1, 3, 4])):\n\n                    pred_log.extend([\n                        wandb.Image(x.data, caption='Input data', grouping=3),\n                        wandb.Image(y.data, caption='Ground Truth'),\n                        wandb.Image(pred[0].data, caption='Prediction')\n                    ])\n\n                # we just log input data\n                else:\n                    pred_log.append(wandb.Image(x.data, caption='Input data'))\n\n            wandb.log({\"Prediction Samples\": pred_log}, commit=False)\n\n        # Log losses & metrics\n        # Adapted from fast.ai \"CSVLogger\"\n        logs = {\n            name: stat\n            for name, stat in list(\n                zip(self.learn.recorder.names, [epoch, smooth_loss] +\n                    last_metrics))[1:]\n        }\n        wandb.log(logs)\n\n    def on_train_end(self, **kwargs):\n        \"Load the best model.\"\n\n        if self.save_model:\n            # Adapted from fast.ai \"SaveModelCallback\"\n            if self.model_path.is_file():\n                with self.model_path.open('rb') as model_file:\n                    self.learn.load(model_file, purge=False)\n                    print('Loaded best saved model from {}'.format(\n                        self.model_path))\n", "path": "wandb/fastai/__init__.py"}], "after_files": [{"content": "'''W&B Callback for fast.ai\n\nThis module hooks fast.ai Learners to Weights & Biases through a callback.\nRequested logged data can be configured through the callback constructor.\n\nExamples:\n    WandbCallback can be used when initializing the Learner::\n\n        from wandb.fastai import WandbCallback\n        [...]\n        learn = Learner(data, ..., callback_fns=WandbCallback)\n        learn.fit(epochs)\n    \n    Custom parameters can be given using functools.partial::\n\n        from wandb.fastai import WandbCallback\n        from functools import partial\n        [...]\n        learn = Learner(data, ..., callback_fns=partial(WandbCallback, ...))\n        learn.fit(epochs)\n\n    Finally, it is possible to use WandbCallback only when starting\n    training. In this case it must be instantiated::\n\n        learn.fit(..., callbacks=WandbCallback())\n\n    or, with custom parameters::\n\n        learn.fit(..., callbacks=WandBCallback(learn, ...))\n'''\nimport wandb\nimport fastai\nfrom fastai.callbacks import TrackerCallback\nfrom pathlib import Path\nimport random\ntry:\n    import matplotlib\n    matplotlib.use('Agg')  # non-interactive backend (avoid tkinter issues)\n    import matplotlib.pyplot as plt\nexcept:\n    print('Warning: matplotlib required if logging sample image predictions')\n\n\nclass WandbCallback(TrackerCallback):\n\n    # Record if watch has been called previously (even in another instance)\n    watch_called = False\n\n    def __init__(self,\n                 learn,\n                 log=\"gradients\",\n                 save_model=True,\n                 monitor=None,\n                 mode='auto',\n                 input_type=None,\n                 validation_data=None,\n                 predictions=36):\n        \"\"\"WandB fast.ai Callback\n\n        Automatically saves model topology, losses & metrics.\n        Optionally logs weights, gradients, sample predictions and best trained model.\n\n        Args:\n            learn (fastai.basic_train.Learner): the fast.ai learner to hook.\n            log (str): \"gradients\", \"parameters\", \"all\", or None. Losses & metrics are always logged.\n            save_model (bool): save model at the end of each epoch.\n            monitor (str): metric to monitor for saving best model. None uses default TrackerCallback monitor value.\n            mode (str): \"auto\", \"min\" or \"max\" to compare \"monitor\" values and define best model.\n            input_type (str): \"images\" or None. Used to display sample predictions.\n            validation_data (list): data used for sample predictions if input_type is set.\n            predictions (int): number of predictions to make if input_type is set and validation_data is None.\n        \"\"\"\n\n        # Check if wandb.init has been called\n        if wandb.run is None:\n            raise ValueError(\n                'You must call wandb.init() before WandbCallback()')\n\n        # Adapted from fast.ai \"SaveModelCallback\"\n        if monitor is None:\n            # use default TrackerCallback monitor value\n            super().__init__(learn, mode=mode)\n        else:\n            super().__init__(learn, monitor=monitor, mode=mode)\n        self.save_model = save_model\n        self.model_path = Path(wandb.run.dir) / 'bestmodel.pth'\n\n        self.log = log\n        self.input_type = input_type\n        self.best = None\n\n        # Select items for sample predictions to see evolution along training\n        self.validation_data = validation_data\n        if input_type and not self.validation_data:\n            predictions = min(predictions, len(learn.data.valid_ds))\n            indices = random.sample(range(len(learn.data.valid_ds)),\n                                    predictions)\n            self.validation_data = [learn.data.valid_ds[i] for i in indices]\n\n    def on_train_begin(self, **kwargs):\n        \"Call watch method to log model topology, gradients & weights\"\n\n        # Set self.best, method inherited from \"TrackerCallback\" by \"SaveModelCallback\"\n        super().on_train_begin()\n\n        # Ensure we don't call \"watch\" multiple times\n        if not WandbCallback.watch_called:\n            WandbCallback.watch_called = True\n\n            # Logs model topology and optionally gradients and weights\n            wandb.watch(self.learn.model, log=self.log)\n\n    def on_epoch_end(self, epoch, smooth_loss, last_metrics, **kwargs):\n        \"Logs training loss, validation loss and custom metrics & log prediction samples & save model\"\n\n        if self.save_model:\n            # Adapted from fast.ai \"SaveModelCallback\"\n            current = self.get_monitor_value()\n            if current is not None and self.operator(current, self.best):\n                print(\n                    'Better model found at epoch {} with {} value: {}.'.format(\n                        epoch, self.monitor, current))\n                self.best = current\n\n                # Save within wandb folder\n                with self.model_path.open('wb') as model_file:\n                    self.learn.save(model_file)\n\n        # Log sample predictions\n        if self.validation_data:\n            pred_log = []\n\n            for x, y in self.validation_data:\n                pred = self.learn.predict(x)\n\n                # scalar -> likely to be a category\n                if not pred[1].shape:\n                    pred_log.append(\n                        wandb.Image(\n                            x.data,\n                            caption='Ground Truth: {}\\nPrediction: {}'.format(\n                                y, pred[0])))\n\n                # most vision datasets have a \"show\" function we can use\n                elif hasattr(x, \"show\"):\n                    # log input data\n                    pred_log.append(\n                        wandb.Image(x.data, caption='Input data', grouping=3))\n\n                    # log label and prediction\n                    for im, capt in (y, \"Ground Truth\"), (pred[0],\n                                                          \"Prediction\"):\n                        # Resize plot to image resolution\n                        # from https://stackoverflow.com/a/13714915\n                        my_dpi = 100\n                        fig = plt.figure(frameon=False, dpi=my_dpi)\n                        h, w = x.size\n                        fig.set_size_inches(w / my_dpi, h / my_dpi)\n                        ax = plt.Axes(fig, [0., 0., 1., 1.])\n                        ax.set_axis_off()\n                        fig.add_axes(ax)\n\n                        # Superpose label or prediction to input image\n                        x.show(ax=ax, y=im)\n                        pred_log.append(wandb.Image(fig, caption=capt))\n                        plt.close(fig)\n\n                # likely to be an image\n                elif hasattr(y, \"shape\") and (\n                    (len(y.shape) == 2) or\n                    (len(y.shape) == 3 and y.shape[0] in [1, 3, 4])):\n\n                    pred_log.extend([\n                        wandb.Image(x.data, caption='Input data', grouping=3),\n                        wandb.Image(y.data, caption='Ground Truth'),\n                        wandb.Image(pred[0].data, caption='Prediction')\n                    ])\n\n                # we just log input data\n                else:\n                    pred_log.append(wandb.Image(x.data, caption='Input data'))\n\n            wandb.log({\"Prediction Samples\": pred_log}, commit=False)\n\n        # Log losses & metrics\n        # Adapted from fast.ai \"CSVLogger\"\n        logs = {\n            name: stat\n            for name, stat in list(\n                zip(self.learn.recorder.names, [epoch, smooth_loss] +\n                    last_metrics))[1:]\n        }\n        wandb.log(logs)\n\n    def on_train_end(self, **kwargs):\n        \"Load the best model.\"\n\n        if self.save_model:\n            # Adapted from fast.ai \"SaveModelCallback\"\n            if self.model_path.is_file():\n                with self.model_path.open('rb') as model_file:\n                    self.learn.load(model_file, purge=False)\n                    print('Loaded best saved model from {}'.format(\n                        self.model_path))\n", "path": "wandb/fastai/__init__.py"}]}