[英]How to run Keras.model() for prediction inside a tensorflow session?
[英]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]
所以我可以做这样的事情:
list_indices
它们相同tf.keras.layers.Dense(512, activation=tf.nn.relu)
的权重,并使用list_indices
内的list_indices
重创建张量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
是偏置向量。 W
是INPUTxOUTPUT
维度的矩阵,其中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.