如何冻结/锁定一个TensorFlow变量的权重(例如,一个层的一个CNN内核)

时间:2017-02-28 20:14:54

标签: tensorflow pruning

我有一个表现良好的TensorFlow CNN模型,我们希望在硬件中实现这个模型;即FPGA。这是一个相对较小的网络,但如果它更小,它将是理想的。有了这个目标,我已经检查了内核,发现有一些权重非常强,还有一些根本没有做太多(内核值都接近于零)。这特别发生在第2层,对应于名为“W_conv2”的tf.Variable()。 W_conv2具有形状[3,3,32,32]。我想冻结/锁定W_conv2 [:,:,29,13]的值并将它们设置为零,以便可以训练网络的其余部分进行补偿。将此内核的值设置为零可以有效地从硬件实现中删除/修剪内核,从而实现上述目标。

我发现了类似的问题,建议通常围绕两种方法之一;

建议#1:

    tf.Variable(some_initial_value, trainable = False)

实现此建议会冻结整个变量。我想冻结一个切片,特别是W_conv2 [:,:,29,13]。

建议#2:

    Optimizer = tf.train.RMSPropOptimizer(0.001).minimize(loss, var_list)

同样,实施此建议不允许使用切片。例如,如果我按照以下方式尝试我所述目标的反转(仅优化单个变量的单个内核):

    Optimizer = tf.train.RMSPropOptimizer(0.001).minimize(loss, var_list = W_conv2[:,:,0,0]))

我收到以下错误:

    NotImplementedError: ('Trying to optimize unsupported type ', <tf.Tensor 'strided_slice_2228:0' shape=(3, 3) dtype=float32>)

以我在这里尝试过的方式切换tf.Variables()是不可能的。我尝试过的唯一可以接近做我想要的就是使用.assign(),但这是非常低效,笨重,和穴居人一样,因为我已经按照以下方式实现了它(在训练模型之后):

    for _ in range(10000):
        # get a new batch of data
        # reset the values of W_conv2[:,:,29,13]=0 each time through
        for m in range(3):
            for n in range(3):
                assign_op = W_conv2[m,n,29,13].assign(0)
                sess.run(assign_op)
        # re-train the rest of the network
        _, loss_val = sess.run([optimizer, loss], feed_dict = {
                                   dict_stuff_here
                               })
        print(loss_val)

该模型在Keras开始,然后转移到TensorFlow,因为Keras似乎没有达到预期结果的机制。我开始认为TensorFlow不允许修剪,但发现这很难相信;它只需要正确的实施。

1 个答案:

答案 0 :(得分:1)

一种可能的方法是用零初始化这些特定的权重,并修改最小化过程,以使梯度不会应用于它们。可以通过将对minimize()的调用替换为以下内容来完成:

W_conv2_weights = np.ones((3, 3, 32, 32))
W_conv2_weights[:, :, 29, 13] = 0
W_conv2_weights_const = tf.constant(W_conv2_weights)

optimizer = tf.train.RMSPropOptimizer(0.001)

W_conv2_orig_grads = tf.gradients(loss, W_conv2)
W_conv2_grads = tf.multiply(W_conv2_weights_const, W_conv2_orig_grads)
W_conv2_train_op = optimizer.apply_gradients(zip(W_conv2_grads, W_conv2))

rest_grads = tf.gradients(loss, rest_of_vars)
rest_train_op = optimizer.apply_gradients(zip(rest_grads, rest_of_vars))

tf.group([rest_train_op, W_conv2_train_op])

  1. 准备一个常数张量以消除适当的梯度
  2. 仅对W_conv2计算梯度,然后将元素与常数W_conv2_weights相乘以将适当的梯度归零,然后才应用梯度。
  3. “正常”计算梯度并将其应用于其余变量。
  4. 将2个训练项目组合为一个训练项目。