使用SparseTensor作为可训练变量?

时间:2016-05-03 10:28:56

标签: neural-network sparse-matrix tensorflow

我尝试使用 SparseTensor 在完全连接的图层中表示重量变量。
但是,似乎TensorFlow 0.8不允许将SparseTensor用作tf.Variable。
有没有办法解决这个问题?

我已经尝试了

import tensorflow as tf

a = tf.constant(1)
b = tf.SparseTensor([[0,0]],[1],[1,1])

print a.__class__  # shows <class 'tensorflow.python.framework.ops.Tensor'>
print b.__class__  # shows <class 'tensorflow.python.framework.ops.SparseTensor'>

tf.Variable(a)     # Variable is declared correctly
tf.Variable(b)     # Fail

顺便说一句,我使用SparseTensor的最终目标是永久地屏蔽密集形式的一些连接。因此,在计算和应用渐变时,忽略了这些修剪过的连接

在我目前的MLP实现中,SparseTensor及其稀疏形式的 matmul ops成功报告推理输出。但是,使用SparseTensor声明的权重不会作为训练步骤进行训练。

4 个答案:

答案 0 :(得分:2)

TensorFlow目前不支持稀疏张量变量。但是,它确实支持密集变量的稀疏查找(tf.embedding_lookup)和稀疏梯度更新(tf.sparse_add)。我怀疑这两个就足够了你的用例。

答案 1 :(得分:2)

作为解决问题的方法,您可以为稀疏张量的值提供tf.Variable(直到Tensorflow v0.8)。在这种情况下,稀疏结构必须预先定义,但重量仍然可以训练。

weights = tf.Variable(<initial-value>)
sparse_var = tf.SparseTensor(<indices>, weights, <shape>)  # v0.8
sparse_var = tf.SparseTensor(<indices>, tf.identity(weights), <shape>)  # v0.9

答案 2 :(得分:1)

TensorFlow还不支持稀疏张量训练。您可以根据需要初始化稀疏张量,然后将其转换为密集张量并从中创建变量:

# You need to correctly initialize the sparse tensor with indices, values and a shape   

b = tf.SparseTensor(indices, values, shape)
b_dense = tf.sparse_tensor_to_dense(b)
b_variable = tf.Variable(b_dense)

现在您已将稀疏张量初始化为变量。现在你需要处理渐变更新(换句话说,确保变量中的条目保持为0,因为在使用它时,在反向传播算法中计算出非消失梯度)。

为了做到这一点,TensorFlow优化器有一个名为 tf.train.Optimizer.compute_gradients(loss,[list_of_variables])的方法。这将计算图表中最小化损失函数所需的所有梯度,但尚未应用它们。此方法以(渐变,变量)的形式返回元组列表。您可以自由地修改这些渐变,但在您的情况下,将不需要的渐变屏蔽为0是有意义的(即通过创建另一个稀疏张量,默认值为0.0,值为1.0,其中存在网络中的权重)。 修改它们之后,调用优化程序方法 tf.train.Optimizer.apply_gradients(grads_and_vars)来实际应用渐变。示例代码如下所示:

# Create optimizer instance
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)

# Get the gradients for your weights
grads_and_vars = optimizer.compute_gradients(loss, [b_variable])

# Modify the gradients at will
# In your case it would look similar to this
modified_grads_and_vars = [(tf.multiply(gv[0], mask_tensor), gv[1] for gv in grads_and_vars]

# Apply modified gradients to your model
optimizer.apply_gradients(modified_grads_and_vars)

这可确保您的条目在权重矩阵中保持为0,并且不会创建不需要的连接。您需要在以后处理所有其他变量的所有其他渐变。

答案 3 :(得分:0)

上面的代码可以像这样进行一些小修改。

def optimize(loss, mask_tensor):
    optimizer = tf.train.AdamOptimizer(0.001)
    grads_and_vars = optimizer.compute_gradients(loss)
    modified_grads_and_vars = [
        (tf.multiply(gv[0], mask_tensor[gv[1]]), gv[1]) for gv in grads_and_vars
    ]
    return optimizer.apply_gradients(modified_grads_and_vars)