or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

file-writer.mdglobal-writer.mdindex.mdrecord-writer.mdsummary-writer.mdtorchvis.mdutilities.md

torchvis.mddocs/

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

```