), ) # Assure that the stacked area plot isn't giant viz.update_window_opts( win=win, opts=dict( width=300, height=300, ), ) # boxplot X = np.random.rand(100, 2) X[:, 1] += 2 viz.boxplot(X=X, opts=dict(legend=['Men', 'Women'])) # stemplot Y = np.linspace(0, 2 * math.pi, 70) X = np.column_stack((np.sin(Y), np.cos(Y))) viz.stem(X=X, Y=Y, opts=dict(legend=['Sine', 'Cosine'])) # quiver plot X = np.arange(0, 2.1, .2) Y = np.arange(0, 2.1, .2) X = np.broadcast_to(np.expand_dims(X, axis=1), (len(X), len(X))) Y = np.broadcast_to(np.expand_dims(Y, axis=0), (len(Y), len(Y))) U = np.multiply(np.cos(X), Y) V = np.multiply(np.sin(X), Y) viz.quiver( X=U,
class Visualizer(threading.Thread): def __init__(self, env='Visualizer'): super(Visualizer, self).__init__() self.name = env self.vis = Visdom(env=env) self.taskList = queue.Queue() self.fStop = False self.funcList = dict(result=self.dispCurrentResults, tTrain=self.dispTrainTime, tIter=self.dispIterTime, text=self.infoText) self.plotData = dict(loss=dict( x=[], y=[], )) self.lossData = {'X': [], 'loss': []} self.trainTime = {'X': [], 'Time': []} self.iterTime = {'iter': [], 'time': []} self.epochIterTime = [[]] # self.boxEpoch = 0 # self.boxIter = 0 # |visuals|: dictionary of images to display or save # vis.task(msg=dict( # func='result', # data=dict( # epoch=, # data=, # errors= # ) # )) def dispCurrentResults(self, msg): epoch = msg['epoch'] data = msg['data'] errors = msg['error'] for item in data.keys(): # print(data[item].shape) self.vis.image(data[item], win=item, opts=dict(title=item)) self.lossData['X'].append(epoch) self.lossData['loss'].append(errors['loss']) self.vis.line(X=np.array(self.lossData['X']), Y=np.array(self.lossData['loss']), opts={ 'title': 'Loss', 'xlabel': 'Epoch', 'ylabel': 'Loss' }, win='loss') # vis.task(msg=dict( # func='tTrain', # data=dict( # epoch=, # time= # ) # )) def dispTrainTime(self, msg): epoch = msg['epoch'] time = msg['time'] self.trainTime['X'].append(epoch) self.trainTime['Time'].append(time) self.vis.line(X=np.array(self.trainTime['X']), Y=np.array(self.trainTime['Time']), opts={ 'title': 'Training Time', 'xlabel': 'Epoch', 'ylabel': 'Time' }, win='trainTime') # vis.task(msg=dict( # func='tIter', # data=dict( # iter=, # time= # ) # )) # def addIterTime(self, msg): def dispIterTime(self, msg): epoch = msg['epoch'] time = msg['time'] if len(self.epochIterTime) <= epoch: self.epochIterTime.append([time]) else: self.epochIterTime[epoch].append(time) if epoch != 0: self.epochIterTime[0][0] = self.epochIterTime[0][1] self.vis.boxplot(X=np.array( self.epochIterTime[:epoch]).transpose(), opts={ 'title': 'Iter Time per Epoch', 'xlabel': 'Epoch', 'ylabel': 'Time' }, win='iterTime') def task(self, msg): self.taskList.put(msg) def run(self): while not self.fStop: if not self.taskList.empty(): msg = self.taskList.get() self.funcList[msg['func']](msg['data']) def stop(self): self.fStop = False # vis.task(msg=dict( # func='text', # data=dict( # text=[], # title=, # 可选 # win= # 可选 # ) # )) def infoText(self, msg): text = msg['text'] try: title = msg['title'] except: title = "info" try: win = msg['win'] except: win = title text_ = "" if win is None: win = title if isinstance(text, str): text_ = text elif isinstance(text, list): text_ = "" for s in text: text_ += s + "<br>" self.vis.text(text_, win=win, opts=dict(title=title, font='Calibri'))
xlabel='Time', ylabel='Volume', ytype='log', title='Stacked area plot', marginleft=30, marginright=30, marginbottom=80, margintop=30, ), ) # boxplot X = np.random.rand(100, 2) X[:, 1] += 2 viz.boxplot( X=X, opts=dict(legend=['Men', 'Women']) ) # stemplot Y = np.linspace(0, 2 * math.pi, 70) X = np.column_stack((np.sin(Y), np.cos(Y))) viz.stem( X=X, Y=Y, opts=dict(legend=['Sine', 'Cosine']) ) # pie chart X = np.asarray([19, 26, 55]) viz.pie( X=X,
if isinstance(text, str): text_ = text elif isinstance(text, list): text_ = "" for s in text: text_ += s + "<br>" self.vis.text(text_, win=win, opts=dict(title=title, font='Calibri')) if __name__ == "__main__": vis = Visdom(env="boxPlotTest") # uneven = np.array([[1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5]]) # vis.boxplot( # uneven.transpose(), # win="unEven" # ) even = np.array([[1, 1], [2, 2], [3, 3], [4, 4], [5], [6], [7], [8]]) vis.boxplot( even, win="even1", ) # vis.boxplot( # even.transpose(), # win="even2" # )
class Visualizer(object): def __init__(self, name, save=True, output_dir="."): self.visdom = Visdom() self.name = name self.plots = dict() self.save = save if save: if not os.path.exists(output_dir): raise ValueError("output_dir does not exists") # output directory for reconstructions self.recon_dir = os.path.join(output_dir, "reconstructions") if not os.path.exists(self.recon_dir): os.mkdir(self.recon_dir) # output directory for traversals self.trav_dir = os.path.join(output_dir, "traversals") if not os.path.exists(self.trav_dir): os.mkdir(self.trav_dir) def traverse(self, decoder, latent_vector, dims=None, num_traversals=None, iter_n=""): """ Traverses a latent vector along a given dimension(s). Args: decoder: (torch.nn.Module) decoder model that generates the reconstructions from a latent vector latent_vector: (torch.tensor) latent vector representation to be traversed of shape (z_dim) dims: (list, range or torch.tensor) list of dimensions to traverse in the latent vector (optional) num_traversals: (int) how many reconstructions to generate for each dimension. The image grid will be of shape: len(dims) x num_traversals iter_n: (str) iteration at which plotting and/or image index (OPTIONAL) """ if dims is None: dims = torch.arange(latent_vector.size(0)) elif not (isinstance(dims, list) or isinstance(dims, range) or isinstance(dims, torch.tensor)): raise ValueError( f"dims must either be a list or a torch.tensor, received {type(dims)}" ) if num_traversals is None: num_traversals = latent_vector.size(0) elif not isinstance(num_traversals, int): raise ValueError( f"num_traversals must either be an int, received {type(num_traversals)}" ) traversals = torch.linspace(-3., 3., steps=num_traversals).to( latent_vector.device) reconstructions = [] for dim in dims: tiles = latent_vector.repeat(num_traversals, 1) tiles[:, dim] = traversals dim_recon = decoder(tiles) reconstructions.append(dim_recon) reconstructions = torch.sigmoid(torch.cat(reconstructions, dim=0)) reconstructed = torchvision.utils.make_grid(reconstructions, normalize=True, nrow=len(dims)) self.visdom.images(reconstructed.cpu(), env=self.name + "-traversals", opts={"title": iter_n}, nrow=len(dims)) if self.save: torchvision.utils.save_image(reconstructions, os.path.join( self.trav_dir, f"traversals-{iter_n}.png"), normalize=True, nrow=len(dims)) def show_reconstructions(self, images, reconstructions, iter_n=""): """ Plots the ELBO loss, reconstruction loss and KL divergence Args: images: (torch.tensor) of shape batch_size x 3 x size x size reconstructions: (torch.Tensor) of shape batch_size x 3 x size x size iter_n: (str) iteration at which plotting (OPTIONAL) """ original = torchvision.utils.make_grid(images, normalize=True) reconstructed = torchvision.utils.make_grid( torch.sigmoid(reconstructions), normalize=True) self.visdom.images(torch.stack([original, reconstructed], dim=0).cpu(), env=self.name + "-reconstructed", opts={"title": iter_n}, nrow=8) if self.save: torchvision.utils.save_image(original, os.path.join( self.recon_dir, f"original-{iter_n}.png"), normalize=True) torchvision.utils.save_image(torch.sigmoid(reconstructions), os.path.join( self.recon_dir, f"reconstructed-{iter_n}.png"), normalize=True) def __init_plots(self, iter_n, elbo, reconstruction_loss, kl_loss): self.plots["elbo"] = self.visdom.line(torch.tensor([elbo]), X=torch.tensor([iter_n]), env=self.name + "-stats", opts={ "title": "ELBO", "width": 600, "height": 500 }) self.plots["reconstruction_loss"] = self.visdom.line( torch.tensor([reconstruction_loss]), X=torch.tensor([iter_n]), env=self.name + "-stats", opts={ "title": "Reconstruction loss", "width": 600, "height": 500 }) self.plots["kl_loss"] = self.visdom.line(torch.tensor([kl_loss]), X=torch.tensor([iter_n]), env=self.name + "-stats", opts={ "title": "KL divergence", "width": 600, "height": 500 }) def plot_stats(self, iter_n, elbo, reconstruction_loss, kl_loss): """ Plots the ELBO loss, reconstruction loss and KL divergence Args: iter_n: (int) iteration at which plotting elbo: (int) reconstruction_loss: (int) kl_loss: (int) """ # Initialize the plots if not self.plots: self.__init_plots(iter_n, elbo, reconstruction_loss, kl_loss) return self.plots["elbo"] = self.visdom.line(torch.tensor([elbo]), X=torch.tensor([iter_n]), win=self.plots["elbo"], update="append", env=self.name + "-stats", opts={ "title": "ELBO", "width": 600, "height": 500 }) self.plots["reconstruction_loss"] = self.visdom.line( torch.tensor([reconstruction_loss]), X=torch.tensor([iter_n]), win=self.plots["reconstruction_loss"], update="append", env=self.name + "-stats", opts={ "title": "Reconstruction Loss", "width": 600, "height": 500 }) self.plots["kl_loss"] = self.visdom.line(torch.tensor([kl_loss]), X=torch.tensor([iter_n]), win=self.plots["kl_loss"], update="append", env=self.name + "-stats", opts={ "title": "KL Divergence", "width": 600, "height": 500 }) def plot_means(self, z): """ Plots dimension-wise boxplot distribution Args: z: (torch.tensor) single batch of latent vector representations """ if not self.plots.get("latent", False): self.plots["latent"] = self.visdom.boxplot( X=z, env=self.name + "-stats", opts={ "title": "Latent stats", "width": 1200, "height": 600, "legend": [f"z_{i}" for i in range(1, z.size(1) + 1)] }) else: self.plots["latent"] = self.visdom.boxplot( X=z, win=self.plots["latent"], env=self.name + "-stats", opts={ "title": "Latent stats", "width": 1200, "height": 600, "legend": [f"z_{i}" for i in range(1, z.size(1) + 1)] })