【问题标题】:Specific linear classifier in TensorFlow: input element as vectorTensorFlow中的特定线性分类器:输入元素作为向量
【发布时间】:2019-10-11 21:27:32
【问题描述】:

如何在 TensorFlow 中实现这样的线性分类器:

x1*w1 + x2*w2 + x3*w3 = y_pred,

其中 x1、x2、x3 - 向量和 w1、w2 和 w3 - 标量?

对于 x1、x2、x3 - 标量 (link) 的情况,我有很好的教程,

但是对于 x1、x2、x3 是向量的情况,我没有实现的想法。

更新

也就是说我正在尝试实现以下模型:

x1*w1+ x2*w1+x3*w1+x4*w2+x5*w2+x6*w2+x7*w3+x8*w3+x9*w3=y_pred, 
where x1..x9 and w1..w9 are scalars.

【问题讨论】:

  • 可疑...我认为权重(w1w2w3)是矩阵。
  • @GyuHyeonChoi 也许标签也是向量? ...
  • @meTchaikovsky 这取决于。通常,深度学习中模型的prediction 表示类的概率分布。因此,它是一个具有类数维数的向量。更实际的是,模型的预测是矩阵,形状为size_of_batch * number_of_classes
  • @GyuHyeonChoi 你说得对,我还没想过这个。
  • @meTchaikovsky 你是这个问题的作者吗?我不知道你到底想做什么。如果你给我细节,我想我可以帮助你。

标签: python tensorflow logistic-regression multilabel-classification


【解决方案1】:

要实现的线性多类分类器:

pred = w1 * (x1 + x2 + x3) + w2 * (x4 + x5 + x6) + w3 * (x7 + x8 + x9)

其中所有变量都是标量。

在此模型中,由于pred 是一个标量,因此您不能使用交叉熵损失来训练分类器pred 不是分布)。 您必须将其视为回归问题。

示例数据集

import numpy as np

x1 = np.ones((100, 3)) # for w1
x2 = np.ones((100, 3)) * 2 # for w2
x3 = np.ones((100, 3)) * 3 # for w3

# set(y) is {0, 1, 2, 3}, corresponds to the four class labels 
y = np.random.randint(0, 4, 100).reshape(-1, 1)

例如tensorflow代码:

import tensorflow as tf 

tf.reset_default_graph()

f1 = tf.placeholder('float32', shape=[None, 3], name='f1')
f2 = tf.placeholder('float32', shape=[None, 3], name='f2')
f3 = tf.placeholder('float32', shape=[None, 3], name='f3')

target = tf.placeholder('float32', shape=[None, 1], name='target')

# the three scalars
w1 = tf.get_variable('w1', shape=[1], initializer=tf.random_normal_initializer())
w2 = tf.get_variable('w2', shape=[1], initializer=tf.random_normal_initializer())
w3 = tf.get_variable('w3', shape=[1], initializer=tf.random_normal_initializer())

pred_1 = tf.reduce_sum(tf.multiply(f1, w1), axis=1)
pred_2 = tf.reduce_sum(tf.multiply(f2, w2), axis=1)
pred_3 = tf.reduce_sum(tf.multiply(f3, w3), axis=1)

# till now the linear classifier has been constructed 
# pred = w1(x1 + x2 + x3) + w2(x4 + x5 + x6) + w3(x7 + x8 + x9)
pred = tf.add_n([pred_1, pred_2, pred_3])

# treat it as a regression problem
loss = tf.reduce_mean(tf.square(pred - target))

optimizer = tf.train.GradientDescentOptimizer(1e-5)
updates = optimizer.minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for t in range(50):
        loss_val, _ = sess.run([loss, updates], 
                               feed_dict={f1: x1, f2: x2, f3: x3, target: y})
        print(t, loss_val)

下面是一个使用交叉熵损失来训练多类分类器的简单示例。如你所见,这个模型是一个神经网络模型

import numpy as np
import tensorflow as tf 

x1 = np.ones((100, 3)) # for w1
x2 = np.ones((100, 3)) * 2 # for w2
x3 = np.ones((100, 3)) * 3 # for w3

y = np.random.randint(0, 4, 400).reshape(100, 4)

tf.reset_default_graph()

f1 = tf.placeholder('float32', shape=[None, 3], name='f1')
f2 = tf.placeholder('float32', shape=[None, 3], name='f2')
f3 = tf.placeholder('float32', shape=[None, 3], name='f3')

target = tf.placeholder('float32', shape=[None, 4], name='target')

# the three scalars
w1 = tf.get_variable('w1', shape=[1], initializer=tf.random_normal_initializer())
w2 = tf.get_variable('w2', shape=[1], initializer=tf.random_normal_initializer())
w3 = tf.get_variable('w3', shape=[1], initializer=tf.random_normal_initializer())

w = tf.get_variable('w', shape=[3, 4], initializer=tf.random_normal_initializer())

pred_1 = tf.reduce_sum(tf.multiply(f1, w1), axis=1)
pred_2 = tf.reduce_sum(tf.multiply(f2, w2), axis=1)
pred_3 = tf.reduce_sum(tf.multiply(f3, w3), axis=1)

pred = tf.stack([pred_1, pred_2, pred_3], axis=1)
pred = tf.matmul(pred, w)
loss = tf.losses.softmax_cross_entropy(onehot_labels=target, logits=pred)

optimizer = tf.train.GradientDescentOptimizer(1e-5)
updates = optimizer.minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for t in range(50):
        loss_val, _ = sess.run([loss, updates], 
                               feed_dict={f1: x1, f2: x2, f3: x3, target: y})
        print(t, loss_val)

【讨论】:

  • 谢谢!我需要一些时间来测试您的解决方案
  • 如果我需要解决的不是二分类问题,而是四类分类问题,代码会有什么变化?
  • 谢谢!请解释为什么将权重的数量从三个增加到四个?毕竟特征向量的个数是三个,所以应该有三个权重因子
  • @V.Gai 对不起,我误解了你的模型,我已经编辑了我的答案:)
  • @V.Gai 您好 V.Gai,实际上,我对我的回答并不满意,基本上,我不太了解您的模型。您的意思是您仍想使用x1 * w1 + ... + x9 * w3 = y 进行多类分类吗?不得不说这个模型有点怪......
【解决方案2】:

我使用创建了一个看起来像 [w1, w1, w1, w2, w2, w2 ...] 的数组,并在将所有项相加之前将它(按元素)乘以 x。我无法让 model.fit 工作,所以我从 https://www.tensorflow.org/tutorials/quickstart/advanced 复制了 train_step 代码。它似乎工作得很好。我把我的测试代码留在了底部供你检查。

这利用了 tensorlfow 2.0 以及与 keras 模型的集成

import numpy as np 
import tensorflow as tf

from tensorflow.keras import Model
from tensorflow.keras.losses import MeanSquaredError
from tensorflow.keras.optimizers import Adam

print(tf.executing_eagerly())

class ProductAdd(Model):
    def __init__(self):
        super(ProductAdd, self).__init__()
        self.vars = list(np.empty([3])) # Creates an empty list (same as [ , , ])
        for i in range(3):
            self.vars[i] = tf.Variable(      # Creates 3 variables to act as weights 
                np.random.standard_normal(), # Assigns variables random value to start
                 name='var'+str(i))          # Names them var0 var1...

    def call(self, x):
        extended_vars = [self.vars[int(np.floor(i/3))] # "Extends" var array to look like:
                          for i in range(9)]           # [w1, w1, w1, w2, w2, w2, w3, w3, w3]
        return np.sum(np.multiply(x, extended_vars))   # Perfoms element-wise multiplication on x and sums

loss_object = MeanSquaredError()    # Create loss and optimizer
optimizer = Adam()

@tf.function                                        # This function perfoms trains the model
def train_step(images, labels):                     # I got it from https://www.tensorflow.org/tutorials/quickstart/advanced
  with tf.GradientTape() as tape:                   
    predictions = model(images)                     
    loss = loss_object(labels, predictions)
  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

model = ProductAdd()

for _ in range(100):
    train_step([1.0, 2.0 ,3.0 ,4.0, 5.0, 6.0, 7.0, 8.0, 9.0], [0.0])

print(model([1.0, 2.0 ,3.0 ,4.0, 5.0, 6.0, 7.0, 8.0, 9.0]).numpy())

【讨论】:

  • 谢谢!您的代码在优化过程中有限制 w1_1 = w1_2 = w1_3 和 w2_1 = w2_2 = w2_3 和 w3_1 = w3_2 = w3_3 吗?还是所有的权重因子(九项)都单独优化?
  • __init__ 中创建的只有三个变量需要优化。只有在call 中,这些变量才会被临时克隆以完成功能。这些克隆仅在call 范围内,不会保存为模型变量,因此模型中仍然只保留三个变量。
  • 你能在这里给出运行命令“print(model([1.0, 2.0 ,3.0,4.0, 5.0, 6.0, 7.0, 8.0, 9.0]).numpy())" 的结果吗?
【解决方案3】:

这个问题不恰当。您说您希望 x_1、x_2、x_3 成为向量,但是尚不清楚您将如何处理 w_1、w_2、w_3。有两种可能。

  • 如果您想将它们保留为标量,正如您的问题似乎暗示的那样,那么该模型并不是真正的矢量模型,您只是对所有条目进行相同的标量操作x 向量,但一次。这相当于一个标量模型。

  • 否则,如果标签是标量,您可以将 w_1、w_2、w_3 定义为矩阵或行向量。在这种情况下,没有理由像你写的那样写方程,因为你可以将 xs 堆叠在一个向量中,将 ws 堆叠在一个向量中并写为 wx = y。无论如何,这是一个多元线性回归,您可以在其中找到许多示例,以及如何在 Tensorflow 和 Torch 中解决它的教程。

更新,鉴于 OP 的澄清

在您的评论中,您现在说您有兴趣解决以下等式:

w1*(x1 + x2 + x3) + w2*(x4 + x5 + x6) + w3*(x7 + x8 + x9) == y

所有变量都是标量。注意 x 变量是已知的,所以我们可以定义(一个简单的算术运算):

z1 = x1 + x2 + x3; z2 = x4 + x5 + x6; z3 = x7 + x8 + x9

等式变成了

w1*z1 + w2*z2 + w3*z3 = y.

所以这更像是一个线性代数问题而不是张量流/火炬问题,因为这个方程可以解析求解,不需要数值拟合。然而,它仍然是不明确的,因为它对于一个线性方程有 3 个未知数(w1、w2、w3)。所以它不会有唯一的解决方案,而是一个二维线性空间的解决方案(它标识了 3 维 w 空间中的一个平面)。要得到一些解,你可以任意决定设置,例如w1 = w2 = 0,从中你会自动得到w3 = z3/y。然后对另外两个做同样的事情,你会得到三个不同的线性独立的解决方案。

希望这会有所帮助。总之,你根本不需要代码。

第二次更新(来自评论)

为什么需要使用优化来解决?如果问题是您提出的问题,那么显然不是。除非你的意思是你有很多 Xs 和 Ys 的值。在这种情况下,您正在执行多元线性回归。 MLR 可以使用普通最小二乘法求解,例如https://towardsdatascience.com/simple-and-multiple-linear-regression-in-python-c928425168f9

【讨论】:

  • 您好,感谢您的回答!我想将 w_1、w_2 和 w_3 保留为标量。我想我没有把任务的含义解释得太清楚。我正在尝试实现以下模型:x1*w1+ x2*w1+x3*w1+x4*w2+x5*w2+x6*w2+x7*w3+x8*w3+x9*w3=y_pred,其中 x1.. x9 和 w1..w9 是标量。
  • 感谢您的回答!我的问题专门针对与选择权重系数相关的机器学习任务之一。这个问题不是用线性代数解决的,而是用优化方法解决的
  • 为什么需要使用优化来解决?如果问题是您提出的问题,那么显然不是。除非您的意思是 X 和 Y 有 许多 值。在这种情况下,您正在执行多元线性回归。 MLR 可以使用普通最小二乘法求解,例如 towardsdatascience.com/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 2016-08-19
  • 2016-06-01
相关资源
最近更新 更多