Tensorflow - рассчитать евклидово расстояние для сети RBF

У меня проблема с реализацией сети RBF в Tensorflow. Мне нужно рассчитать евклидово расстояние между x и центроидами (из определения RBF newtork). Я написал этот код:

    x_data = tf.placeholder(shape=[None, 3], dtype=tf.float32)
    y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)

    # Create variables for NN layers
    A1 = tf.Variable(tf.random_normal(shape=[3, first_layer_nodes]))  # input -> first layer nodes
    A2 = tf.Variable(tf.random_normal(shape=[first_layer_nodes, 1]))  # first_layer nodes -> sum node
    c = tf.Variable(tf.random_normal(shape=[first_layer_nodes]))  # centroids

    # Declare NN
    inputs_with_weights = tf.matmul(x_data, A1)
    print(inputs_with_weights)
    # euclid_dist = tf.sqrt(tf.reduce_sum(tf.pow(tf.subtract(inputs_with_weights, c), 2)))
    euclid_dist = tf.norm(inputs_with_weights - c, ord='euclidean')
    print(euclid_dist)
    first_output = tf_gaussian_function(euclid_dist)
    print(first_output)

final_output = tf.matmul(first_output, A2)

Но у меня такая проблема:

E:\#PROJEKTY\#PROGRAMOWANIE\AI-Project>python Iris.py
2018-04-27 00:49:37.800684: I C:\tf_jenkins\workspace\rel-win\M\windows\PY\36\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
<tf.Variable 'Variable_2:0' shape=(1, 1) dtype=float32_ref>
Tensor("MatMul:0", shape=(?, 1), dtype=float32)
Tensor("norm/Squeeze:0", shape=(), dtype=float32)
Tensor("gaussian_function:0", dtype=float32)
Traceback (most recent call last):
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 1361, in _do_call
    return fn(*args)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 1340, in _run_fn
    target_list, status, run_metadata)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 516, in __exit__
    c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: In[0] is not a matrix
         [[Node: MatMul_1 = MatMul[T=DT_FLOAT, transpose_a=false, transpose_b=false, _device="/job:localhost/replica:0/task:0/device:CPU:0"](gaussian_function, Variable_1/read)]]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "Iris.py", line 144, in <module>
    sess.run(train_step, feed_dict={x_data: x_d, y_target: y_d})
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 905, in run
    run_metadata_ptr)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 1137, in _run
    feed_dict_tensor, options, run_metadata)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 1355, in _do_run
    options, run_metadata)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\client\session.py", line 1374, in _do_call
    raise type(e)(node_def, op, message)
tensorflow.python.framework.errors_impl.InvalidArgumentError: In[0] is not a matrix
         [[Node: MatMul_1 = MatMul[T=DT_FLOAT, transpose_a=false, transpose_b=false, _device="/job:localhost/replica:0/task:0/device:CPU:0"](gaussian_function, Variable_1/read)]]

Caused by op 'MatMul_1', defined at:
  File "Iris.py", line 124, in <module>
    final_output = tf.matmul(first_output, A2)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\math_ops.py", line 2064, in matmul
    a, b, transpose_a=transpose_a, transpose_b=transpose_b, name=name)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 2790, in _mat_mul
    name=name)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 787, in _apply_op_helper
    op_def=op_def)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 3271, in create_op
    op_def=op_def)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 1650, in __init__
    self._traceback = self._graph._extract_stack()  # pylint: disable=protected-access

InvalidArgumentError (see above for traceback): In[0] is not a matrix
         [[Node: MatMul_1 = MatMul[T=DT_FLOAT, transpose_a=false, transpose_b=false, _device="/job:localhost/replica:0/task:0/device:CPU:0"](gaussian_function, Variable_1/read)]]

Если я попытаюсь указать любое значение оси, оно застрянет на:

E:\#PROJEKTY\#PROGRAMOWANIE\AI-Project>python Iris.py
2018-04-27 00:53:15.388129: I C:\tf_jenkins\workspace\rel-win\M\windows\PY\36\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
<tf.Variable 'Variable_2:0' shape=(1, 1) dtype=float32_ref>
Tensor("MatMul:0", shape=(?, 1), dtype=float32)
Traceback (most recent call last):
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 686, in _call_cpp_shape_fn_impl
    input_tensors_as_shapes, status)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 516, in __exit__
    c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: Invalid reduction dimension 2 for input with 2 dimensions. for 'norm/Sum' (op: 'Sum') with input shapes: [?,1], [1] and with computed input tensors: input[1] = <2>.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "Iris.py", line 120, in <module>
    euclid_dist = tf.norm(inputs_with_weights - c, axis = 2, ord='euclidean')
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\util\deprecation.py", line 432, in new_func
    return func(*args, **kwargs)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\linalg_ops.py", line 552, in norm
    tensor * math_ops.conj(tensor), axis, keepdims=True))
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\util\deprecation.py", line 432, in new_func
    return func(*args, **kwargs)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\math_ops.py", line 1373, in reduce_sum
    name=name))
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 5436, in _sum
    name=name)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 787, in _apply_op_helper
    op_def=op_def)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 3273, in create_op
    compute_device=compute_device)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 3313, in _create_op_helper
    set_shapes_for_outputs(op)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 2501, in set_shapes_for_outputs
    return _set_shapes_for_outputs(op)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 2474, in _set_shapes_for_outputs
    shapes = shape_func(op)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\ops.py", line 2404, in call_with_requiring
    return call_cpp_shape_fn(op, require_shape_fn=True)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 627, in call_cpp_shape_fn
    require_shape_fn)
  File "C:\Users\Szatku\AppData\Local\Programs\Python\Python36\lib\site-packages\tensorflow\python\framework\common_shapes.py", line 691, in _call_cpp_shape_fn_impl
    raise ValueError(err.message)
ValueError: Invalid reduction dimension 2 for input with 2 dimensions. for 'norm/Sum' (op: 'Sum') with input shapes: [?,1], [1] and with computed input tensors: input[1] = <2>.

Я понятия не имею, как исправить код. Может ли кто-нибудь мне помочь?

РЕДАКТИРОВАТЬ: гауссовская реализация:

def gaussian_function(input_layer):
    initial = math.exp(-SC*math.pow(input_layer, 2))
    return initial


np_gaussian_function = np.vectorize(gaussian_function)


def d_gaussian_function(input_layer):
    initial = -2*SC*input_layer * math.exp(-SC * math.pow(input_layer, 2))
    return initial


np_d_gaussian_function = np.vectorize(d_gaussian_function)


def np_d_gaussian_function_32(input_layer):
    return np_d_gaussian_function(input_layer).astype(np.float32)


def tf_d_gaussian_function(input_layer, name=None):
    with ops.name_scope(name, "d_gaussian_function", [input_layer]) as name:
        y = tf.py_func(np_d_gaussian_function_32, [input_layer],[tf.float32], name=name, stateful=False)
    return y[0]


def py_func(func, inp, Tout, stateful=True, name=None, grad=None):
    rnd_name = 'PyFunGrad' + str(np.random.randint(0, 1E+8))

    tf.RegisterGradient(rnd_name)(grad)
    g = tf.get_default_graph()
    with g.gradient_override_map({"PyFunc": rnd_name}):
        return tf.py_func(func, inp, Tout, stateful=stateful, name=name)


def gaussian_function_grad(op, grad):
    input_variable = op.inputs[0]
    n_gr = tf_d_gaussian_function(input_variable)
    return grad * n_gr


def np_gaussian_function_32(input_layer):
    return np_gaussian_function(input_layer).astype(np.float32)


def tf_gaussian_function(input_layer, name=None):
    with ops.name_scope(name, "gaussian_function", [input_layer]) as name:
        y = py_func(np_gaussian_function_32, [input_layer], [tf.float32], name=name, grad=gaussian_function_grad)
    return y[0]
# end of defining activation function

person SzateX    schedule 26.04.2018    source источник


Ответы (1)


Ошибка говорит о том, что первый аргумент

final_output = tf.matmul(first_output, A2)

не является матрицей. Так что first_output не в порядке. Это происходит из предыдущей строки:

first_output = tf_gaussian_function(euclid_dist)

Итак, нам нужно проверить эту функцию tf_gaussian_function(), но ее нет в опубликованном коде. Я проверил, не опечатка ли это, и это должно быть tf.gaussian_function(), но такого нет.

Поэтому, пожалуйста, опубликуйте определение функции tf_gaussian_function().


Итак, теперь, когда у нас это есть, получается, что вы пытаетесь отобразить функцию math.exp( -SC * math.pow( input_layer, 2 ) ) (обычно называемую rho или ) на euclid_dist; Я так понимаю, это будет ваша радиальная базисная функция. Примечание: похоже, вы пытаетесь сделать серьезную тяжелую работу, реализуя свой собственный градиент и все такое, проходя через np.vectorize() и все такое. Я бы посоветовал вам реализовать что-то гораздо более простое, например этот код (непроверенный):

first_output = tf.exp( -SC * euclid_dist * euclid_dist )

(Я использую x * x вместо эквивалентного tf.pow( x, 2 ), потому что первый более эффективен.) Это должно создать собственный градиент и позаботиться обо всем, чего вы пытаетесь достичь. Но в любом случае вы уверены, что ваша реализация работает, что вполне может быть так, как я обнаружил здесь; вы также можете дважды проверить, дает ли он те же результаты, что и этот однострочный.

С точки зрения того, что такое euclid_dist, tf.norm( x, ord = "euclidean", axis = None ) возвращает 2nd норма (или евклидова норма, также известная как квадратный корень из суммы квадратов), так что это определенно скаляр. (Это делает в точности то, о чем говорится в закомментированной строке выше: euclid_dist = tf.sqrt(tf.reduce_sum(tf.pow(tf.subtract(inputs_with_weights, c), 2))).) Не знаете, чего вы пытаетесь достичь? Если вам просто нужны квадраты расстояний, то вы должны сделать это так:

euclid_dist = ( inputs_with_weights - c ) * ( inputs_with_weights - c )

Но, насколько я понимаю, в сети с радиальной базисной функцией сначала вы применяете веса на входе, затем идет радиальная базисная функция, и только в качестве третьего шага приходит евклидово расстояние как функция стоимости, которая вполне может быть скаляр.

Если эта строка — ваша попытка реализовать нормализацию для вашей сети RBF, обратите внимание, что нормализация обычно выполняется немного по-другому. Таким образом, ваша реализация может выглядеть более похожей на это, если я правильно пойму ваш дрейф:

from __future__ import print_function
import tensorflow as tf
from tensorflow.python.framework import ops
import numpy as np

x_data = tf.placeholder(shape=[1, 3], dtype=tf.float32)
y_target = tf.placeholder(shape=[1, 1], dtype=tf.float32)

# Create variables for NN layers
first_layer_nodes = 5
A1 = tf.Variable(tf.random_normal(shape=[3, first_layer_nodes]))  # input -> first layer nodes
A2 = tf.Variable(tf.random_normal(shape=[first_layer_nodes, 1]))  # first_layer nodes -> sum node
c = tf.Variable(tf.random_normal(shape=[first_layer_nodes]))  # centroids

# Declare NN
SC = 1
def rho( distances ): return tf.exp( -SC * distances * distances )
def norm( x ): return x / tf.reduce_sum( x, axis = -1 )
inputs_with_weights = tf.matmul( x_data, A1 )
print(inputs_with_weights)
distances = inputs_with_weights - c
print( distances )
first_output = norm( rho( distances ) ) # tf_gaussian_function(distances) # 
print(first_output)
final_output = tf.matmul(first_output, A2)

with tf.Session() as sess:
    sess.run( tf.global_variables_initializer() )
    r = sess.run( [ first_output, final_output ], feed_dict = {
                  x_data : np.array( [ [ 1.0, 2, 3 ] ] ) } )
    for v in r:
        print( v )

Выходы:

Tensor("MatMul_15:0", shape=(1, 5), dtype=float32)
Tensor("sub_8:0", shape=(1, 5), dtype=float32)
Tensor("div_5 :0", shape=(1, 5), dtype=float32)
[[4.4366708e-03 6.8647589e-04 5.9621310e-01 7.5066246e-06 3.9865622e-01]]
[[0.31285414] ]


Чтобы ответить на комментарий, где вы разместили этот фрагмент кода:

exp_list = []
for i in range(first_layer_nodes):
    euclid_distance = tf.reduce_sum(tf.square(tf.subtract(x_data, c[i, :])), 1)
    exp_list.append(tf.exp(-SC * euclid_distance))
phi = tf.transpose(tf.stack(exp_list))

это можно было бы векторизовать, используя неявную трансляцию на tf.subtract() с расширенной индексацией, например это (не проверено):

ed = tf.reduce_sum( tf.square( tf.subtract( x_data[ None, ... ], c ) ), 2 )
phi = tf.transpose( tf.exp( -SC * ed ) )
person Peter Szoldan    schedule 27.04.2018
comment
Я помещаю код в редактирование сообщения. Скорее нет проблем с tf_gaussian_function(). Потому что, если поставить input_with_weights, он работает хорошо (но, конечно, нет сети RBF). Проблема в tf.norm, который возвращает мне скаляр, и я понятия не имею, какой набор должен выполнять правильную работу для каждого узла. - person SzateX; 29.04.2018
comment
Я думаю: расстояния = входы_с_весами - c неверно - евклидово расстояние: sqrt ((x1 - x2) ** 2 + (y1 - y2) ** 2) в двумерном случае - person SzateX; 29.04.2018
comment
У вас нет Y здесь! Двух координат не бывает! Даже центроиды имеют только одну координату! Евклидово расстояние в одном измерении на самом деле равно abs(x2 - x1). - person Peter Szoldan; 29.04.2018
comment
Прошу прощения, я не хотел кричать, я просто потратил МНОГО времени на этот ответ и, похоже, неправильно понял ваш вопрос, что меня расстроило. c = tf.Variable(tf.random_normal(shape=[first_layer_nodes])) заставил меня думать, что у каждого центроида есть только одна координата. Я ошибся? - person Peter Szoldan; 29.04.2018
comment
Извините, это была моя вина. Я плохо делаю свою сеть. Теперь я ищу некоторую оптимизацию этого: ссылка - person SzateX; 14.05.2018
comment
Оптимизация в каком смысле? Вы хотите переписать цикл for и векторизовать его? - person Peter Szoldan; 15.05.2018
comment
Да, точно. Теперь процесс вычислений примерно в 10 раз медленнее - person SzateX; 15.05.2018
comment
Какую именно ошибку вы получаете в какой строке? (Я не могу проверить это сам без полного кода.) - person Peter Szoldan; 15.05.2018
comment
Да, если возможно, это было бы полезно, если бы я мог просто запустить его и работать над ним, пока он не заработает должным образом. - person Peter Szoldan; 15.05.2018
comment
comment
Вы используете это под Python 2 или 3? - person Peter Szoldan; 15.05.2018
comment
Я использую Python 3. - person SzateX; 15.05.2018
comment
Ок, тем временем была встреча. Так получилось запустить ваш код в colab, закомментировать операции сохранения. Эта версия отличается от версии, опубликованной по этой ссылке. c настроен по-другому и т.д. Над чем будем работать? - person Peter Szoldan; 15.05.2018
comment
Новая версия - person SzateX; 15.05.2018