0
# Multi-Backend Visualization
1
2
Multi-backend visualization class supporting both TensorBoard and Visdom simultaneously. Enables cross-platform experiment monitoring and visualization comparison by proxying all SummaryWriter methods to multiple registered backends.
3
4
## Capabilities
5
6
### Initialization
7
8
Creates a TorchVis instance that can register multiple visualization backends and proxy method calls to all of them.
9
10
```python { .api }
11
class TorchVis:
12
def __init__(self, *args, **init_kwargs):
13
"""
14
Creates a TorchVis multi-backend visualization wrapper.
15
16
Parameters:
17
- *args: Variable arguments passed to registered backends
18
- **init_kwargs: Keyword arguments passed to registered backends
19
"""
20
```
21
22
### Backend Management
23
24
Register and unregister visualization backends for simultaneous logging to multiple platforms.
25
26
```python { .api }
27
def register(self, *args, **init_kwargs):
28
"""
29
Register visualization backends.
30
31
Parameters:
32
- *args: Backend classes or instances to register
33
- **init_kwargs: Initialization keyword arguments for backends
34
"""
35
36
def unregister(self, *args):
37
"""
38
Unregister previously registered backends.
39
40
Parameters:
41
- *args: Backend classes or instances to unregister
42
"""
43
```
44
45
### Dynamic Method Proxying
46
47
All SummaryWriter methods are dynamically available and proxied to all registered backends. This includes all logging methods like `add_scalar`, `add_image`, `add_histogram`, etc.
48
49
```python { .api }
50
# All SummaryWriter methods are available through dynamic proxying:
51
# add_scalar, add_scalars, add_image, add_images, add_histogram,
52
# add_figure, add_video, add_audio, add_text, add_graph,
53
# add_embedding, add_pr_curve, add_mesh, add_hparams,
54
# flush, close, etc.
55
```
56
57
## Usage Examples
58
59
### Dual TensorBoard and Visdom Logging
60
61
```python
62
from tensorboardX import TorchVis, SummaryWriter
63
import numpy as np
64
65
# Import visdom for second backend
66
try:
67
import visdom
68
visdom_available = True
69
except ImportError:
70
visdom_available = False
71
72
# Create TorchVis with multiple backends
73
if visdom_available:
74
vis = TorchVis()
75
76
# Register TensorBoard backend
77
tensorboard_writer = SummaryWriter('logs/tensorboard')
78
vis.register(tensorboard_writer)
79
80
# Register Visdom backend
81
visdom_vis = visdom.Visdom()
82
vis.register(visdom_vis)
83
84
# Now all method calls go to both backends
85
for step in range(100):
86
loss = np.random.random()
87
accuracy = np.random.random()
88
89
# This logs to both TensorBoard and Visdom
90
vis.add_scalar('Loss', loss, step)
91
vis.add_scalar('Accuracy', accuracy, step)
92
93
# Images also go to both
94
if step % 10 == 0:
95
image = np.random.rand(3, 64, 64)
96
vis.add_image('Sample', image, step)
97
98
# Close all backends
99
vis.close()
100
else:
101
print("Visdom not available, using TensorBoard only")
102
vis = TorchVis()
103
vis.register(SummaryWriter('logs/tensorboard_only'))
104
```
105
106
### Custom Backend Registration
107
108
```python
109
from tensorboardX import TorchVis, SummaryWriter
110
111
class CustomLogger:
112
"""Custom logging backend example."""
113
114
def __init__(self, log_file):
115
self.log_file = log_file
116
self.file = open(log_file, 'w')
117
118
def add_scalar(self, tag, scalar_value, global_step=None, walltime=None):
119
self.file.write(f"SCALAR: {tag} = {scalar_value} at step {global_step}\n")
120
self.file.flush()
121
122
def add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):
123
self.file.write(f"IMAGE: {tag} shape={img_tensor.shape} at step {global_step}\n")
124
self.file.flush()
125
126
def close(self):
127
self.file.close()
128
129
# Create multi-backend visualization
130
vis = TorchVis()
131
132
# Register multiple backends
133
vis.register(SummaryWriter('logs/tensorboard')) # TensorBoard
134
vis.register(CustomLogger('logs/custom.log')) # Custom logger
135
136
# Log to all backends simultaneously
137
for i in range(10):
138
vis.add_scalar('metric', i * 0.1, i)
139
140
if i % 5 == 0:
141
image = np.random.rand(3, 32, 32)
142
vis.add_image('sample', image, i)
143
144
vis.close()
145
```
146
147
### Dynamic Backend Management
148
149
```python
150
from tensorboardX import TorchVis, SummaryWriter
151
import numpy as np
152
153
vis = TorchVis()
154
155
# Start with one backend
156
tb_writer = SummaryWriter('logs/primary')
157
vis.register(tb_writer)
158
159
# Log some data
160
for i in range(20):
161
vis.add_scalar('Phase1/Loss', np.random.random(), i)
162
163
# Add another backend mid-experiment
164
secondary_writer = SummaryWriter('logs/secondary')
165
vis.register(secondary_writer)
166
167
# Now logs go to both backends
168
for i in range(20, 40):
169
vis.add_scalar('Phase2/Loss', np.random.random(), i)
170
171
# Remove one backend
172
vis.unregister(tb_writer)
173
174
# Now only logs to secondary backend
175
for i in range(40, 60):
176
vis.add_scalar('Phase3/Loss', np.random.random(), i)
177
178
vis.close()
179
```
180
181
### Conditional Backend Registration
182
183
```python
184
from tensorboardX import TorchVis, SummaryWriter
185
import os
186
187
def create_multi_backend_logger(config):
188
"""Create logger based on configuration."""
189
vis = TorchVis()
190
191
# Always register TensorBoard
192
tb_writer = SummaryWriter(config['tensorboard_logdir'])
193
vis.register(tb_writer)
194
195
# Conditionally register Visdom
196
if config.get('use_visdom', False):
197
try:
198
import visdom
199
visdom_vis = visdom.Visdom(
200
server=config.get('visdom_server', 'localhost'),
201
port=config.get('visdom_port', 8097)
202
)
203
vis.register(visdom_vis)
204
print("Registered Visdom backend")
205
except ImportError:
206
print("Visdom not available, skipping")
207
208
# Conditionally register file logger
209
if config.get('use_file_logging', False):
210
file_logger = CustomFileLogger(config['log_file'])
211
vis.register(file_logger)
212
print("Registered file logging backend")
213
214
return vis
215
216
# Configuration-driven backend setup
217
config = {
218
'tensorboard_logdir': 'logs/experiment',
219
'use_visdom': True,
220
'use_file_logging': True,
221
'log_file': 'experiment.log',
222
'visdom_server': 'localhost',
223
'visdom_port': 8097
224
}
225
226
logger = create_multi_backend_logger(config)
227
228
# Log to all configured backends
229
for epoch in range(100):
230
loss = train_one_epoch()
231
accuracy = validate_model()
232
233
logger.add_scalar('Loss', loss, epoch)
234
logger.add_scalar('Accuracy', accuracy, epoch)
235
236
logger.close()
237
```
238
239
## Backend Requirements
240
241
For backends to work with TorchVis, they should implement the same method signatures as SummaryWriter:
242
243
### Required Methods
244
- `add_scalar(tag, scalar_value, global_step=None, walltime=None)`
245
- `add_image(tag, img_tensor, global_step=None, walltime=None, dataformats='CHW')`
246
- `close()`
247
248
### Optional Methods
249
- `add_histogram`, `add_figure`, `add_video`, `add_audio`, `add_text`
250
- `add_graph`, `add_embedding`, `add_pr_curve`, `add_mesh`
251
- `flush()`, any other SummaryWriter methods
252
253
### Error Handling
254
255
TorchVis gracefully handles backend failures:
256
257
```python
258
from tensorboardX import TorchVis, SummaryWriter
259
260
class FailingBackend:
261
def add_scalar(self, *args, **kwargs):
262
raise Exception("Backend failed!")
263
264
def close(self):
265
pass
266
267
vis = TorchVis()
268
vis.register(SummaryWriter('logs/good'))
269
vis.register(FailingBackend())
270
271
# TorchVis continues working even if one backend fails
272
vis.add_scalar('metric', 1.0, 0) # Good backend receives data
273
vis.close()
274
```
275
276
## Performance Considerations
277
278
- **Method Calls**: Each method call is proxied to all registered backends
279
- **Memory Usage**: Data is passed to each backend (not copied by default)
280
- **Network Latency**: Remote backends (like Visdom servers) may introduce delays
281
- **Error Propagation**: Backend failures don't stop other backends from receiving data
282
283
## Integration Patterns
284
285
### Experiment Tracking
286
287
```python
288
# Compare local vs remote visualization
289
vis = TorchVis()
290
vis.register(SummaryWriter('logs/local')) # Local TensorBoard
291
vis.register(RemoteLogger('https://api.wandb.ai')) # Remote tracking service
292
293
# Both receive the same data
294
vis.add_scalar('loss', loss_value, step)
295
```
296
297
### A/B Testing Visualization
298
299
```python
300
# Log to different TensorBoard instances for comparison
301
vis = TorchVis()
302
vis.register(SummaryWriter('logs/experiment_A'))
303
vis.register(SummaryWriter('logs/experiment_B'))
304
305
# Same data logged to both experiments for comparison
306
vis.add_scalar('metric', value, step)
307
```