Keras - Сохранить встраивание изображения из набора данных mnist
Я написал следующую простую сеть MLP для MNIST
дб.
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras import callbacks
batch_size = 100
num_classes = 10
epochs = 20
tb = callbacks.TensorBoard(log_dir='/Users/shlomi.shwartz/tensorflow/notebooks/logs/minist', histogram_freq=10, batch_size=32,
write_graph=True, write_grads=True, write_images=True,
embeddings_freq=10, embeddings_layer_names=None,
embeddings_metadata=None)
early_stop = callbacks.EarlyStopping(monitor='val_loss', min_delta=0,
patience=3, verbose=1, mode='auto')
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Dense(200, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(60, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(30, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
history = model.fit(x_train, y_train,
callbacks=[tb,early_stop],
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
Модель работала нормально, и я мог видеть информацию о скалярах на TensorBoard. Однако, когда я изменил embeddings_freq=10, чтобы попытаться визуализировать изображения (как показано здесь), я получил следующую ошибку:
Traceback (most recent call last):
File "/Users/shlomi.shwartz/IdeaProjects/TF/src/minist.py", line 65, in <module>
validation_data=(x_test, y_test))
File "/Users/shlomi.shwartz/tensorflow/lib/python3.6/site-packages/keras/models.py", line 870, in fit
initial_epoch=initial_epoch)
File "/Users/shlomi.shwartz/tensorflow/lib/python3.6/site-packages/keras/engine/training.py", line 1507, in fit
initial_epoch=initial_epoch)
File "/Users/shlomi.shwartz/tensorflow/lib/python3.6/site-packages/keras/engine/training.py", line 1117, in _fit_loop
callbacks.set_model(callback_model)
File "/Users/shlomi.shwartz/tensorflow/lib/python3.6/site-packages/keras/callbacks.py", line 52, in set_model
callback.set_model(model)
File "/Users/shlomi.shwartz/tensorflow/lib/python3.6/site-packages/keras/callbacks.py", line 719, in set_model
self.saver = tf.train.Saver(list(embeddings.values()))
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/tensorflow/python/training/saver.py", line 1139, in __init__
self.build()
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/tensorflow/python/training/saver.py", line 1161, in build
raise ValueError("No variables to save")
ValueError: No variables to save
Q: Чего мне не хватает? Это правильный способ сделать это в Керасе?
Обновление: я понимаю, что существует некоторая предпосылка для использования проекции встраивания, однако я не нашел хорошего руководства для этого в Керасе, любая помощь будет признательна.
3 ответа
Что называется "встраивание" здесь в callbacks.TensorBoard
в широком смысле, любой слой веса. Согласно документации Keras:
embeddings_layer_names: список имен слоев, за которыми нужно следить. Если None или пустой список, будет наблюдаться весь слой внедрения.
Таким образом, по умолчанию он будет контролировать Embedding
слои, но вам не нужно Embedding
слой, чтобы использовать этот инструмент визуализации.
В приведенном вами примере MLP не хватает embeddings_layer_names
аргумент. Вы должны выяснить, какие слои вы собираетесь визуализировать. Предположим, вы хотите визуализировать вес (или, kernel
в Керасе) всего Dense
слои, вы можете указать embeddings_layer_names
как это:
model = Sequential()
model.add(Dense(200, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(60, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(30, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
embedding_layer_names = set(layer.name
for layer in model.layers
if layer.name.startswith('dense_'))
tb = callbacks.TensorBoard(log_dir='temp', histogram_freq=10, batch_size=32,
write_graph=True, write_grads=True, write_images=True,
embeddings_freq=10, embeddings_metadata=None,
embeddings_layer_names=embedding_layer_names)
model.compile(...)
model.fit(...)
Затем вы можете увидеть что-то вроде этого в TensorBoard:
Вы можете увидеть соответствующие строки в источнике Keras, если вы хотите выяснить, что происходит с embeddings_layer_names
,
Редактировать:
Итак, вот грязное решение для визуализации выходных данных слоя. Так как оригинал TensorBoard
обратный вызов не поддерживает это, реализация нового обратного вызова кажется неизбежной.
Так как это займет много места на странице, чтобы переписать весь TensorBoard
обратный звонок здесь, я просто расширю оригинал TensorBoard
и выписать части, которые отличаются (что уже довольно долго). Но чтобы избежать дублирования вычислений и сохранения модели, переписать TensorBoard
обратный вызов будет лучше и чище.
import tensorflow as tf
from tensorflow.contrib.tensorboard.plugins import projector
from keras import backend as K
from keras.models import Model
from keras.callbacks import TensorBoard
class TensorResponseBoard(TensorBoard):
def __init__(self, val_size, img_path, img_size, **kwargs):
super(TensorResponseBoard, self).__init__(**kwargs)
self.val_size = val_size
self.img_path = img_path
self.img_size = img_size
def set_model(self, model):
super(TensorResponseBoard, self).set_model(model)
if self.embeddings_freq and self.embeddings_layer_names:
embeddings = {}
for layer_name in self.embeddings_layer_names:
# initialize tensors which will later be used in `on_epoch_end()` to
# store the response values by feeding the val data through the model
layer = self.model.get_layer(layer_name)
output_dim = layer.output.shape[-1]
response_tensor = tf.Variable(tf.zeros([self.val_size, output_dim]),
name=layer_name + '_response')
embeddings[layer_name] = response_tensor
self.embeddings = embeddings
self.saver = tf.train.Saver(list(self.embeddings.values()))
response_outputs = [self.model.get_layer(layer_name).output
for layer_name in self.embeddings_layer_names]
self.response_model = Model(self.model.inputs, response_outputs)
config = projector.ProjectorConfig()
embeddings_metadata = {layer_name: self.embeddings_metadata
for layer_name in embeddings.keys()}
for layer_name, response_tensor in self.embeddings.items():
embedding = config.embeddings.add()
embedding.tensor_name = response_tensor.name
# for coloring points by labels
embedding.metadata_path = embeddings_metadata[layer_name]
# for attaching images to the points
embedding.sprite.image_path = self.img_path
embedding.sprite.single_image_dim.extend(self.img_size)
projector.visualize_embeddings(self.writer, config)
def on_epoch_end(self, epoch, logs=None):
super(TensorResponseBoard, self).on_epoch_end(epoch, logs)
if self.embeddings_freq and self.embeddings_ckpt_path:
if epoch % self.embeddings_freq == 0:
# feeding the validation data through the model
val_data = self.validation_data[0]
response_values = self.response_model.predict(val_data)
if len(self.embeddings_layer_names) == 1:
response_values = [response_values]
# record the response at each layers we're monitoring
response_tensors = []
for layer_name in self.embeddings_layer_names:
response_tensors.append(self.embeddings[layer_name])
K.batch_set_value(list(zip(response_tensors, response_values)))
# finally, save all tensors holding the layer responses
self.saver.save(self.sess, self.embeddings_ckpt_path, epoch)
Чтобы использовать это:
tb = TensorResponseBoard(log_dir=log_dir, histogram_freq=10, batch_size=10,
write_graph=True, write_grads=True, write_images=True,
embeddings_freq=10,
embeddings_layer_names=['dense_1'],
embeddings_metadata='metadata.tsv',
val_size=len(x_test), img_path='images.jpg', img_size=[28, 28])
Перед запуском TensorBoard вам необходимо сохранить метки и изображения в log_dir
для визуализации:
from PIL import Image
img_array = x_test.reshape(100, 100, 28, 28)
img_array_flat = np.concatenate([np.concatenate([x for x in row], axis=1) for row in img_array])
img = Image.fromarray(np.uint8(255 * (1. - img_array_flat)))
img.save(os.path.join(log_dir, 'images.jpg'))
np.savetxt(os.path.join(log_dir, 'metadata.tsv'), np.where(y_test)[1], fmt='%d')
Вот результат:
Вам нужен как минимум один слой для встраивания в Keras. На статистике было хорошее объяснение о них. Это не напрямую для Кераса, но концепции примерно одинаковы. Что такое слой встраивания в нейронную сеть?
Итак, я заключаю, что вы действительно хотите (это не совсем ясно из вашего поста), чтобы визуализировать предсказания вашей модели, способом, подобным этой демонстрации Tensorboard.
Начнем с того, что воспроизвести этот материал нетривиально даже в Tensorflow, не говоря уже о Keras. В упомянутой демонстрации очень краткие и краткие ссылки на такие вещи, как метаданные и изображения спрайтов, которые необходимы для получения таких визуализаций.
Итог: хотя это нетривиально, это действительно возможно сделать с помощью Keras. Вам не нужны обратные вызовы Keras; все, что вам нужно, это предсказания вашей модели, необходимые метаданные и изображение спрайта, а также некоторый чистый код TensorFlow. Так,
Шаг 1 - получите прогнозы вашей модели для тестового набора:
emb = model.predict(x_test) # 'emb' for embedding
Шаг 2а - создайте файл метаданных с реальными метками тестового набора:
import numpy as np
LOG_DIR = '/home/herc/SO/tmp' # FULL PATH HERE!!!
metadata_file = os.path.join(LOG_DIR, 'metadata.tsv')
with open(metadata_file, 'w') as f:
for i in range(len(y_test)):
c = np.nonzero(y_test[i])[0][0]
f.write('{}\n'.format(c))
Шаг 2б - получить спрайт-изображение mnist_10k_sprite.png
как предусмотрено парнями из TensorFlow здесь, и поместите его в свой LOG_DIR
Шаг 3 - написать код Tensorflow:
import tensorflow as tf
from tensorflow.contrib.tensorboard.plugins import projector
embedding_var = tf.Variable(emb, name='final_layer_embedding')
sess = tf.Session()
sess.run(embedding_var.initializer)
summary_writer = tf.summary.FileWriter(LOG_DIR)
config = projector.ProjectorConfig()
embedding = config.embeddings.add()
embedding.tensor_name = embedding_var.name
# Specify the metadata file:
embedding.metadata_path = os.path.join(LOG_DIR, 'metadata.tsv')
# Specify the sprite image:
embedding.sprite.image_path = os.path.join(LOG_DIR, 'mnist_10k_sprite.png')
embedding.sprite.single_image_dim.extend([28, 28]) # image size = 28x28
projector.visualize_embeddings(summary_writer, config)
saver = tf.train.Saver([embedding_var])
saver.save(sess, os.path.join(LOG_DIR, 'model2.ckpt'), 1)
Затем, запустив Tensorboard в вашем LOG_DIR
и выбрав цвет по метке, вот что вы получите:
Изменить его, чтобы получить прогнозы для других уровней, довольно просто, хотя в этом случае функциональный API Keras может быть лучшим выбором.