Заполнитель Tensorflow для однострочных кодированных меток

Philip Seyfi спросил: 28 марта 2018 в 02:47 в: python

У меня есть горячие закодированные метки (11 классов от 0 до 10):

# one-hot encode labels
from sklearn.preprocessing import OneHotEncoderlabels = df.rating.values.reshape([-1, 1])
encoder = OneHotEncoder(sparse=False)
encoder.fit(labels)
labels = encoder.transform(labels)

И имеют следующие заполнители:

# create the graph object
graph = tf.Graph()
# add nodes to the graph
with graph.as_default():
    inputs_ = tf.placeholder(tf.int32, [None, None], name='inputs')
    labels_ = tf.placeholder(tf.int32, [None, 1], name='labels')
    keep_prob = tf.placeholder(tf.float32, name='keep_prob')

И я использую sparse_softmax_cross_entropy:

with graph.as_default():
    logits = tf.layers.dense(inputs=outputs[:, -1], units=1)
    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels_, logits=logits)        
    optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)

TF throws: ValueError: Cannot feed value of shape (500, 1, 11) for Tensor 'labels:0', which has shape '(?, 1)'

I "Пробовал все и не мог заставить его работать. Каков правильный заполнитель для горячего кодирования данных?


1 ответ

Есть решение
Peter Szoldan ответил: 28 марта 2018 в 06:09

Вторым измерением должно быть столько классов, сколько у вас есть. Горячее кодирование означает, что если у вас есть, скажем, 10 классов, и вы кодируете класс 5, то это даст вектор [0, 0, 0, 0, 0, 1, 0, 0, 0, 0] длиной 10 , Таким образом, код должен быть:

labels_ = tf.placeholder(tf.int32, [None, ***number of classes***], name='labels')

С другой стороны, tf.losses.sparse_softmax_cross_entropy() принимает метку класса , а не горячее кодирование. Так что либо вы расшифровываете его с помощью tf.argmax() перед передачей его в tf.losses.sparse_softmax_cross_entropy() следующим образом:

loss = tf.losses.sparse_softmax_cross_entropy(
    labels = tf.argmax( labels_, axis = 1 ), logits = logits )

, либо реальный вопрос: почему вы тогда вообще использовать ont-hot кодирование? Вы можете просто подать df.rating.values.reshape([-1, 1]) на свой график как labels_ и оставить 1 во втором измерении. Весь блок горячего кодирования не нужен.

В вашем коде есть несколько других проблем (не показанных в оригинальном вопросе), которые влияют на эту проблему. Прежде всего, вы заполняете сеть следующим образом:

    feed = {inputs_: x,
            labels_: y[:, None],
            keep_prob: 1,
            initial_state: test_state}

Чтобы попытаться устранить проблему labels_, вы добавили индексирование [:, None]. Проблема в том, что в Numpy индекс None имеет особое значение: он вставит новое измерение. Так вот откуда берется дополнительное измерение в ( 500, 1, 1 ). Индексирование y здесь не нужно, я это удалил. Таким образом, код должен быть:

    feed = {inputs_: x,
            labels_: y,
            keep_prob: 1,
            initial_state: test_state}

Затем возникает другая проблема, очень распространенная ошибка, в этой строке:

loss, state, _ = sess.run([loss, final_state, optimizer], feed_dict=feed)

вы назначаете значение от loss до loss, поэтому loss теперь является числом , а не тензор так и должно быть. Так что на второй итерации код не работает. Я изменил его на

loss_val, state, _ = sess.run([loss, final_state, optimizer], feed_dict=feed)

, но, конечно, вам нужно распространить это изменение и на print():

print("Epoch: {}/{}".format(e, epochs),
      "Iteration: {}".format(iteration),
      "Train loss: {:.3f}".format(loss_val))

Кроме того, там, где вы определяете свои логиты, у вас должно быть 11 единиц, поскольку у вас есть 11 классов (0–10), и вам нужна одна вероятность для каждого класса:

logits = tf.layers.dense(inputs=outputs[:, -1], units=11 )

С этими изменениями тренировка проходит, кажется, даже чему-то научилась:

('Epoch: 0/10', 'Iteration: 5', 'Потеря поезда: 1.735') ("Эпоха: 0/10", "Итерация: 10", "Потеря поезда: 2.092")
("Эпоха: 0/10", "Итерация: 15", "Потеря поезда: 2.644") ("Эпоха: 0/10", "Итерация: 20", "Потеря поезда: 1.596")
("Эпоха: 0/10", "Итерация: 25", "Потеря поезда: 1.759") Val acc: 0,012
('Epoch: 0/10', 'Iteration: 30', 'Train train: 1.581')
('Epoch: 0/10', 'Iteration: 35', ' Потеря поезда: 2,213 ')
("Эпоха: 0/10", "Итерация: 40", "Потеря поезда: 2,176")
("Эпоха: 0/10", "Итерация: 45", " Потеря поезда: 1,849 ')
(' Эпоха: 0/10 ',' Итерация: 50 ',' Потеря поезда: 2,447 ')
Val acc: 0,017

Philip Seyfi ответил: 28 марта 2018 в 03:03
Я пробовал это раньше, но потом выдает Can not squeeze dim[1], expected a dimension of 1, got 11 for 'sparse_softmax_cross_entropy_loss/remove_squeezable_dimensions/Squeeze' (op: 'Squeeze') with input shapes: [?,11]. в loss = tf.losses.sparse_softmax_cross_entropy(labels=labels_, logits=logits)
Peter Szoldan ответил: 28 марта 2018 в 03:11
Обновленный ответ.
Philip Seyfi ответил: 28 марта 2018 в 03:13
Я тоже это попробовал (не используя одну горячую кодировку) ... но он выбрасывает Cannot feed value of shape (500, 1, 1) for Tensor 'labels:0', which has shape '(?, 1)' И если вместо этого я использую softmax_cross_entropy с горячей клавишей, выдает Received a label value of 10 which is outside the valid range of [0, 1).
Philip Seyfi ответил: 28 марта 2018 в 03:14
И если я сделаю заполнитель None, 1, 1, выдает Rank mismatch: Rank of labels (received 3) should equal rank of logits minus 1 (received 2).
Peter Szoldan ответил: 28 марта 2018 в 03:17
Вы должны иметь метки в виде (None, 1). Как вы получаете дополнительное измерение? Для каждого изображения у вас есть одна метка.