def draw_visdom(model): viz = Visdom() for i, (name, param) in enumerate(model.named_parameters()): if "autoregressive" in name: A = generate_A(param) viz.histogram(torch.flatten(A), opts=dict(title=name, numbins=10))
class Inspector(object): """ Class for inspecting the internals of neural networks """ def __init__(self, model, stats): """ Args: model (torch.nn.Module): the PyTorch model stats (list): list of stats names. e.g. ["std", "mean"] """ # watch only trainable layers self.watched_layers = {} for name, module in self.get_watched_modules(model): self.watched_layers[name] = {stat: [] for stat in stats} self.viz = Visdom() self.update_state(model) def get_watched_modules(self, model): all_modules = [] for name, module in model.named_modules(): if len(list(module.parameters())) > 0 and all( param.requires_grad for param in module.parameters()): all_modules.append((name, module)) # filter parent nodes fitered_modules = [] for name, module in all_modules: if not any([(name in n and name is not n) for n, m in all_modules]): fitered_modules.append((name, module)) return fitered_modules def plot_layer(self, name, weights): self.viz.histogram(X=weights, win=name, opts=dict(title="{} weights dist".format(name), numbins=40)) for stat_name, stat_val in self.watched_layers[name].items(): stat_val.append(getattr(numpy, stat_name)(weights)) plot_name = "{}-{}".format(name, stat_name) plot_line(self.viz, numpy.array(stat_val), plot_name, [plot_name]) def update_state(self, model): gen = (child for child in model.named_modules() if child[0] in self.watched_layers) for name, layer in gen: weights = [ param.data.cpu().numpy() for param in layer.parameters() ] if len(weights) > 0: weights = numpy.concatenate([w.ravel() for w in weights]) self.plot_layer(name, weights)
class VisdomLinePlotter(object): """Plots to Visdom""" def __init__(self, env_name='main'): self.viz = Visdom(server="http://192.168.12.63", port=8097) self.env = env_name self.plots = {} def plot(self, var_name, split_name, title_name, x, y): if var_name not in self.plots: self.plots[var_name] = self.viz.line(X=np.array([x, x]), Y=np.array([y, y]), env=self.env, opts=dict(legend=[split_name], title=title_name, xlabel='Time Step', ylabel=var_name)) else: self.viz.line(X=np.array([x]), Y=np.array([y]), env=self.env, win=self.plots[var_name], name=split_name, update='append') def plot_histogram(self, var_name, split_name, title_name, x): if var_name not in self.plots: self.plots[var_name] = self.viz.histogram( X=x, env=self.env, opts=dict(title=title_name, xlabel='Particle Preferred Distance', ylabel=var_name, numbins=30))
class VisdomWriter: def __init__(self): try: from visdom import Visdom except ImportError: raise ImportError("Visdom visualization requires installation of Visdom") self.scalar_dict = {} self.server_connected = False self.vis = Visdom() self.windows = {} self._try_connect() def _try_connect(self): startup_sec = 1 self.server_connected = self.vis.check_connection() while not self.server_connected and startup_sec > 0: time.sleep(0.1) startup_sec -= 0.1 self.server_connected = self.vis.check_connection() assert self.server_connected, 'No connection could be formed quickly' @_check_connection def add_scalar(self, tag, scalar_value, global_step=None, main_tag='default'): """Add scalar data to Visdom. Plots the values in a plot titled {main_tag}-{tag}. Args: tag (string): Data identifier scalar_value (float or string/blobname): Value to save global_step (int): Global step value to record main_tag (string): Data group identifier """ if self.scalar_dict.get(main_tag) is None: self.scalar_dict[main_tag] = {} exists = self.scalar_dict[main_tag].get(tag) is not None self.scalar_dict[main_tag][tag] = self.scalar_dict[main_tag][tag] + [scalar_value] if exists else [scalar_value] plot_name = '{}-{}'.format(main_tag, tag) # If there is no global_step provided, follow sequential order x_val = len(self.scalar_dict[main_tag][tag]) if not global_step else global_step if exists: # Update our existing Visdom window self.vis.line( X=make_np(x_val), Y=make_np(scalar_value), name=plot_name, update='append', win=self.windows[plot_name], ) else: # Save the window if we are creating this graph for the first time self.windows[plot_name] = self.vis.line( X=make_np(x_val), Y=make_np(scalar_value), name=plot_name, opts={ 'title': plot_name, 'xlabel': 'timestep', 'ylabel': tag, }, ) @_check_connection def add_scalars(self, main_tag, tag_scalar_dict, global_step=None): """Adds many scalar data to summary. Note that this function also keeps logged scalars in memory. In extreme case it explodes your RAM. Args: tag (string): Data identifier main_tag (string): Data group identifier tag_scalar_dict (dict): Key-value pair storing the tag and corresponding values global_step (int): Global step value to record Examples:: writer.add_scalars('run_14h',{'xsinx':i*np.sin(i/r), 'xcosx':i*np.cos(i/r), 'arctanx': numsteps*np.arctan(i/r)}, i) This function adds three plots: 'run_14h-xsinx', 'run_14h-xcosx', 'run_14h-arctanx' with the corresponding values. """ for key in tag_scalar_dict.keys(): self.add_scalar(key, tag_scalar_dict[key], global_step, main_tag) @_check_connection def export_scalars_to_json(self, path): """Exports to the given 'path' an ASCII file containing all the scalars written so far by this instance, with the following format: {writer_id : [[timestamp, step, value], ...], ...} The scalars saved by ``add_scalars()`` will be flushed after export. """ with open(path, "w") as f: json.dump(self.scalar_dict, f) self.scalar_dict = {} @_check_connection def add_histogram(self, tag, values, global_step=None, bins='tensorflow'): """Add histogram to summary. Args: tag (string): Data identifier values (torch.Tensor, numpy.array, or string/blobname): Values to build histogram global_step (int): Global step value to record bins (string): one of {'tensorflow', 'auto', 'fd', ...}, this determines how the bins are made. You can find other options in: https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html """ values = make_np(values) self.vis.histogram(make_np(values), opts={'title': tag}) @_check_connection def add_image(self, tag, img_tensor, global_step=None, caption=None): """Add image data to summary. Note that this requires the ``pillow`` package. Args: tag (string): Data identifier img_tensor (torch.Tensor, numpy.array, or string/blobname): Image data global_step (int): Global step value to record Shape: img_tensor: :math:`(C, H, W)`. Use ``torchvision.utils.make_grid()`` to prepare it is a good idea. C = colors (can be 1 - grayscale, 3 - RGB, 4 - RGBA) """ img_tensor = make_np(img_tensor) self.vis.image(img_tensor, opts={'title': tag, 'caption': caption}) @_check_connection def add_figure(self, tag, figure, global_step=None, close=True): """Render matplotlib figure into an image and add it to summary. Note that this requires the ``matplotlib`` package. Args: tag (string): Data identifier figure (matplotlib.pyplot.figure) or list of figures: figure or a list of figures global_step (int): Global step value to record close (bool): Flag to automatically close the figure """ self.add_image(tag, figure_to_image(figure, close), global_step) @_check_connection def add_video(self, tag, vid_tensor, global_step=None, fps=4): """Add video data to summary. Note that this requires the ``moviepy`` package. Args: tag (string): Data identifier vid_tensor (torch.Tensor): Video data global_step (int): Global step value to record fps (float or int): Frames per second Shape: vid_tensor: :math:`(B, C, T, H, W)`. (if following tensorboard-pytorch format) vid_tensor: :math:`(T, H, W, C)`. (if following visdom format) B = batches, C = colors (1, 3, or 4), T = time frames, H = height, W = width """ shape = vid_tensor.shape # A batch of videos (tensorboard-pytorch format) is a 5D tensor if len(shape) > 4: for i in range(shape[0]): # Reshape each video to Visdom's (T x H x W x C) and write each video if isinstance(vid_tensor, np.ndarray): ind_vid = torch.from_numpy(vid_tensor[i, :, :, :, :]).permute(1, 2, 3, 0) else: ind_vid = vid_tensor[i, :, :, :, :].permute(1, 2, 3, 0) scale_factor = 255 if np.any((ind_vid > 0) & (ind_vid < 1)) else 1 # Visdom looks for .ndim attr, this is something raw Tensors don't have # Cast to Numpy array to get .ndim attr ind_vid = ind_vid.numpy() ind_vid = (ind_vid * scale_factor).astype(np.uint8) assert ind_vid.shape[3] in [1, 3, 4], \ 'Visdom requires the last dimension to be color, which can be 1 (grayscale), 3 (RGB) or 4 (RGBA)' self.vis.video(tensor=ind_vid, opts={'fps': fps}) else: self.vis.video(tensor=vid_tensor, opts={'fps': fps}) @_check_connection def add_audio(self, tag, snd_tensor, global_step=None, sample_rate=44100): """Add audio data to summary. Args: tag (string): Data identifier snd_tensor (torch.Tensor, numpy.array, or string/blobname): Sound data global_step (int): Global step value to record sample_rate (int): sample rate in Hz Shape: snd_tensor: :math:`(1, L)`. The values should lie between [-1, 1]. """ snd_tensor = make_np(snd_tensor) self.vis.audio(tensor=snd_tensor, opts={'sample_frequency': sample_rate}) @_check_connection def add_text(self, tag, text_string, global_step=None): """Add text data to summary. Args: tag (string): Data identifier text_string (string): String to save global_step (int): Global step value to record Examples:: writer.add_text('lstm', 'This is an lstm', 0) writer.add_text('rnn', 'This is an rnn', 10) """ if text_string is None: # Visdom doesn't support tags, write the tag as the text_string text_string = tag self.vis.text(text_string) @_check_connection def add_graph_onnx(self, prototxt): # TODO: Visdom doesn't support graph visualization yet, so this is a no-op return @_check_connection def add_graph(self, model, input_to_model=None, verbose=False, **kwargs): # TODO: Visdom doesn't support graph visualization yet, so this is a no-op return @_check_connection def add_embedding(self, mat, metadata=None, label_img=None, global_step=None, tag='default', metadata_header=None): # TODO: Visdom doesn't support embeddings yet, so this is a no-op return @_check_connection def add_pr_curve(self, tag, labels, predictions, global_step=None, num_thresholds=127, weights=None): """Adds precision recall curve. Args: tag (string): Data identifier labels (torch.Tensor, numpy.array, or string/blobname): Ground truth data. Binary label for each element. predictions (torch.Tensor, numpy.array, or string/blobname): The probability that an element be classified as true. Value should in [0, 1] global_step (int): Global step value to record num_thresholds (int): Number of thresholds used to draw the curve. """ labels, predictions = make_np(labels), make_np(predictions) raw_data = compute_curve(labels, predictions, num_thresholds, weights) # compute_curve returns np.stack((tp, fp, tn, fn, precision, recall)) # We want to access 'precision' and 'recall' precision, recall = raw_data[4, :], raw_data[5, :] self.vis.line( X=recall, Y=precision, name=tag, opts={ 'title': 'PR Curve for {}'.format(tag), 'xlabel': 'recall', 'ylabel': 'precision', }, ) @_check_connection def add_pr_curve_raw(self, tag, true_positive_counts, false_positive_counts, true_negative_counts, false_negative_counts, precision, recall, global_step=None, num_thresholds=127, weights=None): """Adds precision recall curve with raw data. Args: tag (string): Data identifier true_positive_counts (torch.Tensor, numpy.array, or string/blobname): true positive counts false_positive_counts (torch.Tensor, numpy.array, or string/blobname): false positive counts true_negative_counts (torch.Tensor, numpy.array, or string/blobname): true negative counts false_negative_counts (torch.Tensor, numpy.array, or string/blobname): false negative counts precision (torch.Tensor, numpy.array, or string/blobname): precision recall (torch.Tensor, numpy.array, or string/blobname): recall global_step (int): Global step value to record num_thresholds (int): Number of thresholds used to draw the curve. see: https://github.com/tensorflow/tensorboard/blob/master/tensorboard/plugins/pr_curve/README.md """ precision, recall = make_np(precision), make_np(recall) self.vis.line( X=recall, Y=precision, name=tag, opts={ 'title': 'PR Curve for {}'.format(tag), 'xlabel': 'recall', 'ylabel': 'precision', }, ) def close(self): del self.vis del self.scalar_dict gc.collect()
opts=dict(legend=['A', 'B', 'C'], textlabels=['Label %d' % (i + 1) for i in range(10)])) # bar plots viz.bar(X=np.random.rand(20)) viz.bar(X=np.abs(np.random.rand(5, 3)), opts=dict(stacked=True, legend=['Facebook', 'Google', 'Twitter'], rownames=['2012', '2013', '2014', '2015', '2016'])) viz.bar(X=np.random.rand(20, 3), opts=dict(stacked=False, legend=['The Netherlands', 'France', 'United States'])) # histogram viz.histogram(X=np.random.rand(10000), opts=dict(numbins=20)) # heatmap viz.heatmap( X=np.outer(np.arange(1, 6), np.arange(1, 11)), opts=dict( columnnames=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], rownames=['y1', 'y2', 'y3', 'y4', 'y5'], colormap='Electric', )) # contour x = np.tile(np.arange(1, 101), (100, 1)) y = x.transpose() X = np.exp((((x - 50)**2) + ((y - 50)**2)) / -(20.0**2)) viz.contour(X=X, opts=dict(colormap='Viridis'))
class VisdomPlotter(): """Plots to Visdom""" def __init__(self, env_name='TellDrawRepeat', server='http://localhost'): """Visdom instance constuctor Args: - env_name: name of the environment (str) - server: endpoint (url) """ self.viz = Visdom(server=server) self.env = env_name self.plots = {} self.real_aggregate = [] self.fake_aggregate = [] self.sigma_aggregate = [] def plot(self, var_name, split_name, x, y, xlabel='iteration'): """Plots a line Args: - var_name: plot name (str) - split_name: split name (str) - x: x_axis values [e.g, epoch/iteration] (float) - y: y_axis values (float) - xlabel: label of the x_axis (str) """ if var_name not in self.plots: self.plots[var_name] = self.viz.line(X=np.array([x, x]), Y=np.array([y, y]), env=self.env, win=var_name, opts=dict(legend=[split_name], title=var_name, xlabel=xlabel, ylabel=var_name)) else: self.viz.line(X=np.array([x]), Y=np.array([y]), env=self.env, win=var_name, name=split_name, update='append') def draw(self, var_name, images, nrow=8): """Shows a grid of images Args: - var_name: plot title (str) - images: np.array of images (np.array) - nrow: number of images per row (integer) """ images = images[:16] * 127.5 + 127.5 if var_name not in self.plots: self.plots[var_name] = self.viz.images(images, env=self.env, nrow=nrow) else: self.viz.images(images, env=self.env, win=self.plots[var_name], nrow=nrow, opts=dict(caption=var_name)) def histogram(self): """Draws a hsitogram of D(x) and D(G(z)) Takes no arguments, it uses the values saved using self.track """ self._histogram('D(x)', np.array(self.real_aggregate)) self._histogram('D(G(z))', np.array(self.fake_aggregate)) self.fake_aggregate = [] self.real_aggregate = [] if len(self.sigma_aggregate) > 0: self._histogram('Sigma Gate', np.array(self.sigma_aggregate)) self.sigma_aggregate = [] def track(self, real, fake): """Aggregates values of D(x) and D(G(z)) over all the iterations. Values will be used to draw a histogram using self.histogram() Args: - real: tensor of D(x) (torch.FloatTensor) - fake: tensor of D(G(z)) (torch.FloatTensor) """ self.real_aggregate.extend(real) self.fake_aggregate.extend(fake) def track_sigma(self, sigma): """Aggregates the values of sigma, the gating vector of the genrertor """ if sigma is None: return sigma = sigma.mean(dim=1).data.cpu().numpy() self.sigma_aggregate.extend(sigma) def _histogram(self, var_name, data): if var_name not in self.plots: self.plots[var_name] = self.viz.histogram(X=data, env=self.env, opts=dict( numbins=20, title=var_name)) else: self.viz.histogram(X=data, env=self.env, win=self.plots[var_name], opts=dict(numbins=20, title=var_name)) def write(self, text, var_name='dialog'): """Shows Text in HTML format Args: - text: list of sentences (list) -var_name: plost title (str) """ text = [t.replace('<', '#') for t in text] text = [t.replace('>', '#') for t in text] text = str.join('<ol/ ><br/ ><ol>', text[:32]) if var_name not in self.plots: self.plots[var_name] = self.viz.text(text) else: self.viz.text(text, env=self.env, win=self.plots[var_name])
from torch.utils.data import DataLoader from datasets import YelpReviewsOneHotChars import numpy as np import settings from visdom import Visdom import copy # Instansiate dataset dataset = YelpReviewsOneHotChars(settings.DATAFILE) data_loader = DataLoader(dataset, batch_size=1, shuffle=True, num_workers=4) # Create visdom instance viz = Visdom() labels = np.zeros([4, len(dataset)]) for i, (feature, target) in enumerate(data_loader): labels[:, i] = target[0] print(labels) opts = copy.deepcopy(settings.HIST_OPTS) opts["title"] = "Real star distribution" viz.histogram(X=labels[0], opts=opts)
class VisdomLogger(Logger): """Logs attack results to Visdom.""" def __init__(self, env="main", port=8097, hostname="localhost"): if not port_is_open(port, hostname=hostname): raise socket.error(f"Visdom not running on {hostname}:{port}") self.vis = Visdom(port=port, server=hostname, env=env) self.env = env self.port = port self.hostname = hostname self.windows = {} self.sample_rows = [] def __getstate__(self): state = {i: self.__dict__[i] for i in self.__dict__ if i != "vis"} return state def __setstate__(self, state): self.__dict__ = state self.vis = Visdom(port=self.port, server=self.hostname, env=self.env) def log_attack_result(self, result): text_a, text_b = result.diff_color(color_method="html") result_str = result.goal_function_result_str(color_method="html") self.sample_rows.append([result_str, text_a, text_b]) def log_summary_rows(self, rows, title, window_id): self.table(rows, title=title, window_id=window_id) def flush(self): self.table( self.sample_rows, title="Sample-Level Results", window_id="sample_level_results", ) def log_hist(self, arr, numbins, title, window_id): self.bar(arr, numbins=numbins, title=title, window_id=window_id) def text(self, text_data, title=None, window_id="default"): if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.text(text_data, win=window) else: new_window = self.vis.text(text_data, opts=dict(title=title)) self.windows[window_id] = new_window def table(self, rows, window_id=None, title=None, header=None, style=None): """Generates an HTML table.""" if not window_id: window_id = title # Can provide either of these, if not title: title = window_id # or both. table = html_table_from_rows(rows, title=title, header=header, style_dict=style) self.text(table, title=title, window_id=window_id) def bar(self, X_data, numbins=10, title=None, window_id=None): window = None if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.bar(X=X_data, win=window, opts=dict(title=title, numbins=numbins)) else: new_window = self.vis.bar(X=X_data, opts=dict(title=title, numbins=numbins)) if window_id: self.windows[window_id] = new_window def hist(self, X_data, numbins=10, title=None, window_id=None): window = None if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.histogram(X=X_data, win=window, opts=dict(title=title, numbins=numbins)) else: new_window = self.vis.histogram(X=X_data, opts=dict(title=title, numbins=numbins)) if window_id: self.windows[window_id] = new_window
while True: clustering.start_epoch((len(ds) // 128) // 4, equalize_weights=True) clustering.save('labeller_{}.pth'.format(iters)) for _ in range(5000): opt.zero_grad() loss, x_cpu, pred, y = clustering.batch() loss.backward() norm = torch.nn.utils.clip_grad_norm_(model.parameters(), 5) opt.step() if iters % 20 == 0: pred_cls = pred.argmax(dim=1).cpu() viz.line(X=[iters], Y=[loss.item()], update='append', win='r_loss', opts=dict(title='Loss')) viz.histogram(pred_cls.cpu(), win='per class', opts=dict(title='per class')) viz.histogram(y, win='per class truth', opts=dict(title='per class truth')) for k in range(K): k_aff = x_cpu[pred_cls == k] if k_aff.shape[0] != 0: viz.images(k_aff.detach(), win='aff' + str(k), opts=dict(title='Class ' + str(k))) iters += 1
class VisdomLogger(Logger): def __init__(self, env='main', port=8097, hostname='localhost'): if not port_is_open(port, hostname=hostname): raise socket.error(f'Visdom not running on {hostname}:{port}') self.vis = Visdom(port=port, server=hostname, env=env) self.windows = {} self.sample_rows = [] def log_attack_result(self, result): text_a, text_b = result.diff_color(color_method='html') result_str = result.goal_function_result_str(color_method='html') self.sample_rows.append([result_str, text_a, text_b]) def log_summary_rows(self, rows, title, window_id): self.table(rows, title=title, window_id=window_id) def flush(self): self.table(self.sample_rows, title='Sample-Level Results', window_id='sample_level_results') def log_hist(self, arr, numbins, title, window_id): self.bar(arr, numbins=numbins, title=title, window_id=window_id) def text(self, text_data, title=None, window_id='default'): if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.text(text_data, win=window) else: new_window = self.vis.text(text_data, opts=dict(title=title)) self.windows[window_id] = new_window def table(self, rows, window_id=None, title=None, header=None, style=None): """ Generates an HTML table. """ if not window_id: window_id = title # Can provide either of these, if not title: title = window_id # or both. table = html_table_from_rows(rows, title=title, header=header, style_dict=style) self.text(table_html, title=title, window_id=window_id) def bar(self, X_data, numbins=10, title=None, window_id=None): window = None if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.bar(X=X_data, win=window, opts=dict(title=title, numbins=numbins)) else: new_window = self.vis.bar(X=X_data, opts=dict(title=title, numbins=numbins)) if window_id: self.windows[window_id] = new_window def hist(self, X_data, numbins=10, title=None, window_id=None): window = None if window_id and window_id in self.windows: window = self.windows[window_id] self.vis.histogram(X=X_data, win=window, opts=dict(title=title, numbins=numbins)) else: new_window = self.vis.histogram(X=X_data, opts=dict(title=title, numbins=numbins)) if window_id: self.windows[window_id] = new_window
opts=dict( stacked=True, legend=['Facebook', 'Google', 'Twitter'], rownames=['2012', '2013', '2014', '2015', '2016'] ) ) viz.bar( X=np.random.rand(20, 3), opts=dict( stacked=False, legend=['The Netherlands', 'France', 'United States'] ) ) # histogram viz.histogram(X=np.random.rand(10000), opts=dict(numbins=20)) # heatmap viz.heatmap( X=np.outer(np.arange(1, 6), np.arange(1, 11)), opts=dict( columnnames=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], rownames=['y1', 'y2', 'y3', 'y4', 'y5'], colormap='Electric', ) ) # contour x = np.tile(np.arange(1, 101), (100, 1)) y = x.transpose() X = np.exp((((x - 50) ** 2) + ((y - 50) ** 2)) / -(20.0 ** 2))
class Grapher(object): ''' A helper class to assist with plotting to visdom ''' def __init__(self, env, server, port=8097): self.vis = Visdom(server=server, port=port, env=env) self.env = env self.param_map = self._init_map() self.function_map = { 'line': self._plot_line, 'imgs': self._plot_imgs, 'img': self._plot_img, 'hist': self._plot_hist, 'video': self._plot_video } # this is persisted through the lifespan of the object # it contains the window objects self.registered_lines = {} def save(self): self.vis.save([self.env]) def _init_map(self): ''' Internal member to return a map of lists ''' return {'line': [], 'imgs': [], 'img': [], 'video': [], 'hist': []} def clear(self): '''Helper to clear and reset the internal map''' if hasattr(self, 'param_map'): self.param_map.clear() self.param_map = self._init_map() def _plot_img(self, img_list): for img_map in img_list: for key, value in img_map.items(): self.vis.image(to_data(value).detach().cpu().numpy(), opts=dict(title=key), win=key) def _plot_imgs(self, imgs_list): for imgs_map in imgs_list: for key, value in imgs_map.items(): self.vis.images(to_data(value).detach().cpu().numpy(), opts=dict(title=key), win=key) def _plot_line(self, line_list): for line_map in line_list: for key, value in line_map.items(): x = np.asarray(value[0]) # time-point y = np.asarray(value[1]) # value if len(y.shape) < 1: y = np.expand_dims(y, -1) if len(x.shape) < 1: x = np.expand_dims(x, -1) if key not in self.registered_lines: self.registered_lines[key] = self.vis.line( Y=y, X=x, opts=dict(title=key), win=key) else: self.vis.line(Y=y, X=x, opts=dict(title=key), win=self.registered_lines[key], update='append') def _plot_hist(self, hist_list): for hist_map in hist_list: for key, value in hist_map.items(): numbins = value[0] hist_value = value[1] self.vis.histogram(hist_value, opts=dict(title=key, numbins=numbins), win=key) def _plot_video(self, video_list): for video_map in video_list: for key, value in video_map.item(): assert isinstance(value, torch.Tensor), "files not supported" self.vis.video(tensor=to_data(value), opts=dict(title=key), win=key) def register(self, param_map, plot_types, override=True): ''' submit bulk map here, see register_single for detail ''' assert len(param_map) == len(plot_types) if type(override) != list: override = [override] * len(param_map) for pm, pt, o in zip(param_map, plot_types, override): self.register_single(pm, pt, o) def _find_and_append(self, param_map, plot_type): assert plot_type == 'line', "only line append supported currently" exists = False for i in range(len(self.param_map[plot_type])): list_item = self.param_map[plot_type] for key, value in param_map.items(): for j in range(len(list_item)): if key in list_item[j]: list_item[j][key][0].extend(value[0]) list_item[j][key][1].extend(value[1]) exists = True if not exists: self.param_map[plot_type].append(param_map) def _find_and_replace(self, param_map, plot_type): exists = False for i in range(len(self.param_map[plot_type])): list_item = self.param_map[plot_type] for key, value in param_map.items(): for j in range(len(list_item)): if key in list_item[j]: list_item[j][key] = value exists = True if not exists: self.param_map[plot_type].append(param_map) def register_single(self, param_map, plot_type='line', append=False, override=True): ''' register a single plot which will be added to the current map eg: register({'title': value}, 'line') plot_type: 'line', 'hist', 'imgs', 'img', 'video' override : if True then overwrite an item if it exists append : if True appends to the line. This is mainly useful useful if you are extending a line before show() Note: you can't override and append ''' assert len(param_map) == 1, "only one register per call" assert not (override is True and append is True), "cant override and append" plot_type = plot_type.lower().strip() assert plot_type == 'line' \ or plot_type == 'hist' \ or plot_type == 'imgs' \ or plot_type == 'img' \ or plot_type == 'video' if append: self._find_and_append(param_map, plot_type) if override: self._find_and_replace(param_map, plot_type) def _check_exists(self, plot_type, param_map): for key, _ in param_map.items(): # {'name', value} for list_item in self.param_map[ plot_type]: # [{'name': value}, {'name2': value2}] return key not in list_item def show(self, clear=True): ''' This helper is called to actually push the data to visdom''' for key, value_list in self.param_map.items(): self.function_map[key](value_list) if clear: # helper to clear the plot map self._init_map()
class Visualizer: def __init__(self, env="main", server="http://localhost", port=8097, base_url="/", http_proxy_host=None, http_proxy_port=None, log_to_filename=None): self._viz = Visdom(env=env, server=server, port=port, http_proxy_host=http_proxy_host, http_proxy_port=http_proxy_port, log_to_filename=log_to_filename, use_incoming_socket=False) self._viz.close(env=env) self.plots = {} def plot_line(self, name, tag, title, value, step=None): if name not in self.plots: y = numpy.array([value, value]) if step is not None: x = numpy.array([step, step]) else: x = numpy.array([1, 1]) opts = dict(title=title, xlabel='steps', ylabel=name) if tag is not None: opts["legend"] = [tag] self.plots[name] = self._viz.line(X=x, Y=y, opts=opts) else: y = numpy.array([value]) x = numpy.array([step]) self._viz.line(X=x, Y=y, win=self.plots[name], name=tag, update='append') def plot_text(self, text, title, pre=True): _width = max([len(x) for x in text.split("\n")]) * 10 _heigth = len(text.split("\n")) * 20 _heigth = max(_heigth, 120) if pre: text = "<pre>{}</pre>".format(text) self._viz.text(text, win=title, opts=dict(title=title, width=min(_width, 450), height=min(_heigth, 300))) def plot_bar(self, data, labels, title): self._viz.bar(win=title, X=data, opts=dict(legend=labels, stacked=False, title=title)) def plot_hist(self, data, title, numbins=20): self._viz.histogram(win=title, X=data, opts=dict(numbins=numbins, title=title)) def plot_scatter(self, data, title, targets=None, labels=None): self._viz.scatter( win=title, X=data, Y=targets, opts=dict( # legend=labels, title=title, markersize=5, webgl=True, width=400, height=400, markeropacity=0.5)) def plot_heatmap(self, data, labels, title): height = min(data.shape[0] * 20, 600) width = min(data.shape[1] * 25, 600) self._viz.heatmap( win=title, X=data, opts=dict( # title=title, columnnames=labels[1], rownames=labels[0], width=width, height=height, layoutopts={ 'plotly': { 'showscale': False, 'showticksuffix': False, 'showtickprefix': False, 'xaxis': { 'side': 'top', 'tickangle': -60, # 'autorange': "reversed" }, 'yaxis': { 'autorange': "reversed" }, } }))
'rownames': ['2012', '2013', '2014', '2015', '2016'] }) viz.bar(X=np.random.rand(20, 3), win='bar2', opts={ 'stacked': False, 'legend': ['America', 'Britsh', 'China'] }) # 直方图 viz.histogram( X=np.random.randint(255, size=(100)), win='win_histogram', opts=dict( xlabel='gray_rank', ylabel='count', title='histogram', numbins=10 #利用numbins对数据单位进行划分,默认是30组 )) # 热力图,地理图,表面图 x = np.tile(np.arange(1, 101), (100, 1)) y = x.transpose() X = np.exp((((x - 50)**2) + ((y - 50)**2)) / -(20.0**2)) viz.heatmap(X=X, win='heatmap', opts=dict(colormap='Hot')) # 地表图 viz.contour(X=X, win='contour', opts=dict(colormap='Viridis')) # 表面图 viz.surf(X=X, win='surf', opts=dict(colormap='Hot'))
class VisdomGrapher: def __init__(self, env_name, server, port=8097): self.env_name = env_name self.vis = Visdom(server=server, port=port, env=env_name) startup_sec = 1 while not self.vis.check_connection() and startup_sec > 0: time.sleep(0.1) startup_sec -= 0.1 # optional, time out connection def add_scalar(self, y, x, plot_name, idtag, opts={}): ''' Update vidomplot by win_title with a scalar value. If it doesn't exist, create a new plot - win_title: name and title of plot - y: y coord - x: x coord - options_dict, example {'legend': 'NAME', 'ytickmin': 0, 'ytickmax': 1} ''' # todo:numpy check for y and x # check if graph exists exists = self.vis.win_exists(idtag) # update existing window if exists: self.vis.line(Y=np.array([y]), X=np.array([x]), win=idtag, update='append', opts=opts) else: self.vis.line(Y=np.array([y]), X=np.array([x]), win=idtag, opts={ 'title': plot_name, 'xlabel': 'epoch' }) def add_histogram(self, x, plot_name, idtag, opts={'numbins': 25}): if len(list(x.shape)) > 1: x = x.ravel() opts = {**opts, **{'title': plot_name}} self.vis.histogram(x, win=idtag, opts=opts) def add_image(self, image, plot_name, idtag): ''' Update visdomplot by win_title with a scalar value. If it doesn't exist, create a new plot by default ''' self.vis.images(image, win=idtag, opts=dict(title=plot_name)) def add_tensor_grid(self, batch_tensor, plot_name, idtag, nrow): # .permute(1, 2, 0) grid_image = torchvision.utils.make_grid(batch_tensor, nrow=nrow) self.add_image(grid_image, plot_name, idtag) def add_scatter2d(self, x, labels, plot_name, idtag, reinit=True, opts={}): # check if graph exists exists = self.vis.win_exists(idtag) and not reinit # check for single values if x.shape[0] == 1: x = np.array([x]) labels = np.array([labels]) # Labels should start at 1 if np.amin(labels) == 0: labels += 1 # update existing window if exists: self.vis.scatter(x, labels, win=idtag, update='append', opts=opts) else: self.vis.scatter(x, labels, win=idtag, opts={'title': plot_name})
if model.debug: output, hidden, v = model(input, hidden, reset_experience=True) debug.append(v) else: output, hidden = model(input, hidden, reset_experience=True) word_weights = output.squeeze().data.div( args.temperature).exp().cpu() word_idx = [torch.topk(w, args.nbest)[1] for w in word_weights] words = [[corpus.dictionary.idx2word[w] for w in ws] for ws in word_idx] total_len = len(words) matched = 0 for i, w in enumerate(words): if raw_input[i + 1] in w: matched += 1 except Exception as e: pass matches.append(matched / (total_len)) print("Matched: %s / %s" % (matched, total_len)) viz.histogram(X=np.array(matches), opts=dict(colormap='Viridis', title='Fraction of Words Predicted.', ylabel='Number of Sentences', xlabel='Fraction Matched', numbins=30))