36

假设我们有权重

x = tf.Variable(np.random.random((5,10)))
cost = ...

我们使用 GD 优化器:

upds = tf.train.GradientDescentOptimizer(lr).minimize(cost)
session.run(upds)

例如,我们如何实现权重的非负性?

我试着剪掉它们:

upds = tf.train.GradientDescentOptimizer(lr).minimize(cost)
session.run(upds)
session.run(tf.assign(x, tf.clip_by_value(x, 0, np.infty)))

但这会使我的训练速度减慢 50 倍。

有人知道在 TensorFlow 中对权重实施此类约束的好方法吗?

PS:在等效的 Theano 算法中,我有

T.clip(x, 0, np.infty)

它运行顺利。

4

5 回答 5

26

您可以采用拉格朗日方法,只需为您不想要的变量的特征添加惩罚。

例如,为了鼓励 theta成为非负数,您可以将以下内容添加到优化器的目标函数中。

    added_loss = -tf.minimum( tf.reduce_min(theta),0)

如果任何一个theta为负数,则 add2loss 将为正数,否则为零。将其缩放为有意义的值留给读者作为练习。缩放太少不会施加足够的压力。太多可能会使事情变得不稳定。

于 2016-05-25T02:23:58.303 回答
23

从 TensorFlow 1.4 开始,有一个新参数允许tf.get_variable传递在优化器更新后应用的约束函数。这是一个强制执行非负约束的示例:

with tf.variable_scope("MyScope"):
  v1 = tf.get_variable("v1", …, constraint=lambda x: tf.clip_by_value(x, 0, np.infty))

约束:一个可选的投影函数,在被更新后应用于变量Optimizer(例如,用于实现层权重的范数约束或值约束)。该函数必须将表示变量值的未投影张量作为输入,并返回投影值的张量(必须具有相同的形状)。在进行异步分布式训练时使用约束是不安全的。

于 2017-11-08T21:10:07.653 回答
16

通过运行

sess.run(tf.assign(x, tf.clip_by_value(x, 0, np.infty)))

您一直在向图中添加节点并使其越来越慢。

实际上,您可以clip_op在构建图形时定义 a 并在每次更新权重后运行它:

# build the graph
x = tf.Variable(np.random.random((5,10)))
loss = ...
train_op = tf.train.GradientDescentOptimizer(lr).minimize(loss)
clip_op = tf.assign(x, tf.clip(x, 0, np.infty))

# train
sess.run(train_op)
sess.run(clip_op)
于 2017-03-31T06:02:46.463 回答
3

我最近也遇到了这个问题。我发现您可以导入具有很好的权重约束功能的 keras,因为它们可以直接在 tensorflow 的 kernen 约束中使用。这是我的代码示例。你可以用内核正则化器做类似的事情

from keras.constraints import non_neg

conv1 = tf.layers.conv2d(
    inputs=features['x'],
    filters=32,
    kernel_size=[5,5],
    strides = 2,
    padding='valid',
    activation=tf.nn.relu,
    kernel_regularizer=None,
    kernel_constraint=non_neg(),
    use_bias=False)
于 2018-04-26T22:30:26.360 回答
1

有一个实用的解决方案:您可以编写成本函数,将高成本置于负权重上。我在 TensorFlow 中使用 python 的矩阵分解模型中做到了这一点,并且效果很好。正确的?我的意思是这很明显。但是没有其他人提到它,所以你去吧。编辑:我刚刚看到 Mark Borderding 在我之前还提供了另一个基于损失和成本的解决方案实施。

如果想要“最好的方式”,正如 OP 所问的那样,那会怎样?好吧,“最佳”实际上可能是特定于应用程序的,在这种情况下,您需要对数据集尝试几种不同的方法并考虑应用程序要求。

这是增加不需要的负解变量成本的工作代码:

cost = tf.reduce_sum(keep_loss) + Lambda * reg # Cost = sum of losses for training set, except missing data.        
if prefer_nonneg: # Optionally increase cost for negative values in rhat, if you want that.
    negs_indices = tf.where(rhat < tf.constant(0.0))
    neg_vals = tf.gather_nd(rhat, negs_indices)
    cost += 2. * tf.reduce_sum(tf.abs(neg_vals))  # 2 is a magic number (empirical parameter)         

您可以自由使用我的代码,但如果您选择使用它,请给我一些信任。请在 stackoverflow.com 上提供此答案的链接。

这种设计将被视为软约束,因为如果允许,您仍然可以获得负权重,具体取决于您的成本定义。

似乎在 TF v1.4+ 中也可以使用 constraint= 作为 tf.get_variable() 的参数,您可以在其中传递像 tf.clip_by_value 这样的函数。在我看来,这似乎是另一个软约束,而不是硬约束,因为它取决于您的功能是否正常工作。它也可能很慢,因为其他回答者尝试了相同的功能并报告收敛速度很慢,尽管他们没有使用 constraint= 参数来执行此操作。我看不出有什么理由比另一个更快,因为它们都使用相同的裁剪方法。因此,如果您使用约束 = 参数,那么您应该期望在原始海报应用程序的上下文中收敛缓慢。

如果 TF 也为 API 提供真正的硬约束,并让 TF 弄清楚如何实现它并使其在后端高效,那就更好了。我的意思是,我已经在线性规划求解器中看到了这一点很长时间了。应用程序声明一个约束,后端让它发生。

于 2018-04-25T15:35:26.760 回答