Подтвердить что ты не робот

Тензор с неопределенным размером в тензорном потоке

Я играю с тензорным потоком и столкнулся с проблемой со следующим кодом:

def _init_parameters(self, input_data, labels):

    # the input shape is (batch_size, input_size)
    input_size = tf.shape(input_data)[1]

    # labels in one-hot format have shape (batch_size, num_classes)
    num_classes = tf.shape(labels)[1]

    stddev = 1.0 / tf.cast(input_size, tf.float32)

    w_shape = tf.pack([input_size, num_classes], 'w-shape')
    normal_dist = tf.truncated_normal(w_shape, stddev=stddev, name='normaldist')
    self.w = tf.Variable(normal_dist, name='weights')

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

Когда я запускаю его (из более крупного script, который вызывает этот), я получаю эту ошибку:

ValueError: initial_value must have a shape specified: Tensor("normaldist:0", shape=TensorShape([Dimension(None), Dimension(None)]), dtype=float32)

Я попытался реплицировать процесс в интерактивной оболочке. В самом деле, размеры normal_dist не определены, хотя имеющиеся значения существуют:

In [70]: input_size.eval()
Out[70]: 4

In [71]: num_classes.eval()
Out[71]: 3

In [72]: w_shape.eval()
Out[72]: array([4, 3], dtype=int32)

In [73]: normal_dist.eval()
Out[73]: 
array([[-0.27035281, -0.223277  ,  0.14694688],
       [-0.16527176,  0.02180306,  0.00807841],
       [ 0.22624688,  0.36425814, -0.03099642],
       [ 0.25575709, -0.02765726, -0.26169327]], dtype=float32)

In [78]: normal_dist.get_shape()
Out[78]: TensorShape([Dimension(None), Dimension(None)])

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

4b9b3361

Ответ 1

Как говорит Ишамаэль, все тензоры имеют статическую форму, которая известна во время построения графика и доступна с помощью Tensor.get_shape(); и динамическая форма, которая известна только во время выполнения и доступна путем извлечения значения тензора или передачи его оператору типа tf.shape. Во многих случаях статические и динамические формы одинаковы, но они могут быть разными - статическая форма может быть частично определена - чтобы динамическая форма менялась от одного шага к следующему.

В вашем коде normal_dist есть частично заданная статическая форма, потому что w_shape - вычисленное значение. (TensorFlow иногда пытается оценить эти вычисленные значения при времени построения графика, но он застревает в tf.pack.) Он отображает форму TensorShape([Dimension(None), Dimension(None)]), что означает "матрица с неизвестным количеством строк и столбцов", потому что она известна тем, что w_shape является вектор длины 2, поэтому результирующий normal_dist должен быть двумерным.

У вас есть два варианта решения этой проблемы. Вы можете установить статическую форму, как предполагает Ishamael, но для этого вам нужно знать форму при построении графика. Например, может работать следующее:

normal_dist.set_shape([input_data.get_shape()[1], labels.get_shape()[1]])

В качестве альтернативы вы можете передать validate_shape=False в конструктор tf.Variable. Это позволяет создать переменную с частично определенной формой, но она ограничивает количество информации о статической форме, которая может быть выведена позже на графике.

Ответ 2

Переменная может иметь динамическую форму. get_shape() возвращает статическую форму.

В вашем случае у вас есть тензор, который имеет динамическую форму и в настоящее время имеет значение 4 × 3 (но в некоторый другой момент он может удерживать значение с другой формой - поскольку форма является динамической). Чтобы установить статическую форму, используйте set_shape(w_shape). После этого будет применена установленная вами форма, и тензор будет действительным initial_value.

Ответ 3

Подобный вопрос хорошо объяснен в Часто задаваемые вопросы TF:

В TensorFlow тензор имеет как статическую (предполагаемую) форму, так и динамическая (истинная) форма. Статическая форма может быть прочитана с помощью tf.Tensor.get_shape: эта форма выводится из операций которые были использованы для создания тензора и могут быть частично завершены. Если статическая форма не полностью определена, динамическая форма тензора t может быть определено путем оценки tf.shape(t).

Итак tf.shape() возвращает вам тензор, всегда будет иметь размер shape=(N,) и может быть рассчитан в сеансе:

a = tf.Variable(tf.zeros(shape=(2, 3, 4)))
with tf.Session() as sess:
    print sess.run(tf.shape(a))

С другой стороны, вы можете извлечь статическую форму с помощью x.get_shape().as_list(), и это можно вычислить где угодно.