Tensorflow 如何使用Keras在TensorBoard中显示自定义图像?

Tensorflow 如何使用Keras在TensorBoard中显示自定义图像?,tensorflow,keras,deep-learning,tensorboard,Tensorflow,Keras,Deep Learning,Tensorboard,我正在研究Keras中的分割问题,我想在每个训练阶段结束时显示分割结果 我想要类似的东西,但使用Keras。我知道Keras有回调功能,但它似乎仅限于此目的 我知道这将打破Keras后端抽象,但我对使用TensorFlow后端感兴趣 Keras+TensorFlow有可能实现这一点吗?因此,以下解决方案对我很有效: 将tensorflow导入为tf def make_图像(张量): """ 将numpy表示图像转换为图像协议。 抄袭https://github.com/lanpa/tensorb

我正在研究Keras中的分割问题,我想在每个训练阶段结束时显示分割结果

我想要类似的东西,但使用Keras。我知道Keras有回调功能,但它似乎仅限于此目的

我知道这将打破Keras后端抽象,但我对使用TensorFlow后端感兴趣


Keras+TensorFlow有可能实现这一点吗?

因此,以下解决方案对我很有效:

将tensorflow导入为tf
def make_图像(张量):
"""
将numpy表示图像转换为图像协议。
抄袭https://github.com/lanpa/tensorboard-pytorch/
"""
从PIL导入图像
高度、宽度、通道=张量.shape
image=image.fromarray(张量)
输入io
输出=io.BytesIO()
image.save(输出,格式='PNG')
image\u string=output.getvalue()
output.close()
返回tf.Summary.Image(高度=高度,
宽度=宽度,
颜色空间=通道,
编码的\u图像\u字符串=图像\u字符串)
类TensorBoardImage(keras.callbacks.Callback):
定义初始化(自我,标记):
super()。\uuuu init\uuuuu()
self.tag=tag
_epoch_end上的def(self、epoch、logs={}):
#加载图像
img=data.automotor()
#对图像做点什么
img=(255*skimage.util.random_noise(img)).astype('uint8')
图像=制作图像(img)
summary=tf.summary(值=[tf.summary.value(tag=self.tag,image=image)])
writer=tf.summary.FileWriter(“./logs”)
编写者.添加摘要(摘要,历元)
writer.close()
返回
tbi_callback=TensorBoardImage('图像示例')
只需将回调传递给
fit
fit\u generator

请注意,您还可以在回调中使用
模型运行某些操作。例如,可以在某些图像上运行模型以检查其性能


同样,您可能想试试。这是散点图

import tensorflow as tf
import numpy as np

import tfmpl

@tfmpl.figure_tensor
def draw_scatter(scaled, colors): 
    '''Draw scatter plots. One for each color.'''  
    figs = tfmpl.create_figures(len(colors), figsize=(4,4))
    for idx, f in enumerate(figs):
        ax = f.add_subplot(111)
        ax.axis('off')
        ax.scatter(scaled[:, 0], scaled[:, 1], c=colors[idx])
        f.tight_layout()

    return figs

with tf.Session(graph=tf.Graph()) as sess:

    # A point cloud that can be scaled by the user
    points = tf.constant(
        np.random.normal(loc=0.0, scale=1.0, size=(100, 2)).astype(np.float32)
    )
    scale = tf.placeholder(tf.float32)        
    scaled = points*scale

    # Note, `scaled` above is a tensor. Its being passed `draw_scatter` below. 
    # However, when `draw_scatter` is invoked, the tensor will be evaluated and a
    # numpy array representing its content is provided.   
    image_tensor = draw_scatter(scaled, ['r', 'g'])
    image_summary = tf.summary.image('scatter', image_tensor)      
    all_summaries = tf.summary.merge_all() 

    writer = tf.summary.FileWriter('log', sess.graph)
    summary = sess.run(all_summaries, feed_dict={scale: 2.})
    writer.add_summary(summary, global_step=0)
执行时,这将在张力板内部生成以下图


请注意,tf matplotlib注意评估任何张量输入,避免
pyplot
线程问题,并支持针对运行时关键绘图的blitting。

我相信我找到了一种更好的方法,可以使用tf matplotlib将此类自定义图像记录到tensorboard。这里是如何

class TensorBoardDTW(tf.keras.callbacks.TensorBoard):
    def __init__(self, **kwargs):
        super(TensorBoardDTW, self).__init__(**kwargs)
        self.dtw_image_summary = None

    def _make_histogram_ops(self, model):
        super(TensorBoardDTW, self)._make_histogram_ops(model)
        tf.summary.image('dtw-cost', create_dtw_image(model.output))
只需覆盖TensorBoard回调类中的_make_histogram_ops方法,即可添加自定义摘要。在我的例子中,
create\u dtw\u image
是一个使用tf matplotlib创建图像的函数


关于,.

以下是如何在图像上绘制地标的示例:

class CustomCallback(keras.callbacks.Callback):
    def __init__(self, model, generator):
        self.generator = generator
        self.model = model

    def tf_summary_image(self, tensor):
        import io
        from PIL import Image

        tensor = tensor.astype(np.uint8)

        height, width, channel = tensor.shape
        image = Image.fromarray(tensor)
        output = io.BytesIO()
        image.save(output, format='PNG')
        image_string = output.getvalue()
        output.close()
        return tf.Summary.Image(height=height,
                             width=width,
                             colorspace=channel,
                             encoded_image_string=image_string)

    def on_epoch_end(self, epoch, logs={}):
        frames_arr, landmarks = next(self.generator)

        # Take just 1st sample from batch
        frames_arr = frames_arr[0:1,...]

        y_pred = self.model.predict(frames_arr)

        # Get last frame for which we have done predictions
        img = frames_arr[0,-1,:,:]

        img = img * 255
        img = img[:, :, ::-1]
        img = np.copy(img)

        landmarks_gt = landmarks[-1].reshape(-1,2)
        landmarks_pred = y_pred.reshape(-1,2)

        img = draw_landmarks(img, landmarks_gt, (0,255,0))
        img = draw_landmarks(img, landmarks_pred, (0,0,255))

        image = self.tf_summary_image(img)
        summary = tf.Summary(value=[tf.Summary.Value(image=image)])
        writer = tf.summary.FileWriter('./logs')
        writer.add_summary(summary, epoch)
        writer.close()
        return

基于以上答案和我自己的搜索,我提供以下代码,以使用Keras中的TensorBoard完成以下工作:


  • 问题设置:预测双目立体匹配中的视差图
  • 向模型提供输入的左图像
    x
    和地面真实视差图
    gt
  • 在某个迭代时间显示输入
    x
    和地面真相'gt'
  • 在某个迭代时间显示模型的输出
    y

  • 首先,您必须使用
    callback
    创建定制的回调类。
    注意
    回调可以通过类属性
    self.model
    访问与其关联的模型。另外
    注意
    如果要获取并显示模型的输出,则必须使用feed\u dict将输入馈送到模型。

    from keras.callbacks import Callback
    import numpy as np
    from keras import backend as K
    import tensorflow as tf
    import cv2
    
    # make the 1 channel input image or disparity map look good within this color map. This function is not necessary for this Tensorboard problem shown as above. Just a function used in my own research project.
    def colormap_jet(img):
        return cv2.cvtColor(cv2.applyColorMap(np.uint8(img), 2), cv2.COLOR_BGR2RGB)
    
    class customModelCheckpoint(Callback):
        def __init__(self, log_dir='./logs/tmp/', feed_inputs_display=None):
              super(customModelCheckpoint, self).__init__()
              self.seen = 0
              self.feed_inputs_display = feed_inputs_display
              self.writer = tf.summary.FileWriter(log_dir)
    
        # this function will return the feeding data for TensorBoard visualization;
        # arguments:
        #  * feed_input_display : [(input_yourModelNeed, left_image, disparity_gt ), ..., (input_yourModelNeed, left_image, disparity_gt), ...], i.e., the list of tuples of Numpy Arrays what your model needs as input and what you want to display using TensorBoard. Note: you have to feed the input to the model with feed_dict, if you want to get and display the output of your model. 
        def custom_set_feed_input_to_display(self, feed_inputs_display):
              self.feed_inputs_display = feed_inputs_display
    
        # copied from the above answers;
        def make_image(self, numpy_img):
              from PIL import Image
              height, width, channel = numpy_img.shape
              image = Image.fromarray(numpy_img)
              import io
              output = io.BytesIO()
              image.save(output, format='PNG')
              image_string = output.getvalue()
              output.close()
              return tf.Summary.Image(height=height, width=width, colorspace= channel, encoded_image_string=image_string)
    
    
        # A callback has access to its associated model through the class property self.model.
        def on_batch_end(self, batch, logs = None):
              logs = logs or {} 
              self.seen += 1
              if self.seen % 200 == 0: # every 200 iterations or batches, plot the costumed images using TensorBorad;
                  summary_str = []
                  for i in range(len(self.feed_inputs_display)):
                      feature, disp_gt, imgl = self.feed_inputs_display[i]
                      disp_pred = np.squeeze(K.get_session().run(self.model.output, feed_dict = {self.model.input : feature}), axis = 0)
                      #disp_pred = np.squeeze(self.model.predict_on_batch(feature), axis = 0)
                      summary_str.append(tf.Summary.Value(tag= 'plot/img0/{}'.format(i), image= self.make_image( colormap_jet(imgl)))) # function colormap_jet(), defined above;
                      summary_str.append(tf.Summary.Value(tag= 'plot/disp_gt/{}'.format(i), image= self.make_image( colormap_jet(disp_gt))))
                      summary_str.append(tf.Summary.Value(tag= 'plot/disp/{}'.format(i), image= self.make_image( colormap_jet(disp_pred))))
    
                  self.writer.add_summary(tf.Summary(value = summary_str), global_step =self.seen)
    
  • 接下来,将此回调对象传递给模型的
    fit\u generator()
    ,如:

       feed_inputs_4_display = some_function_you_wrote()
       callback_mc = customModelCheckpoint( log_dir = log_save_path, feed_inputd_display = feed_inputs_4_display)
       # or 
       callback_mc.custom_set_feed_input_to_display(feed_inputs_4_display)
       yourModel.fit_generator(... callbacks = callback_mc)
       ...
    
  • 现在,您可以运行代码,并转到TensorBoard主机以查看服装图像显示。例如,这是我使用上述代码得到的:


    完成了!享受吧


  • 我试图在tensorboard上显示matplotlib图(在绘制统计数据、热图等方面很有用)。它也可用于一般情况

    class AttentionLogger(keras.callbacks.Callback):
    定义初始化(自身、值数据、日志数据):
    超级(注意力记录器,自我)。\uuuu初始化
    self.logsdir=logsdir#将在其中写入事件文件
    self.validation_data=val_data#验证数据生成器
    self.writer=tf.summary.FileWriter(self.logsdir)#创建摘要编写器
    @tfmpl.figure\u张量
    def attention_matplotlib(自我、gen_图像):
    '''
    创建matplotlib图形,并使用tf matplotlib将其写入tensorboard
    gen_images:要写入tensorboard的形状(大小、宽度、高度、通道)的图像张量
    '''  
    r、 c=5,5#希望在TBD(tensorboard)中将25个图像作为5x5 matplotlib子批次写入
    图=tfmpl.创建图(1,figsize=(15,15))
    cnt=0
    对于idx,枚举中的f(图):
    对于范围(r)内的i:
    对于范围(c)内的j:
    ax=f.add_子批次(r、c、cnt+1)
    ax.设置标签([])
    ax.setxticklabels([])
    ax.imshow(gen_images[cnt])#将索引cnt处的图像写入5x5网格
    cnt+=1
    f、 紧凑的布局()
    返回无花果
    列车上的def开始(self,logs=None):#培训开始时(仅运行一次)
    image_summary=[]创建所需摘要列表(可以是标量、图像、直方图等)
    对于范围内的索引(len(self.model.output)):#self.model可在回调中访问
    img_sum=tf.summary.image('img{}.format(index),self.attention_matplotlib(self.model.output[index]))
    
    class customModelCheckpoint(Callback):
    def __init__(self, log_dir='../logs/', feed_inputs_display=None):
          super(customModelCheckpoint, self).__init__()
          self.seen = 0
          self.feed_inputs_display = feed_inputs_display
          self.writer = tf.summary.FileWriter(log_dir)
    
    
    def custom_set_feed_input_to_display(self, feed_inputs_display):
          self.feed_inputs_display = feed_inputs_display
    
    
    # A callback has access to its associated model through the class property self.model.
    def on_batch_end(self, batch, logs = None):
          logs = logs or {}
          self.seen += 1
          if self.seen % 8 == 0: # every 200 iterations or batches, plot the costumed images using TensorBorad;
              summary_str = []
              feature = self.feed_inputs_display[0][0]
              disp_gt = self.feed_inputs_display[0][1]
              disp_pred = self.model.predict_on_batch(feature)
    
              summary_str.append(tf.summary.image('disp_input/{}'.format(self.seen), feature, max_outputs=4))
              summary_str.append(tf.summary.image('disp_gt/{}'.format(self.seen), disp_gt, max_outputs=4))
              summary_str.append(tf.summary.image('disp_pred/{}'.format(self.seen), disp_pred, max_outputs=4))
    
              summary_st = tf.summary.merge(summary_str)
              summary_s = K.get_session().run(summary_st)
              self.writer.add_summary(summary_s, global_step=self.seen)
              self.writer.flush()
    
    callback_mc = customModelCheckpoint(log_dir='../logs/',  feed_inputs_display=[(a, b)])
    callback_tb = TensorBoard(log_dir='../logs/', histogram_freq=0, write_graph=True, write_images=True)
    callback = []
    def data_gen(fr1, fr2):
    while True:
        hdr_arr = []
        ldr_arr = []
        for i in range(args['batch_size']):
            try:
                ldr = pickle.load(fr2)           
                hdr = pickle.load(fr1)               
            except EOFError:
                fr1 = open(args['data_h_hdr'], 'rb')
                fr2 = open(args['data_h_ldr'], 'rb')
            hdr_arr.append(hdr)
            ldr_arr.append(ldr)
        hdr_h = np.array(hdr_arr)
        ldr_h = np.array(ldr_arr)
        gen = aug.flow(hdr_h, ldr_h, batch_size=args['batch_size'])
        out = gen.next()
        a = out[0]
        b = out[1]
        callback_mc.custom_set_feed_input_to_display(feed_inputs_display=[(a, b)])
        yield [a, b]
    
    callback.append(callback_tb)
    callback.append(callback_mc)
    H = model.fit_generator(data_gen(fr1, fr2), steps_per_epoch=100,   epochs=args['epoch'], callbacks=callback)
    
    import tensorflow as tf
    import math
    
    class TensorBoardImage(tf.keras.callbacks.Callback):
    
        def __init__(self, logdir, train, validation=None):
            super(TensorBoardImage, self).__init__()
            self.logdir = logdir
            self.train = train
            self.validation = validation
            self.file_writer = tf.summary.create_file_writer(logdir)
    
        def on_batch_end(self, batch, logs):
            images_or_labels = 0 #0=images, 1=labels
            imgs = self.train[batch][images_or_labels]
    
            #calculate epoch
            n_batches_per_epoch = self.train.samples / self.train.batch_size
            epoch = math.floor(self.train.total_batches_seen / n_batches_per_epoch)
    
            #since the training data is shuffled each epoch, we need to use the index_array to find something which uniquely 
            #identifies the image and is constant throughout training
            first_index_in_batch = batch * self.train.batch_size
            last_index_in_batch = first_index_in_batch + self.train.batch_size
            last_index_in_batch = min(last_index_in_batch, len(self.train.index_array))
            img_indices = self.train.index_array[first_index_in_batch : last_index_in_batch]
    
            #convert float to uint8, shift range to 0-255
            imgs -= tf.reduce_min(imgs)
            imgs *= 255 / tf.reduce_max(imgs)
            imgs = tf.cast(imgs, tf.uint8)
    
            with self.file_writer.as_default():
                for ix,img in enumerate(imgs):
                    img_tensor = tf.expand_dims(img, 0) #tf.summary needs a 4D tensor
                    #only post 1 out of every 1000 images to tensorboard
                    if (img_indices[ix] % 1000) == 0:
                        #instead of img_filename, I could just use str(img_indices[ix]) as a unique identifier
                        #but this way makes it easier to find the unaugmented image
                        img_filename = self.train.filenames[img_indices[ix]]
                        tf.summary.image(img_filename, img_tensor, step=epoch)
    
    train_augmentation = keras.preprocessing.image.ImageDataGenerator(rotation_range=20,
                                                                        shear_range=10,
                                                                        zoom_range=0.2,
                                                                        width_shift_range=0.2,
                                                                        height_shift_range=0.2,
                                                                        brightness_range=[0.8, 1.2],
                                                                        horizontal_flip=False,
                                                                        vertical_flip=False
                                                                        )
    train_data_generator = train_augmentation.flow_from_directory(directory='/some/path/train/',
                                                                    class_mode='categorical',
                                                                    batch_size=batch_size,
                                                                    shuffle=True
                                                                    )
    
    valid_augmentation = keras.preprocessing.image.ImageDataGenerator()
    valid_data_generator = valid_augmentation.flow_from_directory(directory='/some/path/valid/',
                                                                    class_mode='categorical',
                                                                    batch_size=batch_size,
                                                                    shuffle=False
                                                                    )
    tensorboard_log_dir = '/some/path'
    tensorboard_callback = keras.callbacks.TensorBoard(log_dir=tensorboard_log_dir, update_freq='batch')
    tensorboard_image_callback = tensorflow_image_callback.TensorBoardImage(logdir=tensorboard_log_dir, train=train_data_generator, validation=valid_data_generator)
    
    model.fit(x=train_data_generator,
            epochs=n_epochs,
            validation_data=valid_data_generator, 
            validation_freq=1,
            callbacks=[
                        tensorboard_callback,
                        tensorboard_image_callback
                        ])