Нарезка тензорного потока на основе переменной

Я обнаружил, что индексирование по-прежнему является открытой проблемой в tensorflow (# 206), поэтому мне интересно, что я могу использовать в качестве обходного пути на данный момент, Я хочу индексировать/нарезать строку/столбец матрицы на основе переменной, которая изменяется для каждого примера обучения.

Что я пробовал до сих пор:

  • Нарезка на основе заполнителя (не работает)

Следующие (рабочие) фрагменты кода на основе фиксированного числа.

import tensorflow as tf
import numpy as np

x = tf.placeholder("float")
y = tf.slice(x,[0],[1])

#initialize
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

#run
result = sess.run(y, feed_dict={x:[1,2,3,4,5]})
print(result)

Однако, похоже, я не могу просто заменить одно из этих фиксированных чисел на tf.placeholder. Следующий код дает мне ошибку "TypeError: список тензоров при ожидании одиночного тензора".

import tensorflow as tf
import numpy as np

x = tf.placeholder("float")
i = tf.placeholder("int32")
y = tf.slice(x,[i],[1])

#initialize
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

#run
result = sess.run(y, feed_dict={x:[1,2,3,4,5],i:0})
print(result)

Это звучит так, как скобки вокруг [i] слишком много, но удаление их тоже не помогает. Как использовать заполнитель/переменную в качестве индекса?

  1. Нарезка на основе переменной python (не поддерживает backprop/update должным образом)

Я также пытался использовать обычную переменную python в качестве индекса. Это не приводит к ошибке, но сеть не учит чему-либо во время обучения. Я полагаю, потому что изменяющаяся переменная неправильно зарегистрирована, график неверен и обновления не работают?

  1. Нарезка через одноструй вектор + умножение (работает, но медленнее)

Один обходной путь, который я нашел, - это использование горячего вектора. Создание одноразового вектора в numpy, передавая его с помощью заполнителя, а затем выполняем разбиение по матричному умножению. Это работает, но довольно медленно.

Любые идеи, как эффективно срезать/индексировать на основе переменной?

Ответ 1

Нарезка, основанная на заполнителе, должна работать нормально. Похоже, вы сталкиваетесь с ошибкой типа из-за некоторых тонких проблем форм и типов. Где у вас есть следующее:

x = tf.placeholder("float")
i = tf.placeholder("int32")
y = tf.slice(x,[i],[1])

... вместо этого вы должны:

x = tf.placeholder("float")
i = tf.placeholder("int32")
y = tf.slice(x,i,[1])

... а затем вы должны отправить i как [0] в вызове sess.run().

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

import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32, shape=[None])  # 1-D tensor
i = tf.placeholder(tf.int32, shape=[1])
y = tf.slice(x, i, [1])

#initialize
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

#run
result = sess.run(y, feed_dict={x: [1, 2, 3, 4, 5], i: [0]})
print(result)

Дополнительные аргументы shape для справки tf.placeholder op, чтобы гарантировать, что значения, которые вы кормите, имеют соответствующие формы, а также то, что TensorFlow вызывает ошибку, если фигуры неправильны.

Ответ 2

Если у вас есть дополнительное измерение, это работает.

import tensorflow as tf
import numpy as np

def reorder0(e, i, length):
    '''
    e: a two dimensional tensor
    i: a one dimensional int32 tensor, of shape (e.shape[0])
    returns: a tensor of the same shape as e, where the jth entry is entry i[j] from e
    '''
    return tf.concat(
        [ tf.expand_dims( e[i[j],:], axis=0)  for j in range(length) ],
        axis=0
    )

e = tf.placeholder(tf.float32, shape=(2,3,5), name='e' )  # sentences, words, embedding
i = tf.placeholder(tf.int32, shape=(2,3), name='i' ) # for each word, index of parent
p = tf.concat(
    [ tf.expand_dims(reorder0(e[k,:,:], i[k,:], 3), axis=0)  for k in range(2) ],
    axis=0,
    name='p'
)

#initialize
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

#run
result = sess.run(p, feed_dict={
    e: [ 
        ( (1.0,1.1,1.2,1.3,1.4),(2.0,2.1,2.2,2.3,2.4),(3.0,3.1,3.2,3.3,3.4) ), 
        ( (21.0,21.1,21.2,21.3,21.4),(22.0,22.1,22.2,22.3,22.4),(23.0,23.1,23.2,23.3,23.4) ),  
    ], 
    i: [ (1,1,1), (2,0,2)]
})
print(result)

Ответ 3

Если размеры не известны при построении модели, используйте TensorArray.

e = tf.placeholder(tf.float32, shape=(3,5) )  # words, embedding
i = tf.placeholder(tf.int32, shape=(3) ) # for each word, index of parent
#p = reorder0(e, i, 3)
a = tf.TensorArray(
    tf.float32, 
    size=e.get_shape()[0],
    dynamic_size=True,
    infer_shape= True,
    element_shape=e.get_shape()[1],
    clear_after_read = False
)


#initialize
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

#run
result = sess.run(
    a.unstack(e).gather(i), 
    feed_dict={
        e: ( (1.0,1.1,1.2,1.3,1.4),(2.0,2.1,2.2,2.3,2.4),(3.0,3.1,3.2,3.3,3.4) ),
            #( (21.0,21.1,21.2,21.3,21.4),(22.0,22.1,22.2,22.3,22.4),(23.0,23.1,23.2,23.3,23.4) ),  
        i: (2,0,2)
    }
)
print(result)