TensorFlow 2.0 Keras:如何为TensorBoard编写图像摘要

时间:2019-03-29 16:01:50

标签: python tensorflow keras tensorboard summary

我正在尝试使用TensorFlow 2.0设置图像识别CNN。为了能够分析我的图像增强,我想查看我在张量板上馈入网络的图像。

不幸的是,我无法弄清楚如何使用TensorFlow 2.0和Keras做到这一点。我也没有真正找到关于此的文档。

为简单起见,我正在显示MNIST示例的代码。如何在此处添加图片摘要?

import tensorflow as tf
(x_train, y_train), _ = tf.keras.datasets.mnist.load_data()

def scale(image, label):
    return tf.cast(image, tf.float32) / 255.0, label

def augment(image, label):
    return image, label  # do nothing atm

dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.map(scale).map(augment).batch(32)

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(dataset, epochs=5, callbacks=[tf.keras.callbacks.TensorBoard(log_dir='D:\\tmp\\test')])

2 个答案:

答案 0 :(得分:1)

除了提供您问题的答案 我将使代码更像TF2.0。如果您有任何疑问/需要澄清,请在下面发表评论。

1。正在加载数据

我建议使用Tensorflow Datasets库。如果一个人可以单行执行,则绝对不需要将数据加载到numpy中并将其转换为tf.data.Dataset

import tensorflow_datasets as tfds

dataset = tfds.load("mnist", as_supervised=True, split=tfds.Split.TRAIN)

上面的行将仅返回TRAIN个拆分(有关here的更多信息)。

2。定义扩充和摘要

为了保存图像,每次通过时都必须保留tf.summar.SummaryWriter个对象。

我使用__call__方法创建了一个方便的包装类,以便通过tf.data.Dataset的{​​{1}}功能轻松使用:

map

import tensorflow as tf class ExampleAugmentation: def __init__(self, logdir: str, max_images: int, name: str): self.file_writer = tf.summary.create_file_writer(logdir) self.max_images: int = max_images self.name: str = name self._counter: int = 0 def __call__(self, image, label): augmented_image = tf.image.random_flip_left_right( tf.image.random_flip_up_down(image) ) with self.file_writer.as_default(): tf.summary.image( self.name, augmented_image, step=self._counter, max_outputs=self.max_images, ) self._counter += 1 return augmented_image, label 将是保存图像各部分的名称。您可能会问哪一部分-由name定义的部分。

max_outputs中说image的形状为__call__,其中第一个尺寸是批处理,第二个宽度,第三个高度和最后一个通道(在MNIST的情况下,仅是onel,但是此尺寸(32, 28, 28, 1)扩充中需要)。此外,假设tf.image被指定为max_outputs。在这种情况下,将仅保存批次中的前4张图像。默认值为4,因此您可以将其设置为3以保存每张图像。

BATCH_SIZE中,每个图像都是一个单独的样本,您可以在其上最后进行迭代。

Tensorboard是必需的,这样图像将不会被覆盖(我认为,不确定,请别人澄清一下会很好)。

重要提示::在进行更严格的商务处理并将增强移动到单独的函子/ lambda函数时,您可能希望将此类重命名为_counter。我猜这足以满足演示目的。

3。设置全局变量

请不要混合使用函数声明,全局变量,数据加载和其他功能(例如,加载数据并随后创建函数)。我知道ImageSaver鼓励这种类型的编程,但是他们正试图摆脱这种编程,您可能想顺应潮流。

下面,我定义了一些全局变量,这些变量将在接下来的部分中使用,我想这很容易解释:

TF1.0

4。数据集扩充

与您相似,但略有不同:

BATCH_SIZE = 32
DATASET_SIZE = 60000
EPOCHS = 5

LOG_DIR = "/logs/images"
AUGMENTATION = ExampleAugmentation(LOG_DIR, max_images=4, name="Images")
  • dataset = ( dataset.map( lambda image, label: ( tf.image.convert_image_dtype(image, dtype=tf.float32), label, ) ) .batch(BATCH_SIZE) .map(AUGMENTATION) .repeat(EPOCHS) ) 是必需的,因为加载的数据集是生成器
  • tf.image.convert_image_dtype-比显式repeat和除以tf.cast的混合方式(更好的图像格式)更好和更具可读性的选项。
  • 为演示起见,在扩增前进行分批

5。定义模型,编译,训练

几乎与您在示例中所做的一样,但是我提供了额外的255,因此steps_per_epoch知道构成一个纪元的批次数量:

fit

除了我想的以外,没有太多要解释的了。

6。运行Tensorboard

由于model = tf.keras.models.Sequential( [ tf.keras.layers.Flatten(input_shape=(28, 28, 1)), tf.keras.layers.Dense(128, activation="relu"), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation="softmax"), ] ) model.compile( optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"] ) model.fit( dataset, epochs=EPOCHS, steps_per_epoch=DATASET_SIZE // BATCH_SIZE, callbacks=[tf.keras.callbacks.TensorBoard(log_dir=LOG_DIR)], ) 可以使用TF2.0在colab内完成,因此只想为可能访问此问题的其他人添加它。随心所欲地做到这一点,反正您肯定会做到这一点。

图像应位于%tensorboard --logdir /logs/images内,并将由IMAGES命名的每个样本提供给name对象。

7。整个代码(使每个人的生活更轻松)

AUGMENTATION

答案 1 :(得分:-1)

您可以执行类似的操作以将输入图像添加到张量板

def scale(image, label):
    return tf.cast(image, tf.float32) / 255.0, label


def augment(image, label):
    return image, label  # do nothing atm


file_writer = tf.summary.create_file_writer(logdir + "/images")


def plot_to_image(figure):
    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    plt.close(figure)
    buf.seek(0)
    image = tf.image.decode_png(buf.getvalue(), channels=4)
    image = tf.expand_dims(image, 0)
    return image


def image_grid():
    """Return a 5x5 grid of the MNIST images as a matplotlib figure."""
    # Create a figure to contain the plot.
    figure = plt.figure(figsize=(10, 10))
    for i in range(25):
        # Start next subplot.
        plt.subplot(5, 5, i + 1, title=str(y_train[i]))
        plt.xticks([])
        plt.yticks([])
        plt.grid(False)
        image, _ = scale(x_train[i], y_train[i])
        plt.imshow(x_train[i], cmap=plt.cm.binary)

    return figure


# Prepare the plot
figure = image_grid()
# Convert to image and log
with file_writer.as_default():
    tf.summary.image("Training data", plot_to_image(figure), step=0)

dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.map(scale).map(augment).batch(32)

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

model.fit(dataset, epochs=5, callbacks=[tf.keras.callbacks.TensorBoard(log_dir=logdir)])