将权重从一个conv2d层复制到另一层



上下文

我已经使用Keras培训了MNIST模型。我的目标是在第一层之后打印图像,第一层是Conv2D层。为了解决这个问题,我正在创建一个新模型,其中一个Conv2D层将在其中将训练网络的权重复制到新的网络中。

# Visualization for image ofter first convolution
model_temp = Sequential()
model_temp.add(Conv2D(32, (3, 3),
                         activation='relu', 
                         input_shape=(28,28,1,)))
trained_weights = model.layers[0].get_weights()[0]
model_temp.layers[0].set_weights(trained_weights)
activations = model_temp._predict(X_test)

可变model持有来自完整网络的训练有素的数据。另外,Conv2D的输入参数与原始模型中的输入参数完全相同。

我已经检查了modelmodel_temp的权重的形状,并以(3, 3, 1, 32)返回。从理论上讲,我应该能够从原始模型中获取权重,并将其直接输入新模型中单个Conv2D层的set_weights()调用中。

在此卷积之后,命名为"激活"的变量将是一个张量,可容纳32(层),26乘26矩阵的每个输入图像的输出值的矩阵。


错误

所以当我运行此代码时,我会收到此错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-152-4ae260f0fe89> in <module>()
      7 trained_weights = model.layers[0].get_weights()[0]
      8 print(trained_weights.shape)
----> 9 model_test = model_test.layers[0].set_weights(trained_weights)
     10 
     11 activations = model_test._predict(X_test[1, 28, 28, 1])
/usr/local/lib/python2.7/dist-packages/keras/engine/topology.pyc in set_weights(self, weights)
   1189                              str(len(params)) +
   1190                              ' weights. Provided weights: ' +
-> 1191                              str(weights)[:50] + '...')
   1192         if not params:
   1193             return
ValueError: You called `set_weights(weights)` on layer "conv2d_60" with a  weight list of length 3, but the layer was expecting 2 weights. Provided weights: [[[[ -6.22274876e-01  -2.18614027e-01   5.29607059...

在最后一行,为什么set_weights(weights)要寻找两个长度而不是三个?此错误消息对我来说有点神秘,因此,如果不是两个,则"期望两个权重"是什么意思?

我也愿意接受更轻松的方法的建议。


进一步研究

检查get_weights()(第1168行)的源代码后,在本节中提出了错误:

 params = self.weights
    if len(params) != len(weights):
        raise ValueError('You called `set_weights(weights)` on layer "' +
                         self.name +
                         '" with a  weight list of length ' +
                         str(len(weights)) +
                         ', but the layer was expecting ' +
                         str(len(params)) +
                         ' weights. Provided weights: ' +
                         str(weights)[:50] + '...')

此条件检查确定我传递的长度( (3, 3, 1, 32)张量)是否等同于此类的权重属性。因此,我测试了这些属性如下:

# Print contents of weights property
print(model.layers[0].weights)
print(model_test.layers[0].weights)
# Length test of tensors from get_weights call
len_test  = len(model.layers[0].get_weights()[0])
len_test2 = len(model_test.layers[0].get_weights()[0])
print("nLength get_weights():")
print("Trained Model: ", len_test, "Test Model: ", len_test2)
# Length test of wights attributes from both models
len_test3 = len(model.layers[0].weights)
len_test4 = len(model_test.layers[0].weights)
print("nLength weights attribute:")
print("Trained Model: ", len_test3, "Test Model: ", len_test4)

输出:

[<tf.Variable 'conv2d_17/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>,         <tf.Variable 'conv2d_17/bias:0' shape=(32,) dtype=float32_ref>]
[<tf.Variable 'conv2d_97/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>, <tf.Variable 'conv2d_97/bias:0' shape=(32,) dtype=float32_ref>]
Length get_weights():
('Trained Model: ', 3, 'Test Model: ', 3)
Length weights attribute:
('Trained Model: ', 2, 'Test Model: ', 2)

此输出对我来说是一百%有意义的,因为每个模型中的这些卷积均完全相同。现在也很明显为什么要长时间。这是因为权重属性是tf.Variable的两个元素的列表。

进一步研究此源文件,在第213行中,我们看到权重有"列表的串联trainable_weights和non_trainable_weights(按此顺序)"。

因此,请确保我可以从原始训练的模型的Conv2D层中获取权重属性,并将其传递给以满足此条件,但是这种情况根本没有检查数据中传递的形状。如果我确实从原始型号传递了权重,我会从numpy中获得setting an array element with a sequence错误。

思想

我认为这是源代码中的错误。如果有人可以验证这一点,我会很棒。

您忘记了偏见向量。get_weights()和set_weights()的conv2d函数返回一个列表,将striges矩阵作为第一个元素,而偏置向量为第二。因此,错误正确地表明它希望有2个成员的列表。这样做应该有效

trained_weights = model.layers[0].get_weights()
model_temp.layers[0].set_weights(trained_weights)

另外,如果您想从中间层获得输出,则无需手动传输权重。做类似关注的事情更便宜

get_layer_output = K.function([model.input],
                                  [model.layers[0].output])
layer_output = get_layer_output([x])[0]

intermediate_layer_model = Model(inputs=model.input,
                                 outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(data)

最新更新