We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Make TensorBoardWriter no-op if tensorboard is not available


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `example/mnist.py`
Content:
```
1 import argparse
2 import torch
3 import torch.nn as nn
4 import torch.nn.functional as F
5 import torch.optim as optim
6 from torchvision import datasets, transforms
7 
8 import pytorch_pfn_extras as ppe
9 import pytorch_pfn_extras.training.extensions as extensions
10 
11 
12 class Net(nn.Module):
13     def __init__(self):
14         super().__init__()
15         self.conv1 = nn.Conv2d(1, 20, 5, 1)
16         self.conv2 = nn.Conv2d(20, 50, 5, 1)
17         self.fc1 = nn.Linear(4 * 4 * 50, 500)
18         self.fc2 = nn.Linear(500, 10)
19 
20     def forward(self, x):
21         x = F.relu(self.conv1(x))
22         x = F.max_pool2d(x, 2, 2)
23         x = F.relu(self.conv2(x))
24         x = F.max_pool2d(x, 2, 2)
25         x = x.flatten(start_dim=1)
26         x = F.relu(self.fc1(x))
27         x = self.fc2(x)
28         ppe.nn.ensure(x, shape=(None, 10))
29         return F.log_softmax(x, dim=1)
30 
31 
32 def train(manager, args, model, device, train_loader):
33     while not manager.stop_trigger:
34         model.train()
35         for _, (data, target) in enumerate(train_loader):
36             with manager.run_iteration(step_optimizers=['main']):
37                 data, target = data.to(device), target.to(device)
38                 output = model(data)
39                 loss = F.nll_loss(output, target)
40                 ppe.reporting.report({'train/loss': loss.item()})
41                 loss.backward()
42 
43 
44 def test(args, model, device, data, target):
45     """ The extension loops over the iterator in order to
46         drive the evaluator progress bar and reporting
47         averages
48     """
49     model.eval()
50     data, target = data.to(device), target.to(device)
51     output = model(data)
52     # Final result will be average of averages of the same size
53     test_loss = F.nll_loss(output, target, reduction='mean').item()
54     ppe.reporting.report({'val/loss': test_loss})
55     pred = output.argmax(dim=1, keepdim=True)
56 
57     correct = pred.eq(target.view_as(pred)).sum().item()
58     ppe.reporting.report({'val/acc': correct / len(data)})
59 
60 
61 def main():
62     # Training settings
63     parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
64     parser.add_argument('--batch-size', type=int, default=64, metavar='N',
65                         help='input batch size for training (default: 64)')
66     parser.add_argument('--test-batch-size', type=int, default=1000,
67                         metavar='N',
68                         help='input batch size for testing (default: 1000)')
69     parser.add_argument('--epochs', type=int, default=10, metavar='N',
70                         help='number of epochs to train (default: 10)')
71     parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
72                         help='learning rate (default: 0.01)')
73     parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
74                         help='SGD momentum (default: 0.5)')
75     parser.add_argument('--no-cuda', dest='cuda',
76                         action='store_false', default=True,
77                         help='disables CUDA training')
78     parser.add_argument('--seed', type=int, default=1, metavar='S',
79                         help='random seed (default: 1)')
80     parser.add_argument('--save-model', action='store_true', default=False,
81                         help='For Saving the current Model')
82     parser.add_argument('--snapshot', type=str, default=None,
83                         help='path to snapshot file')
84     args = parser.parse_args()
85     use_cuda = args.cuda and torch.cuda.is_available()
86 
87     torch.manual_seed(args.seed)
88 
89     device = torch.device("cuda" if use_cuda else "cpu")
90 
91     kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
92     train_loader = torch.utils.data.DataLoader(
93         datasets.MNIST('../data', train=True, download=True,
94                        transform=transforms.Compose([
95                            transforms.ToTensor(),
96                            transforms.Normalize((0.1307,), (0.3081,))
97                        ])),
98         batch_size=args.batch_size, shuffle=True,
99         **kwargs)  # type: ignore[arg-type]
100     test_loader = torch.utils.data.DataLoader(
101         datasets.MNIST('../data', train=False, transform=transforms.Compose([
102             transforms.ToTensor(),
103             transforms.Normalize((0.1307,), (0.3081,))
104         ])),
105         batch_size=args.test_batch_size, shuffle=True,
106         **kwargs)  # type: ignore[arg-type]
107 
108     model = Net()
109     model.to(device)
110 
111     optimizer = optim.SGD(
112         model.parameters(), lr=args.lr, momentum=args.momentum)
113 
114     # manager.extend(...) also works
115     my_extensions = [
116         extensions.LogReport(),
117         extensions.ProgressBar(),
118         extensions.observe_lr(optimizer=optimizer),
119         extensions.ParameterStatistics(model, prefix='model'),
120         extensions.VariableStatisticsPlot(model),
121         extensions.Evaluator(
122             test_loader, model,
123             eval_func=lambda data, target:
124                 test(args, model, device, data, target),
125             progress_bar=True),
126         extensions.PlotReport(
127             ['train/loss', 'val/loss'], 'epoch', filename='loss.png'),
128         extensions.PrintReport(['epoch', 'iteration',
129                                 'train/loss', 'lr', 'model/fc2.bias/grad/min',
130                                 'val/loss', 'val/acc']),
131         extensions.snapshot(),
132     ]
133     # Custom stop triggers can be added to the manager and
134     # their status accessed through `manager.stop_trigger`
135     trigger = None
136     # trigger = ppe.training.triggers.EarlyStoppingTrigger(
137     #     check_trigger=(1, 'epoch'), monitor='val/loss')
138     manager = ppe.training.ExtensionsManager(
139         model, optimizer, args.epochs,
140         extensions=my_extensions,
141         iters_per_epoch=len(train_loader),
142         stop_trigger=trigger)
143     # Lets load the snapshot
144     if args.snapshot is not None:
145         state = torch.load(args.snapshot)
146         manager.load_state_dict(state)
147     train(manager, args, model, device, train_loader)
148     # Test function is called from the evaluator extension
149     # to get access to the reporter and other facilities
150     # test(args, model, device, test_loader)
151 
152     if (args.save_model):
153         torch.save(model.state_dict(), "mnist_cnn.pt")
154 
155 
156 if __name__ == '__main__':
157     main()
158
```

Path: `pytorch_pfn_extras/writing/_tensorboard_writer.py`
Content:
```
1 from typing import Any, KeysView, Optional
2 
3 from pytorch_pfn_extras.writing._writer_base import (
4     _TargetType, _SaveFun, _FileSystem
5 )
6 
7 
8 class TensorBoardWriter(object):
9     """ Writer that sends statistics to TensorBoard.
10 
11     This class contains a `torch.utils.tensorboard.SummaryWriter`
12     object that is used to send the collected statistics to TensorBoard.
13     A list of stats can be specified to report only the desired ones.
14 
15     Args:
16         savefun: Ignored.
17         fs: Ignored.
18         out_dir: Passed as ``log_dir`` argument to SummaryWriter.
19         stats (list): List of statistic keys.
20         kwds: Passed as an additional arguments to SummaryWriter.
21     """
22     def __init__(
23             self,
24             savefun: Optional[_SaveFun] = None,
25             fs: _FileSystem = None,
26             out_dir: Optional[str] = None,
27             stats: Optional[KeysView[str]] = None,
28             **kwds: Any
29     ) -> None:
30         from torch.utils.tensorboard import SummaryWriter
31         self._stats = stats
32         self._writer: Optional[SummaryWriter] = (
33             SummaryWriter(  # type: ignore[no-untyped-call]
34                 log_dir=out_dir, **kwds))
35 
36     def __del__(self) -> None:
37         self.finalize()
38 
39     def __call__(
40             self,
41             filename: str,
42             out_dir: str,
43             target: _TargetType,
44             *,
45             savefun: Optional[_SaveFun] = None,
46             append: bool = False,
47     ) -> None:
48         """Sends the statistics to the TensorBoard.
49 
50         Args:
51             filename: Ignored.
52             out_dir: Ignored.
53             target (dict or list): The statistics of the iteration. If given as
54                 a list, only the last element (assumed to be a dict containing
55                 the latest iteration statistics) is reported.
56             savefun: Ignored.
57             append: Ignored.
58         """
59         if self._writer is None:
60             raise RuntimeError('TensorBoardWriter already finalized')
61 
62         stats_cpu = target
63         if isinstance(target, list):
64             stats_cpu = target[-1]
65 
66         if not isinstance(stats_cpu, dict):
67             raise TypeError('target must be dict or list of dicts')
68         keys = stats_cpu.keys()
69         if self._stats is not None:
70             keys = self._stats
71         for key in keys:
72             value = stats_cpu[key]
73             self._writer.add_scalar(  # type: ignore[no-untyped-call]
74                 key, value, stats_cpu['iteration'])
75 
76     def finalize(self) -> None:
77         writer = self._writer
78         if writer is not None:
79             writer.close()  # type: ignore[no-untyped-call]
80         self._writer = None
81
```
--- 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/example/mnist.py b/example/mnist.py
--- a/example/mnist.py
+++ b/example/mnist.py
@@ -114,6 +114,12 @@
     # manager.extend(...) also works
     my_extensions = [
         extensions.LogReport(),
+
+        # Enables TensorBoard support.
+        # Run `tensorboard --logdir runs` to launch the TensorBoard.
+        extensions.LogReport(
+            writer=ppe.writing.TensorBoardWriter(out_dir='runs'),
+            trigger=(1, 'iteration')),
         extensions.ProgressBar(),
         extensions.observe_lr(optimizer=optimizer),
         extensions.ParameterStatistics(model, prefix='model'),
diff --git a/pytorch_pfn_extras/writing/_tensorboard_writer.py b/pytorch_pfn_extras/writing/_tensorboard_writer.py
--- a/pytorch_pfn_extras/writing/_tensorboard_writer.py
+++ b/pytorch_pfn_extras/writing/_tensorboard_writer.py
@@ -1,4 +1,5 @@
 from typing import Any, KeysView, Optional
+import warnings
 
 from pytorch_pfn_extras.writing._writer_base import (
     _TargetType, _SaveFun, _FileSystem
@@ -27,10 +28,17 @@
             stats: Optional[KeysView[str]] = None,
             **kwds: Any
     ) -> None:
-        from torch.utils.tensorboard import SummaryWriter
+        self._writer = None
+        try:
+            import torch.utils.tensorboard
+        except ImportError:
+            warnings.warn(
+                'tensorboard is unavailable. '
+                'TensorBoardWriter will do nothing.')
+            return
         self._stats = stats
-        self._writer: Optional[SummaryWriter] = (
-            SummaryWriter(  # type: ignore[no-untyped-call]
+        self._writer = (
+            torch.utils.tensorboard.SummaryWriter(  # type: ignore[no-untyped-call]
                 log_dir=out_dir, **kwds))
 
     def __del__(self) -> None:
@@ -57,8 +65,7 @@
             append: Ignored.
         """
         if self._writer is None:
-            raise RuntimeError('TensorBoardWriter already finalized')
-
+            return
         stats_cpu = target
         if isinstance(target, list):
             stats_cpu = target[-1]
@@ -74,7 +81,6 @@
                 key, value, stats_cpu['iteration'])
 
     def finalize(self) -> None:
-        writer = self._writer
-        if writer is not None:
-            writer.close()  # type: ignore[no-untyped-call]
-        self._writer = None
+        if self._writer is not None:
+            self._writer.close()  # type: ignore[no-untyped-call]
+            self._writer = None

{"golden_diff": "diff --git a/example/mnist.py b/example/mnist.py\n--- a/example/mnist.py\n+++ b/example/mnist.py\n@@ -114,6 +114,12 @@\n     # manager.extend(...) also works\n     my_extensions = [\n         extensions.LogReport(),\n+\n+        # Enables TensorBoard support.\n+        # Run `tensorboard --logdir runs` to launch the TensorBoard.\n+        extensions.LogReport(\n+            writer=ppe.writing.TensorBoardWriter(out_dir='runs'),\n+            trigger=(1, 'iteration')),\n         extensions.ProgressBar(),\n         extensions.observe_lr(optimizer=optimizer),\n         extensions.ParameterStatistics(model, prefix='model'),\ndiff --git a/pytorch_pfn_extras/writing/_tensorboard_writer.py b/pytorch_pfn_extras/writing/_tensorboard_writer.py\n--- a/pytorch_pfn_extras/writing/_tensorboard_writer.py\n+++ b/pytorch_pfn_extras/writing/_tensorboard_writer.py\n@@ -1,4 +1,5 @@\n from typing import Any, KeysView, Optional\n+import warnings\n \n from pytorch_pfn_extras.writing._writer_base import (\n     _TargetType, _SaveFun, _FileSystem\n@@ -27,10 +28,17 @@\n             stats: Optional[KeysView[str]] = None,\n             **kwds: Any\n     ) -> None:\n-        from torch.utils.tensorboard import SummaryWriter\n+        self._writer = None\n+        try:\n+            import torch.utils.tensorboard\n+        except ImportError:\n+            warnings.warn(\n+                'tensorboard is unavailable. '\n+                'TensorBoardWriter will do nothing.')\n+            return\n         self._stats = stats\n-        self._writer: Optional[SummaryWriter] = (\n-            SummaryWriter(  # type: ignore[no-untyped-call]\n+        self._writer = (\n+            torch.utils.tensorboard.SummaryWriter(  # type: ignore[no-untyped-call]\n                 log_dir=out_dir, **kwds))\n \n     def __del__(self) -> None:\n@@ -57,8 +65,7 @@\n             append: Ignored.\n         \"\"\"\n         if self._writer is None:\n-            raise RuntimeError('TensorBoardWriter already finalized')\n-\n+            return\n         stats_cpu = target\n         if isinstance(target, list):\n             stats_cpu = target[-1]\n@@ -74,7 +81,6 @@\n                 key, value, stats_cpu['iteration'])\n \n     def finalize(self) -> None:\n-        writer = self._writer\n-        if writer is not None:\n-            writer.close()  # type: ignore[no-untyped-call]\n-        self._writer = None\n+        if self._writer is not None:\n+            self._writer.close()  # type: ignore[no-untyped-call]\n+            self._writer = None\n", "issue": "Make TensorBoardWriter no-op if tensorboard is not available\n\n", "before_files": [{"content": "import argparse\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torchvision import datasets, transforms\n\nimport pytorch_pfn_extras as ppe\nimport pytorch_pfn_extras.training.extensions as extensions\n\n\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.conv1 = nn.Conv2d(1, 20, 5, 1)\n        self.conv2 = nn.Conv2d(20, 50, 5, 1)\n        self.fc1 = nn.Linear(4 * 4 * 50, 500)\n        self.fc2 = nn.Linear(500, 10)\n\n    def forward(self, x):\n        x = F.relu(self.conv1(x))\n        x = F.max_pool2d(x, 2, 2)\n        x = F.relu(self.conv2(x))\n        x = F.max_pool2d(x, 2, 2)\n        x = x.flatten(start_dim=1)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        ppe.nn.ensure(x, shape=(None, 10))\n        return F.log_softmax(x, dim=1)\n\n\ndef train(manager, args, model, device, train_loader):\n    while not manager.stop_trigger:\n        model.train()\n        for _, (data, target) in enumerate(train_loader):\n            with manager.run_iteration(step_optimizers=['main']):\n                data, target = data.to(device), target.to(device)\n                output = model(data)\n                loss = F.nll_loss(output, target)\n                ppe.reporting.report({'train/loss': loss.item()})\n                loss.backward()\n\n\ndef test(args, model, device, data, target):\n    \"\"\" The extension loops over the iterator in order to\n        drive the evaluator progress bar and reporting\n        averages\n    \"\"\"\n    model.eval()\n    data, target = data.to(device), target.to(device)\n    output = model(data)\n    # Final result will be average of averages of the same size\n    test_loss = F.nll_loss(output, target, reduction='mean').item()\n    ppe.reporting.report({'val/loss': test_loss})\n    pred = output.argmax(dim=1, keepdim=True)\n\n    correct = pred.eq(target.view_as(pred)).sum().item()\n    ppe.reporting.report({'val/acc': correct / len(data)})\n\n\ndef main():\n    # Training settings\n    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')\n    parser.add_argument('--batch-size', type=int, default=64, metavar='N',\n                        help='input batch size for training (default: 64)')\n    parser.add_argument('--test-batch-size', type=int, default=1000,\n                        metavar='N',\n                        help='input batch size for testing (default: 1000)')\n    parser.add_argument('--epochs', type=int, default=10, metavar='N',\n                        help='number of epochs to train (default: 10)')\n    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',\n                        help='learning rate (default: 0.01)')\n    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',\n                        help='SGD momentum (default: 0.5)')\n    parser.add_argument('--no-cuda', dest='cuda',\n                        action='store_false', default=True,\n                        help='disables CUDA training')\n    parser.add_argument('--seed', type=int, default=1, metavar='S',\n                        help='random seed (default: 1)')\n    parser.add_argument('--save-model', action='store_true', default=False,\n                        help='For Saving the current Model')\n    parser.add_argument('--snapshot', type=str, default=None,\n                        help='path to snapshot file')\n    args = parser.parse_args()\n    use_cuda = args.cuda and torch.cuda.is_available()\n\n    torch.manual_seed(args.seed)\n\n    device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n\n    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}\n    train_loader = torch.utils.data.DataLoader(\n        datasets.MNIST('../data', train=True, download=True,\n                       transform=transforms.Compose([\n                           transforms.ToTensor(),\n                           transforms.Normalize((0.1307,), (0.3081,))\n                       ])),\n        batch_size=args.batch_size, shuffle=True,\n        **kwargs)  # type: ignore[arg-type]\n    test_loader = torch.utils.data.DataLoader(\n        datasets.MNIST('../data', train=False, transform=transforms.Compose([\n            transforms.ToTensor(),\n            transforms.Normalize((0.1307,), (0.3081,))\n        ])),\n        batch_size=args.test_batch_size, shuffle=True,\n        **kwargs)  # type: ignore[arg-type]\n\n    model = Net()\n    model.to(device)\n\n    optimizer = optim.SGD(\n        model.parameters(), lr=args.lr, momentum=args.momentum)\n\n    # manager.extend(...) also works\n    my_extensions = [\n        extensions.LogReport(),\n        extensions.ProgressBar(),\n        extensions.observe_lr(optimizer=optimizer),\n        extensions.ParameterStatistics(model, prefix='model'),\n        extensions.VariableStatisticsPlot(model),\n        extensions.Evaluator(\n            test_loader, model,\n            eval_func=lambda data, target:\n                test(args, model, device, data, target),\n            progress_bar=True),\n        extensions.PlotReport(\n            ['train/loss', 'val/loss'], 'epoch', filename='loss.png'),\n        extensions.PrintReport(['epoch', 'iteration',\n                                'train/loss', 'lr', 'model/fc2.bias/grad/min',\n                                'val/loss', 'val/acc']),\n        extensions.snapshot(),\n    ]\n    # Custom stop triggers can be added to the manager and\n    # their status accessed through `manager.stop_trigger`\n    trigger = None\n    # trigger = ppe.training.triggers.EarlyStoppingTrigger(\n    #     check_trigger=(1, 'epoch'), monitor='val/loss')\n    manager = ppe.training.ExtensionsManager(\n        model, optimizer, args.epochs,\n        extensions=my_extensions,\n        iters_per_epoch=len(train_loader),\n        stop_trigger=trigger)\n    # Lets load the snapshot\n    if args.snapshot is not None:\n        state = torch.load(args.snapshot)\n        manager.load_state_dict(state)\n    train(manager, args, model, device, train_loader)\n    # Test function is called from the evaluator extension\n    # to get access to the reporter and other facilities\n    # test(args, model, device, test_loader)\n\n    if (args.save_model):\n        torch.save(model.state_dict(), \"mnist_cnn.pt\")\n\n\nif __name__ == '__main__':\n    main()\n", "path": "example/mnist.py"}, {"content": "from typing import Any, KeysView, Optional\n\nfrom pytorch_pfn_extras.writing._writer_base import (\n    _TargetType, _SaveFun, _FileSystem\n)\n\n\nclass TensorBoardWriter(object):\n    \"\"\" Writer that sends statistics to TensorBoard.\n\n    This class contains a `torch.utils.tensorboard.SummaryWriter`\n    object that is used to send the collected statistics to TensorBoard.\n    A list of stats can be specified to report only the desired ones.\n\n    Args:\n        savefun: Ignored.\n        fs: Ignored.\n        out_dir: Passed as ``log_dir`` argument to SummaryWriter.\n        stats (list): List of statistic keys.\n        kwds: Passed as an additional arguments to SummaryWriter.\n    \"\"\"\n    def __init__(\n            self,\n            savefun: Optional[_SaveFun] = None,\n            fs: _FileSystem = None,\n            out_dir: Optional[str] = None,\n            stats: Optional[KeysView[str]] = None,\n            **kwds: Any\n    ) -> None:\n        from torch.utils.tensorboard import SummaryWriter\n        self._stats = stats\n        self._writer: Optional[SummaryWriter] = (\n            SummaryWriter(  # type: ignore[no-untyped-call]\n                log_dir=out_dir, **kwds))\n\n    def __del__(self) -> None:\n        self.finalize()\n\n    def __call__(\n            self,\n            filename: str,\n            out_dir: str,\n            target: _TargetType,\n            *,\n            savefun: Optional[_SaveFun] = None,\n            append: bool = False,\n    ) -> None:\n        \"\"\"Sends the statistics to the TensorBoard.\n\n        Args:\n            filename: Ignored.\n            out_dir: Ignored.\n            target (dict or list): The statistics of the iteration. If given as\n                a list, only the last element (assumed to be a dict containing\n                the latest iteration statistics) is reported.\n            savefun: Ignored.\n            append: Ignored.\n        \"\"\"\n        if self._writer is None:\n            raise RuntimeError('TensorBoardWriter already finalized')\n\n        stats_cpu = target\n        if isinstance(target, list):\n            stats_cpu = target[-1]\n\n        if not isinstance(stats_cpu, dict):\n            raise TypeError('target must be dict or list of dicts')\n        keys = stats_cpu.keys()\n        if self._stats is not None:\n            keys = self._stats\n        for key in keys:\n            value = stats_cpu[key]\n            self._writer.add_scalar(  # type: ignore[no-untyped-call]\n                key, value, stats_cpu['iteration'])\n\n    def finalize(self) -> None:\n        writer = self._writer\n        if writer is not None:\n            writer.close()  # type: ignore[no-untyped-call]\n        self._writer = None\n", "path": "pytorch_pfn_extras/writing/_tensorboard_writer.py"}], "after_files": [{"content": "import argparse\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torchvision import datasets, transforms\n\nimport pytorch_pfn_extras as ppe\nimport pytorch_pfn_extras.training.extensions as extensions\n\n\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.conv1 = nn.Conv2d(1, 20, 5, 1)\n        self.conv2 = nn.Conv2d(20, 50, 5, 1)\n        self.fc1 = nn.Linear(4 * 4 * 50, 500)\n        self.fc2 = nn.Linear(500, 10)\n\n    def forward(self, x):\n        x = F.relu(self.conv1(x))\n        x = F.max_pool2d(x, 2, 2)\n        x = F.relu(self.conv2(x))\n        x = F.max_pool2d(x, 2, 2)\n        x = x.flatten(start_dim=1)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        ppe.nn.ensure(x, shape=(None, 10))\n        return F.log_softmax(x, dim=1)\n\n\ndef train(manager, args, model, device, train_loader):\n    while not manager.stop_trigger:\n        model.train()\n        for _, (data, target) in enumerate(train_loader):\n            with manager.run_iteration(step_optimizers=['main']):\n                data, target = data.to(device), target.to(device)\n                output = model(data)\n                loss = F.nll_loss(output, target)\n                ppe.reporting.report({'train/loss': loss.item()})\n                loss.backward()\n\n\ndef test(args, model, device, data, target):\n    \"\"\" The extension loops over the iterator in order to\n        drive the evaluator progress bar and reporting\n        averages\n    \"\"\"\n    model.eval()\n    data, target = data.to(device), target.to(device)\n    output = model(data)\n    # Final result will be average of averages of the same size\n    test_loss = F.nll_loss(output, target, reduction='mean').item()\n    ppe.reporting.report({'val/loss': test_loss})\n    pred = output.argmax(dim=1, keepdim=True)\n\n    correct = pred.eq(target.view_as(pred)).sum().item()\n    ppe.reporting.report({'val/acc': correct / len(data)})\n\n\ndef main():\n    # Training settings\n    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')\n    parser.add_argument('--batch-size', type=int, default=64, metavar='N',\n                        help='input batch size for training (default: 64)')\n    parser.add_argument('--test-batch-size', type=int, default=1000,\n                        metavar='N',\n                        help='input batch size for testing (default: 1000)')\n    parser.add_argument('--epochs', type=int, default=10, metavar='N',\n                        help='number of epochs to train (default: 10)')\n    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',\n                        help='learning rate (default: 0.01)')\n    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',\n                        help='SGD momentum (default: 0.5)')\n    parser.add_argument('--no-cuda', dest='cuda',\n                        action='store_false', default=True,\n                        help='disables CUDA training')\n    parser.add_argument('--seed', type=int, default=1, metavar='S',\n                        help='random seed (default: 1)')\n    parser.add_argument('--save-model', action='store_true', default=False,\n                        help='For Saving the current Model')\n    parser.add_argument('--snapshot', type=str, default=None,\n                        help='path to snapshot file')\n    args = parser.parse_args()\n    use_cuda = args.cuda and torch.cuda.is_available()\n\n    torch.manual_seed(args.seed)\n\n    device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n\n    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}\n    train_loader = torch.utils.data.DataLoader(\n        datasets.MNIST('../data', train=True, download=True,\n                       transform=transforms.Compose([\n                           transforms.ToTensor(),\n                           transforms.Normalize((0.1307,), (0.3081,))\n                       ])),\n        batch_size=args.batch_size, shuffle=True,\n        **kwargs)  # type: ignore[arg-type]\n    test_loader = torch.utils.data.DataLoader(\n        datasets.MNIST('../data', train=False, transform=transforms.Compose([\n            transforms.ToTensor(),\n            transforms.Normalize((0.1307,), (0.3081,))\n        ])),\n        batch_size=args.test_batch_size, shuffle=True,\n        **kwargs)  # type: ignore[arg-type]\n\n    model = Net()\n    model.to(device)\n\n    optimizer = optim.SGD(\n        model.parameters(), lr=args.lr, momentum=args.momentum)\n\n    # manager.extend(...) also works\n    my_extensions = [\n        extensions.LogReport(),\n\n        # Enables TensorBoard support.\n        # Run `tensorboard --logdir runs` to launch the TensorBoard.\n        extensions.LogReport(\n            writer=ppe.writing.TensorBoardWriter(out_dir='runs'),\n            trigger=(1, 'iteration')),\n        extensions.ProgressBar(),\n        extensions.observe_lr(optimizer=optimizer),\n        extensions.ParameterStatistics(model, prefix='model'),\n        extensions.VariableStatisticsPlot(model),\n        extensions.Evaluator(\n            test_loader, model,\n            eval_func=lambda data, target:\n                test(args, model, device, data, target),\n            progress_bar=True),\n        extensions.PlotReport(\n            ['train/loss', 'val/loss'], 'epoch', filename='loss.png'),\n        extensions.PrintReport(['epoch', 'iteration',\n                                'train/loss', 'lr', 'model/fc2.bias/grad/min',\n                                'val/loss', 'val/acc']),\n        extensions.snapshot(),\n    ]\n    # Custom stop triggers can be added to the manager and\n    # their status accessed through `manager.stop_trigger`\n    trigger = None\n    # trigger = ppe.training.triggers.EarlyStoppingTrigger(\n    #     check_trigger=(1, 'epoch'), monitor='val/loss')\n    manager = ppe.training.ExtensionsManager(\n        model, optimizer, args.epochs,\n        extensions=my_extensions,\n        iters_per_epoch=len(train_loader),\n        stop_trigger=trigger)\n    # Lets load the snapshot\n    if args.snapshot is not None:\n        state = torch.load(args.snapshot)\n        manager.load_state_dict(state)\n    train(manager, args, model, device, train_loader)\n    # Test function is called from the evaluator extension\n    # to get access to the reporter and other facilities\n    # test(args, model, device, test_loader)\n\n    if (args.save_model):\n        torch.save(model.state_dict(), \"mnist_cnn.pt\")\n\n\nif __name__ == '__main__':\n    main()\n", "path": "example/mnist.py"}, {"content": "from typing import Any, KeysView, Optional\nimport warnings\n\nfrom pytorch_pfn_extras.writing._writer_base import (\n    _TargetType, _SaveFun, _FileSystem\n)\n\n\nclass TensorBoardWriter(object):\n    \"\"\" Writer that sends statistics to TensorBoard.\n\n    This class contains a `torch.utils.tensorboard.SummaryWriter`\n    object that is used to send the collected statistics to TensorBoard.\n    A list of stats can be specified to report only the desired ones.\n\n    Args:\n        savefun: Ignored.\n        fs: Ignored.\n        out_dir: Passed as ``log_dir`` argument to SummaryWriter.\n        stats (list): List of statistic keys.\n        kwds: Passed as an additional arguments to SummaryWriter.\n    \"\"\"\n    def __init__(\n            self,\n            savefun: Optional[_SaveFun] = None,\n            fs: _FileSystem = None,\n            out_dir: Optional[str] = None,\n            stats: Optional[KeysView[str]] = None,\n            **kwds: Any\n    ) -> None:\n        self._writer = None\n        try:\n            import torch.utils.tensorboard\n        except ImportError:\n            warnings.warn(\n                'tensorboard is unavailable. '\n                'TensorBoardWriter will do nothing.')\n            return\n        self._stats = stats\n        self._writer = (\n            torch.utils.tensorboard.SummaryWriter(  # type: ignore[no-untyped-call]\n                log_dir=out_dir, **kwds))\n\n    def __del__(self) -> None:\n        self.finalize()\n\n    def __call__(\n            self,\n            filename: str,\n            out_dir: str,\n            target: _TargetType,\n            *,\n            savefun: Optional[_SaveFun] = None,\n            append: bool = False,\n    ) -> None:\n        \"\"\"Sends the statistics to the TensorBoard.\n\n        Args:\n            filename: Ignored.\n            out_dir: Ignored.\n            target (dict or list): The statistics of the iteration. If given as\n                a list, only the last element (assumed to be a dict containing\n                the latest iteration statistics) is reported.\n            savefun: Ignored.\n            append: Ignored.\n        \"\"\"\n        if self._writer is None:\n            return\n        stats_cpu = target\n        if isinstance(target, list):\n            stats_cpu = target[-1]\n\n        if not isinstance(stats_cpu, dict):\n            raise TypeError('target must be dict or list of dicts')\n        keys = stats_cpu.keys()\n        if self._stats is not None:\n            keys = self._stats\n        for key in keys:\n            value = stats_cpu[key]\n            self._writer.add_scalar(  # type: ignore[no-untyped-call]\n                key, value, stats_cpu['iteration'])\n\n    def finalize(self) -> None:\n        if self._writer is not None:\n            self._writer.close()  # type: ignore[no-untyped-call]\n            self._writer = None\n", "path": "pytorch_pfn_extras/writing/_tensorboard_writer.py"}]}