Как создать слой встраивания в Tensorflow RNN?

Я строю сеть RNN LSTM для классификации текстов по возрасту авторов (бинарная классификация - молодые/взрослые).

Похоже, сеть не учится и вдруг начинает переобучать:

rnn_overfitting
Красный: обучение
Синий: проверка

Одной из возможностей может быть недостаточное представление данных. Я просто отсортировал уникальные слова по их частоте и дал им индексы. Например.:

unknown -> 0
the     -> 1
a       -> 2
.       -> 3
to      -> 4

Поэтому я пытаюсь заменить это встраиванием слов. Я видел пару примеров, но я не могу реализовать это в своем коде. Большинство примеров выглядят так:

embedding = tf.Variable(tf.random_uniform([vocab_size, hidden_size], -1, 1))
inputs = tf.nn.embedding_lookup(embedding, input_data)

Означает ли это, что мы создаем слой, который изучает встраивание? Я подумал, что нужно скачать какой-нибудь Word2Vec или Glove и просто использовать его.

В любом случае, скажем, я хочу создать этот слой внедрения...
Если я использую эти 2 строки в своем коде, я получаю сообщение об ошибке:

TypeError: значение, переданное параметру «индексы», имеет DataType float32, которого нет в списке допустимых значений: int32, int64

Так что я думаю, мне нужно изменить тип input_data на int32. Итак, я делаю это (в конце концов, это все индексы), и я получаю следующее:

TypeError: входы должны быть последовательностью

Я попытался обернуть inputs (аргумент tf.contrib.rnn.static_rnn) списком: [inputs], как это было предложено в этом ответе, но это привело к другой ошибке:

ValueError: Размер входных данных (размерность 0 входных данных) должен быть доступен через вывод формы, но видел значение None.


Обновление:

Я распаковывал тензор x, прежде чем передать его embedding_lookup. Я перенес распаковку после встраивания.

Обновленный код:

MIN_TOKENS = 10
MAX_TOKENS = 30
x = tf.placeholder("int32", [None, MAX_TOKENS, 1])
y = tf.placeholder("float", [None, N_CLASSES]) # 0.0 / 1.0
...
seqlen = tf.placeholder(tf.int32, [None]) #list of each sequence length*
embedding = tf.Variable(tf.random_uniform([VOCAB_SIZE, HIDDEN_SIZE], -1, 1))
inputs = tf.nn.embedding_lookup(embedding, x) #x is the text after converting to indices
inputs = tf.unstack(inputs, MAX_POST_LENGTH, 1)
outputs, states = tf.contrib.rnn.static_rnn(lstm_cell, inputs, dtype=tf.float32, sequence_length=seqlen) #---> Produces error

*seqlen: я дополнил последовательности нулями, чтобы все они имели одинаковый размер списка, но, поскольку фактические размеры различаются, я подготовил список, описывающий длину без заполнения.

Новая ошибка:

ValueError: Вход 0 слоя basic_lstm_cell_1 несовместим со слоем: ожидается ndim=2, найдено ndim=3. Получена полная форма: [Нет, 1, 64]

64 – размер каждого скрытого слоя.

Очевидно, что у меня проблема с размерами... Как сделать так, чтобы входы соответствовали сети после встраивания?


person Alaa M.    schedule 04.09.2018    source источник


Ответы (2)


Из tf.nn.static_rnn мы можем увидеть аргументы inputs быть:

Список входных данных длиной T, каждый из которых представляет собой тензор формы [batch_size, input_size]

Итак, ваш код должен быть примерно таким:

x = tf.placeholder("int32", [None, MAX_TOKENS])
...
inputs = tf.unstack(inputs, axis=1)
person vijay m    schedule 12.09.2018
comment
Это решило мою проблему ValueError (+ соответствующая корректировка ввода - изменение формы пакетов с (BATCH_SIZE, MAX_TOKENS, 1) на (BATCH_SIZE, MAX_TOKENS), чтобы они соответствовали новой форме x ). Однако это не решило проблему обучения. Графики теперь выглядят следующим образом: это. Я думаю, вы заслуживаете награды (и +1). - person Alaa M.; 14.09.2018
comment
Можете ли вы поделиться всем кодом, чтобы я мог попробовать его локально? - person vijay m; 14.09.2018
comment
Вместо того, чтобы присваивать словам уникальные значения, лучше присвоить заранее подготовленные векторы встраивания из glove или word2vec и не обучать их. - person vijay m; 15.09.2018
comment
Я также пытался сделать это (перчатка). Графики были похожи на то, что я разместил изначально. Так что наверняка я что-то делаю не так. Вот код (используя перчатку): ссылка - person Alaa M.; 15.09.2018
comment
Из кода я вижу, что вы меняете вектор встраивания перчатки на одно значение, используя np.linalg.norm, одного значения может быть недостаточно для представления слова. Я рекомендую вам изменить это. - person vijay m; 17.09.2018

tf.squeeze — это метод, удаляющий из тензора размерность 1. Если конечная цель состоит в том, чтобы форма ввода была [None,64], тогда поместите строку, подобную inputs = tf.squeeze(inputs), и это решит вашу проблему.

person Neeyanth Kopparapu    schedule 08.09.2018
comment
Это не сработало. Куда мне это положить? Если я поставлю его непосредственно перед вызовом static_rnn, я получаю еще одну ошибку: Inputs must be a sequence - person Alaa M.; 09.09.2018
comment
Попробуйте заключить входные данные в скобки, чтобы сделать tf.contrib.rnn.static_rnn(lstm_cell, [inputs], dtype=tf.float32, sequence_length=seqlen) - person Neeyanth Kopparapu; 09.09.2018
comment
Я же написал, что пробовал. Прочтите пост полностью, пожалуйста - person Alaa M.; 09.09.2018
comment
Ты сделал это с tf.sqeeze? Не могли бы вы также напечатать dtype и форму входных данных прямо перед вызовом rnn? - person Neeyanth Kopparapu; 09.09.2018
comment
Да, как я сказал в своем первом комментарии, я попробовал ваше предложение с squeeze, и оно не сработало. Типы: tensorflow.python.framework.ops.Tensor для x, sqlen и keep_prob и dict для weights и biases. - person Alaa M.; 14.09.2018