首页 文章

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

提问于
浏览
3

上下文

我使用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个输出值的矩阵 .


错误

因此,当我运行此代码时,我收到此错误:

---------------------------------------------------------------------------
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) 寻找长度为2而不是3?这个错误信息对我来说有点神秘,所以如果不是两个长度"expecting two weights"是什么意思?

此外,我愿意接受更简单的方法来解决这个问题 .


经过进一步调查

在检查source code for 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) 张量)是否等于此类的weights属性 . 所以我测试了这些属性如下:

# 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)

这个输出对我来说是百分之百的意义,因为每个模型中的这些卷积构造完全相同 . 现在也很明显为什么它需要两个长度 . 这是因为weights属性是 tf.Variable 的两个元素的列表 .

进一步调查这个源文件,在第213行,我们看到权重保持“列表trainable_weights和non_trainable_weights(按此顺序)的串联” .

那么我确定我可以从原始训练模型的 Conv2D 层中获取权重属性并将其传递给满足此条件但是此条件根本不检查传入数据的形状 . 如果我从原始模型传递权重,我会从numpy中得到 setting an array element with a sequence 错误 .

想法

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

1 回答

  • 0

    你忘记了偏向量 . conv2d的Get_weights()和set_weights()函数返回一个列表,其中权重矩阵作为第一个元素,偏差矢量作为第二个元素 . 所以错误正确地表明它需要一个包含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)
    

相关问题