我正在尝试在Tensorflow中实现线性回归模型,并加入额外的限制(来自领域),即W
和b
项必须为非负数。
我相信有几种方法可以做到这一点。
- 我们可以修改成本函数,以惩罚负权重[Lagrangian方法] [参见:TensorFlow-最佳实现权重约束的方法
- 我们可以自己计算梯度并将其投影到[0,无穷大] [投影梯度方法]
方法1:Lagrangian
当我尝试第一种方法时,我经常会得到负数的b
。
我已经从以下内容修改了成本函数:
cost = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)
to:
cost = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)
nn_w = tf.reduce_sum(tf.abs(W) - W)
nn_b = tf.reduce_sum(tf.abs(b) - b)
constraint = 100.0*nn_w + 100*nn_b
cost_with_constraint = cost + constraint
nn_b
nn_w
Here is the complete code.
import numpy as np
import tensorflow as tf
n_samples = 50
train_X = np.linspace(1, 50, n_samples)
train_Y = 10*train_X + 6 +40*np.random.randn(50)
X = tf.placeholder("float")
Y = tf.placeholder("float")
# Set model weights
W = tf.Variable(np.random.randn(), name="weight")
b = tf.Variable(np.random.randn(), name="bias")
# Construct a linear model
pred = tf.add(tf.multiply(X, W), b)
# Gradient descent
learning_rate=0.0001
# Initializing the variables
init = tf.global_variables_initializer()
# Mean squared error
cost = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)
nn_w = tf.reduce_sum(tf.abs(W) - W)
nn_b = tf.reduce_sum(tf.abs(b) - b)
constraint = 1.0*nn_w + 100*nn_b
cost_with_constraint = cost + constraint
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost_with_constraint)
training_epochs=200
with tf.Session() as sess:
sess.run(init)
# Fit all training data
cost_array = np.zeros(training_epochs)
W_array = np.zeros(training_epochs)
b_array = np.zeros(training_epochs)
for epoch in range(training_epochs):
for (x, y) in zip(train_X, train_Y):
sess.run(optimizer, feed_dict={X: x, Y: y})
W_array[epoch] = sess.run(W)
b_array[epoch] = sess.run(b)
cost_array[epoch] = sess.run(cost, feed_dict={X: train_X, Y: train_Y})
以下是在10个不同运行中
b
的平均值。0 -1.101268
1 0.169225
2 0.158363
3 0.706270
4 -0.371205
5 0.244424
6 1.312516
7 -0.069609
8 -1.032187
9 -1.711668
显然,第一种方法并不是最优的。此外,在选择惩罚项系数时需要有很多技巧。
方法二:投影梯度
然后我考虑使用第二种方法,这种方法更有保证可以奏效。
gr = tf.gradients(cost, [W, b])
我们手动计算梯度并更新W和b。
with tf.Session() as sess:
sess.run(init)
for epoch in range(training_epochs):
for (x, y) in zip(train_X, train_Y):
W_del, b_del = sess.run(gr, feed_dict={X: x, Y: y})
W = max(0, (W - W_del)*learning_rate) #Project the gradient on [0, infinity]
b = max(0, (b - b_del)*learning_rate) # Project the gradient on [0, infinity]
这种方法似乎非常缓慢。
我正在思考是否有更好的方法来运行第二种方法,或者保证第一种方法的结果。我们是否可以以某种方式允许优化器确保学习到的权重为非负数?
exp(b)
而不是b
...然后有效偏差将始终>0。 - etarionW
和b
都应该是非负的。那么您建议我们学习W
和b
的对数吗?这不会改变Y = W.X + b吗? - Nipun Batra