[英]TensorFlow 2.0 Keras: How to write image summaries for TensorBoard
我正在嘗試使用 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')])
除了為您的問題提供答案外,我將使代碼更像TF2.0
。 如果您有任何問題/需要澄清,請在下方發表評論。
我建議使用Tensorflow Datasets庫。 如果可以在一行中完成,絕對不需要在numpy
加載數據並將其轉換為tf.data.Dataset
:
import tensorflow_datasets as tfds
dataset = tfds.load("mnist", as_supervised=True, split=tfds.Split.TRAIN)
上面的行只會返回TRAIN
split(在此處閱讀有關這些內容的更多信息)。
為了保存圖像,必須在每次傳遞中保留tf.summary.SummaryWriter對象。
我用__call__
方法創建了一個方便的包裝類,以便與tf.data.Dataset
的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
定義的部分。
假設__call__
image
將具有形狀(32, 28, 28, 1)
,其中第一個維度是批次、第二個寬度、第三個高度和最后一個通道(在 MNIST 的情況下只有一個,但在tf.image
增強中需要這個維度) . 此外,假設max_outputs
被指定為4
。 在這種情況下,將只保存批次中的 4 張第一張圖像。 默認值為3
,因此您可以將其設置為BATCH_SIZE
以保存每個圖像。
在Tensorboard
,每個圖像都是一個單獨的樣本,您可以在最后對其進行迭代。
_counter
是必需的,因此圖像不會被覆蓋(我認為,不太確定,其他人的澄清會很好)。
重要提示:在進行更嚴肅的ImageSaver
時,您可能希望將此類重命名為ImageSaver
類的名稱,並將擴充移至單獨的函子/lambda 函數。 我想這足以用於演示目的。
請不要混合使用函數聲明、全局變量、數據加載等(如加載數據和創建函數)。 我知道TF1.0
鼓勵這種類型的編程,但他們正試圖擺脫它,你可能想跟上潮流。
下面我定義了一些全局變量,這些變量將在接下來的部分中使用,我想這是不言自明的:
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)
)
repeat
,因為加載的數據集是一個生成器tf.image.convert_image_dtype
- 比顯式tf.cast
與除以255
混合更好、更易讀的選項(並確保正確的圖像格式)幾乎就像你在你的例子中所做的那樣,但我提供了額外的steps_per_epoch
,所以fit
知道有多少批次構成一個紀元:
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
命名的樣本都提供給AUGMENTATION
對象。
import tensorflow as tf
import tensorflow_datasets as tfds
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
if __name__ == "__main__":
# Global settings
BATCH_SIZE = 32
DATASET_SIZE = 60000
EPOCHS = 5
LOG_DIR = "/logs/images"
AUGMENTATION = ExampleAugmentation(LOG_DIR, max_images=4, name="Images")
# Dataset
dataset = tfds.load("mnist", as_supervised=True, split=tfds.Split.TRAIN)
dataset = (
dataset.map(
lambda image, label: (
tf.image.convert_image_dtype(image, dtype=tf.float32),
label,
)
)
.batch(BATCH_SIZE)
.map(AUGMENTATION)
.repeat(EPOCHS)
)
# Model and training
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)],
)
你可以做這樣的事情來將輸入圖像添加到張量板
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)])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.