代码之家  ›  专栏  ›  技术社区  ›  toliveira

使用keras和tensorflow找到使神经网络输出最大化的输入

  •  1
  • toliveira  · 技术社区  · 6 年前

    我用了Keras和Tensorflow来分类 Fashion MNIST 下列的 this tutorial .

    它使用 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 回复  |  直到 6 年前
        1
  •  4
  •   Saket Kumar Singh    6 年前

    我觉得你应该考虑到输入冻结你的模型的所有重量。你能做的是:

    1. 在输入层之后添加一个与输入尺寸相同的密集层,并将其设置为可训练
    2. 冻结模型的所有其他层。(您添加的除外)
    3. 作为一个输入,输入一个身份矩阵,并根据你想要的输出来训练你的模型。

    This 条款和 this 如果你想基于输入来支持post,它可能会帮助你。这有点像你的目标,但你可以得到直觉。

        2
  •  3
  •   today    6 年前

    它将非常类似于卷积网络的过滤器的可视化方式:我们将 梯度上升 优化 输入空间 最大化响应 一种特殊的过滤器。

    方法如下:培训结束后,首先需要指定输出并定义要最大化的损失函数:

    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]范围内。

        3
  •  0
  •   Francesco Pegoraro    6 年前

    很有趣。也许一个解决方案是将所有数据传送到网络,并为每个示例保存 output_layer 之后 softmax .

    这边,因为 3类 ,您希望在其中找到 一级 ,您正在查找第一个组件高的输出。例如: [1 0 0]

    实际上,输出意味着网络的概率或置信度,因为样本是类之一。

        4
  •  0
  •   toliveira    6 年前

    在萨克特·库马尔·辛格给出答案的暗示之后,我写了以下似乎能解决这个问题的文章。

    我创建了两个自定义层。也许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]
    
        5
  •  0
  •   CAFEBABE    6 年前

    有趣的巧合是我只是在处理同一个“问题”。我对对抗训练的方向很感兴趣。我所做的就是插入一个 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()
    

    结果还不令人满意,但我有信心的方法,我想我需要发挥与乐观者。