Определенный линейный классификатор в TensorFlow: элемент ввода как вектор - PullRequest
2 голосов
/ 12 октября 2019

Как я могу реализовать такой линейный классификатор в TensorFlow:

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

, где x1, x2, x3 - векторы и w1, w2 и w3 - скаляры?

У меня есть хороший учебник дляслучай, когда x1, x2, x3 - скаляры ( ссылка ),

, но для случая, когда 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.

Ответы [ 3 ]

2 голосов
/ 15 октября 2019

Должен быть реализован линейный мультиклассовый классификатор:

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)
2 голосов
/ 19 октября 2019

Я использовал созданный массив, который выглядит как [w1, w1, w1, w2, w2, w2 ...] и умножил его (поэлементно) на x, прежде чем суммировать все члены. Я не смог заставить model.fit работать, поэтому я скопировал код train_step из https://www.tensorflow.org/tutorials/quickstart/advanced. Кажется, он работает нормально. Я оставил свой тестовый код внизу для вас, чтобы вы могли его проверить.

В нем используется tennsorlfow 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())
2 голосов
/ 14 октября 2019

Этот вопрос некорректен. Вы говорите, что хотите, чтобы x_1, x_2, x_3 были векторами, однако неясно, что вы будете делать с w_1, w_2, w_3. Есть две возможности.

  • Если вы хотите оставить их как скаляры , как, по-видимому, подразумевается в вашем вопросе, то модель на самом деле не является векторной моделью, выВы просто делаете одну и ту же скалярную операцию для всех записей векторов x, но сразу. Это эквивалентно скалярной модели.

  • В противном случае вы можете определить w_1, w_2, w_3 как матрицы или векторы строк, если метка скалярная. В этом случае нет причин писать уравнение так, как вы его написали, потому что вы можете сложить x в один вектор и w в один вектор и написать wx = y. В любом случае, это многомерная линейная регрессия, из которой вы можете найти множество примеров и учебные пособия по ее решению в Tensorflow и Torch.

Обновление с учетом разъяснений ОП

В своем комментарии вы теперь говорите, что заинтересованы в решении следующего уравнения:

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) для одного линейного уравнения. Таким образом, у него будет не единственное решение, а двумерное линейное пространство решений (оно идентифицирует плоскость в трехмерном w-пространстве). Чтобы получить некоторые решения, вы можете произвольно выбрать, например, w1 = w2 = 0, из которого вы автоматически получите w3 = z3 / y. Затем сделайте то же самое для двух других, и вы получите три разных и линейно независимых решения.

Надеюсь, это поможет. Таким образом, вам вообще не нужен код.

Второе обновление (из комментария)

Почему его необходимо решить с помощью оптимизации? Если проблема в том виде, в каком вы ее представили, это явно не так. Если вы не имеете в виду, у вас есть много значений для X и Y. В этом случае вы делаете многомерную линейную регрессию. MLR может быть решено с использованием обычных наименьших квадратов, см. Например https://towardsdatascience.com/simple-and-multiple-linear-regression-in-python-c928425168f9

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...