繁体   English   中英

如何删除模型 Tensorflow Keras 中的特定神经元

[英]How to remove a specific neuron inside Model Tensorflow Keras

有没有办法去除模型中的特定神经元?

例如,我有一个带有 512 个神经元的 Dense 层的模型。 有没有办法删除所有在list_indeces中有索引的神经元? 当然,移除一个神经元会影响下一层甚至前一层。

例子:

我在多篇论文中都有这个通用模型:

data_format = 'channels_last'
    input_shape = [28, 28, 1]
    max_pool = functools.partial(
        tf.keras.layers.MaxPooling2D,
        pool_size=(2, 2),
        padding='same',
        data_format=data_format)
    conv2d = functools.partial(
        tf.keras.layers.Conv2D,
        kernel_size=5,
        padding='same',
        data_format=data_format,
        activation=tf.nn.relu)
    model = tf.keras.models.Sequential([
        conv2d(filters=32, input_shape=input_shape),
        max_pool(),
        conv2d(filters=64),
        max_pool(),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(512, activation=tf.nn.relu),
        tf.keras.layers.Dense(10 if only_digits else 62),
    ])
    return model

假设从层tf.keras.layers.Dense(512, activation=tf.nn.relu)我想移除 100 个神经元,基本上将它们关闭。

当然,我将有一个新模型,层为tf.keras.layers.Dense(412, activation=tf.nn.relu)而不是tf.keras.layers.Dense(512, activation=tf.nn.relu)但是这个修改也应该传播到下一层的权重,因为从密集层的神经元到下一层的连接也被删除了。

关于如何这样做的任何意见? 我可以通过执行以下操作来手动执行此操作:

如果我正确理解,模型形状就是这个: [5, 5, 1, 32], [32], [5, 5, 32, 64], [64], [3136, 512], [512], [512, 62], [62]

所以我可以做这样的事情:

  1. 生成我需要的所有索引并在list_indices它们相同
  2. 访问层tf.keras.layers.Dense(512, activation=tf.nn.relu)的权重,并使用list_indices内的list_indices重创建张量
  3. 将新的权重张量分配给子模型的层tf.keras.layers.Dense(412, activation=tf.nn.relu)

问题是我不知道如何获得下一层权重的正确权重,这些权重对应于我刚刚创建的权重索引以及我应该分配给子模型下一层的权重。 我希望我已经清楚地解释了自己。

谢谢,莱拉。

您的操作在文献中被称为selective dropout ,实际上不需要每次都创建不同的模型,您只需要将所选神经元的输出乘以 0,这样下一层的输入就不会采用那些帐户中的激活。

请注意,如果您“关闭” Ln层中的一个神经元,它不会完全“关闭” Ln+1层中的任何神经元,假设两者都是完全连接的层(密集): Ln+1中的每个神经元层连接到前一层中的所有神经元。 换句话说,移除全连接(密集)层中的神经元不会影响下一层的维度。

您可以使用Multiply Layer (Keras)简单地实现此操作。 缺点是您需要学习如何使用Keras 函数式 API 还有其他方法但比这更复杂(例如自定义层),而且函数式 API 在许多方面都非常有用和强大,非常建议阅读!

你的模型会变成这样:

data_format = 'channels_last'
input_shape = [28, 28, 1]
max_pool = ...
conv2d = ...

# convert a list of indexes to a weight tensor
def make_index_weights(indexes):
    # converting indexes to a list of weights
    indexes = [ float(i not in indexes) for i in range(units) ]
    # converting indexes from list/numpy to tensor
    indexes = tf.convert_to_tensor(indexes)
    # reshaping to the correct format
    indexes = tf.reshape(indexes, (1, units))
    # ensuring it is a float tensor
    indexes = tf.cast(indexes, 'float32')
    return indexes

# layer builder utility
def selective_dropout(units, indexes, **kwargs):
    indexes = make_index_weights(indexes)
    dense = tf.keras.layers.Dense(units, **kwargs)
    mul = tf.keras.layers.Multiply()
    # return the tensor builder
    return lambda inputs: mul([ dense(inputs), indexes ])

input_layer = tf.keras.layers.Input(input_shape)
conv_1  = conv2d(filters=32, input_shape=input_shape)(input_layer)
maxp_1  = max_pool()(conv_1)
conv_2  = conv2d(filters=64)(maxp_1)
maxp_2  = max_pool()(conv_2)
flat    = tf.keras.layers.Flatten()(maxp_2)
sel_drop_1 = selective_dropout(512, INDEXES, activation=tf.nn.relu)(flat)
dense_2 = tf.keras.layers.Dense(10 if only_digits else 62)(sel_drop_1)
output_layer = dense2
model = tf.keras.models.Model([ input_layer ], [ output_layer ])
return model

现在你只需要根据你需要删除的那些神经元的索引来建立你的INDEXES列表。

在您的情况下,张量的形状为1x512因为密集层中有 512 个权重(单位/神经元),因此您需要为索引提供尽可能多的权重。 selective_dropout函数允许传递要丢弃的索引列表,并自动建立所需的张量。

例如,如果您想移除神经元 1, 10, 12,您只需将列表[1, 10, 12]传递给函数,它将生成一个1x512张量,这些位置为0.0 ,所有其他位置为1.0

编辑:

正如您所提到的,您严格需要减少模型中参数的大小。

每个密集层由关系y = Wx + B ,其中W是内核(或权重矩阵), B是偏置向量。 WINPUTxOUTPUT维度的矩阵,其中INPUT是最后一层输出形状, OUTPUT是层中神经元/单元/权重的数量; B只是一个维度为1xOUTPUT的向量(但我们对此不感兴趣)。

现在的问题是您在Ln层中丢弃了N神经元,这会导致Ln+1层中的NxOUTPUT权重下降。 让我们用一些数字来实事求是。 在你的情况下(假设only_digits为真)你开始:

Nx512 -> 512x10 (5120 weights)

并且在丢掉 100 个神经元之后(这意味着减少了 100*10=1000 个权重)

Nx412 -> 412x10 (4120 weights)

现在W矩阵的每一列都描述了一个神经元(作为一个维度等于前一层输出维度的权重向量,在我们的例子中是 512 或 412)。 矩阵的行代表前一层中的单个神经元。

W[0,0]表示第n层的第一个神经元和第n+1层的第一个神经元之间的关系。

  • W[0,0] -> 1st n, 1st n+1
  • W[0,1] -> 2nd n, 1st n+1
  • W[1,0] -> 1st n, 2nd n+1

等等。 因此,您可以从此矩阵中删除与您删除的神经元索引相关的所有行: index 0 -> row 0

您可以使用dense.kernel从密集层访问W矩阵作为张量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM