【问题标题】:Find input that maximises output of a neural network using Keras and TensorFlow使用 Keras 和 TensorFlow 查找最大化神经网络输出的输入
【发布时间】:2019-03-11 16:55:04
【问题描述】:

我已经使用 Keras 和 TensorFlow 对 Fashion MNISTthis 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)
])

【问题讨论】:

    标签: python tensorflow machine-learning neural-network keras


    【解决方案1】:

    我觉得你会想要对冻结所有权重到你的模型的输入进行反向传播。你可以做的是:

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

    This 文章和this 帖子如果您想根据输入进行反向传播,可能会为您提供帮助。这有点像你的目标,但你可以得到直觉。

    【讨论】:

    • 输入必须只是一个标量,1.,对吗?所以每个神经元只训练一个参数,即那个“位置”的输入值。
    • 嗨,@Anakhand,抱歉回复晚了。我不确定我是否在上下文中理解了你的问题。能否请您详细说明一下?
    • 假设有一个 $n$ 维度的输入空间,为了简单起见,让它平坦(只有一个轴)。然后我们想找到最大化模型输出的 $v \in \mathbb{R}^n$。通过添加一个没有偏差的“假”全连接线性层(没有激活),它接受一个维度为 1 的输入,一个值1. 的单个标量,该层将具有恰好 n 个参数,并且每个神经元的输出将只是其单个参数的值。我已经做了一个图表来说明它here(只有第一层,其余的忽略)。
    • 嘿@Anakhand,感谢您的解释。现在清楚多了。事实上,单位矩阵将执行完全相同的功能。由于在每一行中都会有一个标量值 1 与一个权重参数相互作用,所以它本质上会做同样的事情。
    【解决方案2】:

    这与卷积网络过滤器的可视化方式非常相似:我们将在输入空间中进行梯度上升优化以最大化响应 的特定过滤器。

    这是怎么做的:训练完成后,首先我们需要指定输出并定义一个我们想要最大化的损失函数:

    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】:

    在 Saket Kumar Singh 在他的回答中给出的提示之后,我写了以下似乎解决了问题的内容。

    我创建了两个自定义层。也许 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]
    

    【讨论】:

    • 我只是尝试实现一下,看看训练后输入如何变化,但没有奏效。能否请您也实施并发布前后结果?
    【解决方案4】:

    有趣。也许解决方案是将所有数据提供给网络,并为每个样本在softmax 之后保存output_layer

    这样,对于 3 类,您想为 1 类 找到最佳输入,您正在寻找第一个分量较高的输出。例如:[1 0 0]

    实际上,输出是指样本作为类别之一的概率或网络置信度。

    【讨论】:

      【解决方案5】:

      有趣的巧合是我正在研究同一个“问题”。我对对抗性训练等方向感兴趣。我所做的是在输入之后插入一个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()
      

      结果还不令人满意,但我对这种方法很有信心,我想我需要尝试一下优化器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-23
        • 1970-01-01
        • 1970-01-01
        • 2021-09-22
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多