我正在尝试使用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.如果您有任何疑问/需要澄清,请在下面发表评论.
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的地图功能:
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__中的图像将具有形状(32,28,28,1),其中第一个维度是批次,第二个宽度,第三个高度和最后一个通道(仅在MNIST的情况下是onel但在tf.image增强中需要此尺寸) .此外,假设max_outputs指定为4.在这种情况下,将仅保存批处理中的4个第一个图像.默认值为3,因此您可以将其设置为BATCH_SIZE以保存每个图像.
在Tensorboard中,每个图像都是一个单独的样本,您可以在最后进行迭代.
需要_counter所以图像不会被覆盖(我想,不太确定,其他人的澄清会很好).
重要提示:您可能希望在执行更严重的业务时将此类重命名为ImageSaver,并将扩充移动到单独的仿函数/ lambda函数.我想这足以用于演示目的.
3.设置全局变量
请不要混合函数声明,全局变量,数据加载等(如后加载数据和创建函数).我知道TF1.0鼓励这种类型的编程,但他们试图摆脱它,你可能想要跟随趋势.
下面我已经定义了一些全局变量,这些变量将在下一部分中使用,我猜是非常不言自明的:
BATCH_SIZE = 32
DATASET_SIZE = 60000
EPOCHS = 5
LOG_DIR = "/logs/images"
AUGMENTATION = ExampleAugmentation(LOG_DIR, max_images=4, name="Images")
4.数据集扩充
与你的相似,但有一点点扭曲:
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
– 比显式tf.cast混合更好和更可读的选项与除以255(并确保正确的图像格式)
>仅为了演示而在扩充之前完成批处理
5.定义模型,编译,训练
几乎就像你在你的例子中所做的那样,但我提供了额外的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)],
)
除了我认为的解释之外,没什么可说的.
6.运行Tensorboard
由于TF2.0可以使用%tensorboard –logdir / logs / images在colab内部执行,只是想为可能访问此问题的其他人添加此内容.无论你喜欢它,无论如何你知道如何做到这一点.
图像应位于IMAGES内,并且按名称命名的每个样本都提供给AUGMENTATION对象.
7.整个代码(让每个人的生活更轻松)
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)],
)