Найдите вход, который максимизирует выход нейронной сети, используя Keras и TensorFlow - PullRequest
0 голосов
/ 06 октября 2018

Я использовал Keras и TensorFlow для классификации Fashion MNIST после этого урока .

Он использует AdamOptimizer , чтобы найти значениедля параметров модели, которые минимизируют функцию потерь в сети.Вход для сети - это двумерный тензор с формой [28, 28], а вывод - это одномерный тензор с формой [10], который является результатом функции softmax.

После того, как сетьбыл обучен, я хочу использовать оптимизатор для другой задачи: найти вход, который максимизирует один из элементов выходного тензора.Как это может быть сделано?Возможно ли это сделать с помощью Keras или нужно использовать API более низкого уровня?

Поскольку входные данные не являются уникальными для данного выходного сигнала, было бы еще лучше, если бы мы могли наложить некоторые ограничения на значениявход может принимать.

Обученная модель имеет следующий формат

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

Ответы [ 5 ]

0 голосов
/ 07 октября 2018

Это было бы очень похоже на способ визуализации фильтров сверточной сети: мы бы сделали градиентное восхождение оптимизацию в пространство ввода в максимизацию ответа конкретного фильтра.

Вот как это сделать: после окончания обучения сначала нам нужно указать выходные данные и определить функцию потерь, которую мы хотим максимизировать:

from keras import backend as K

output_class = 0 # the index of the output class we want to maximize
output = model.layers[-1].output
loss = K.mean(output[:,output_class]) # get the average activation of our desired class over the batch

Далее нам нужно взять градиент потерь, который мы определили выше, относительно входного слоя:

grads = K.gradients(loss, model.input)[0] # the output of `gradients` is a list, just take the first (and only) element

grads = K.l2_normalize(grads) # normalize the gradients to help having an smooth optimization process

Далее нам нужно определить бэкэнд-функцию, которая берет исходное входное изображение и даетзначения потерь и градиентов в качестве выходных данных, чтобы мы могли использовать их на следующем шаге для реализации процесса оптимизации:

func = K.function([model.input], [loss, grads])

Наконец, мы реализуем процесс оптимизации подъема градиента:

import numpy as np

input_img = np.random.random((1, 28, 28)) # define an initial random image

lr = 1.  # learning rate used for gradient updates
max_iter = 50  # number of gradient updates iterations
for i in range(max_iter):
    loss_val, grads_val = func([input_img])
    input_img += grads_val * lr  # update the image based on gradients

Обратите внимание, что после завершения этого процесса для отображения изображения может потребоваться убедиться, что все значения на изображении находятся в диапазоне [0, 255] (или [0,1]).

0 голосов
/ 06 октября 2018

Забавное совпадение: я просто работал над той же «проблемой».Я заинтересован в направлении состязательного обучения и т. Д. Что я сделал, так это вставил слой LocallyConnected2D после ввода, а затем обучился с данными, которые все едины и имеют в качестве целей интересующий класс.

В качестве модели я использую

batch_size = 64
num_classes = 10
epochs = 20
input_shape = (28, 28, 1)


inp = tf.keras.layers.Input(shape=input_shape)
conv1 = tf.keras.layers.Conv2D(32, kernel_size=(3, 3),activation='relu',kernel_initializer='he_normal')(inp)
pool1 = tf.keras.layers.MaxPool2D((2, 2))(conv1)
drop1 = tf.keras.layers.Dropout(0.20)(pool1)
flat  = tf.keras.layers.Flatten()(drop1)
fc1   = tf.keras.layers.Dense(128, activation='relu')(flat)
norm1 = tf.keras.layers.BatchNormalization()(fc1)
dropfc1 = tf.keras.layers.Dropout(0.25)(norm1)
out   = tf.keras.layers.Dense(num_classes, activation='softmax')(dropfc1)

model = tf.keras.models.Model(inputs = inp , outputs = out)

model.compile(loss=tf.keras.losses.categorical_crossentropy,
              optimizer=tf.keras.optimizers.RMSprop(),
              metrics=['accuracy'])
model.summary()

после тренировки, я вставляю новый слой

def insert_intermediate_layer_in_keras(model,position, before_layer_id):
    layers = [l for l in model.layers]

    if(before_layer_id==0) :
        x = new_layer
    else:
        x = layers[0].output
    for i in range(1, len(layers)):
        if i == before_layer_id:
            x = new_layer(x)
            x = layers[i](x)

        else:
            x = layers[i](x)

    new_model = tf.keras.models.Model(inputs=layers[0].input, outputs=x)
    return new_model

def fix_model(model):
    for l in model.layers:
        l.trainable=False


fix_model(model)    
new_layer = tf.keras.layers.LocallyConnected2D(1, kernel_size=(1, 1),
                                               activation='linear',
                                               kernel_initializer='he_normal',
                                                use_bias=False)
new_model = insert_intermediate_layer_in_keras(model,new_layer,1)
new_model.compile(loss=tf.keras.losses.categorical_crossentropy,
              optimizer=tf.keras.optimizers.RMSprop(),
              metrics=['accuracy'])

и, наконец, перезапускаю тренировку с моими поддельными данными.

X_fake = np.ones((60000,28,28,1))
print(Y_test.shape)
y_fake = np.ones((60000))
Y_fake = tf.keras.utils.to_categorical(y_fake, num_classes)
new_model.fit(X_fake, Y_fake, epochs=100)
weights = new_layer.get_weights()[0]

imshow(weights.reshape(28,28))
plt.show()

Результаты еще не удовлетворяют, но я уверен в подходе и думаю, что мне нужно поиграть с оптимизатором.

0 голосов
/ 06 октября 2018

Я чувствую, что вы захотите сделать бэкпроп в отношении ввода, замораживающего все веса вашей модели.Что вы могли бы сделать:

  1. Добавьте плотный слой после входного слоя с такими же размерами, как у входного, и установите его как обучаемый
  2. Заморозьте все остальные слои вашей модели.(кроме того, который вы добавили)
  3. В качестве входных данных введите матрицу идентификаторов и обучите свою модель на основе любого желаемого результата.

Эта статья и Эта публикация может помочь вам, если вы хотите сделать бэкпроп на основе введенных данных.Это немного похоже на то, к чему вы стремитесь, но вы можете получить интуицию.

0 голосов
/ 06 октября 2018

После намеков, которые Сакет Кумар Сингх дал в своем ответе, я написал следующее, что, похоже, решает вопрос:

Я создаю два пользовательских слоя.Возможно, Keras уже предлагает некоторые классы, которые им эквивалентны.

Первый из них - обучаемый вход:

class MyInputLayer(keras.layers.Layer):
    def __init__(self, output_dim, **kwargs):
        self.output_dim = output_dim
        super(MyInputLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.kernel = self.add_weight(name='kernel',
                                      shape=self.output_dim,
                                      initializer='uniform',
                                      trainable=True)
        super(MyInputLayer, self).build(input_shape)

    def call(self, x):
        return self.kernel

    def compute_output_shape(self, input_shape):
        return self.output_dim

Второй получает вероятность интересующей метки:

class MySelectionLayer(keras.layers.Layer):
    def __init__(self, position, **kwargs):
        self.position = position
        self.output_dim = 1
        super(MySelectionLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        super(MySelectionLayer, self).build(input_shape)

    def call(self, x):
        mask = np.array([False]*x.shape[-1])
        mask[self.position] = True
        return tf.boolean_mask(x, mask,axis=1)

    def compute_output_shape(self, input_shape):
        return self.output_dim

Я использовал их таким образом:

# Build the model
layer_flatten =  keras.layers.Flatten(input_shape=(28, 28))
layerDense1 = keras.layers.Dense(128, activation=tf.nn.relu)
layerDense2 = keras.layers.Dense(10, activation=tf.nn.softmax)
model = keras.Sequential([
    layer_flatten,
    layerDense1,
    layerDense2
])

# Compile the model
model.compile(optimizer=tf.train.AdamOptimizer(),
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# Train the model
# ...

# Freeze the model
layerDense1.trainable = False
layerDense2.trainable = False

# Build another model
class_index = 7

layerInput =  MyInputLayer((1,784))
layerSelection = MySelectionLayer(class_index)

model_extended = keras.Sequential([
    layerInput,
    layerDense1,
    layerDense2,
    layerSelection
])

# Compile it
model_extended.compile(optimizer=tf.train.AdamOptimizer(),
              loss='mean_absolute_error')

# Train it
dummyInput = np.ones((1,1))
target = np.ones((1,1))
model_extended.fit(dummyInput, target,epochs=300)

# Retrieve the weights of layerInput
layerInput.get_weights()[0]
0 голосов
/ 06 октября 2018

Интересно.Возможно, решением было бы передать все ваши данные в сеть и для каждого образца сохранить output_layer после softmax.

Таким образом, для 3 классов , где вы хотитенайти лучший вход для класс 1 , вы ищете выходы, где первый компонент высокий.Например: [1 0 0]

Действительно, результат означает вероятность или доверие сети для выборки, являющейся одним из классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...