Вопрос или проблема
Сейчас я изучаю тему генерации текста для своего университетского проекта. Я (конечно) решил использовать RNN, принимая последовательность токенов на входе с целью предсказать следующий токен, исходя из этой последовательности. Я прочитал несколько туториалов, и у меня есть один вопрос. Источники, которые я изучал, независимо от того, как они кодируют последовательности X
(one-hot или векторные представления слов), кодируют целевые токены y
как one-hot вектор, чтобы интерпретировать вывод сети как распределение вероятностей по всем возможным токенам. Таким образом, задача на самом деле формулируется как проблема многоклассовой классификации (например, как здесь https://machinelearningmastery.com/develop-word-based-neural-language-models-python-keras/).
Я действительно планирую закодировать свои последовательности X
в последовательности векторов, отображающих каждый токен на заранее обученный вектор слов, но на самом деле я думал о том, чтобы спроектировать сеть так, чтобы она выдавалa вектор значений той же размерности, что и входные векторы, и сопоставлять выходной вектор с определенным словом, находя наиболее похожий вектор среди известных заранее обученных векторов. Поскольку мы пытаемся найти вектор чисел, соответствующий вектору целевого слова, можно сказать, что это формулирует задачу как задачу регрессии, верно?
Мой вопрос: известен ли метод, описанный в вышеприведенном абзаце (вывод вектора слов вместо распределения вероятностей), под каким-либо термином или названием? Сомневаюсь, что никто не думал об этом до меня (если это не имеет смысла, и я не в курсе), но быстрый поиск в Google, описывающий метод, не нашел ничего полезного, и мне хотелось бы узнать больше.
У меня был тот же вопрос, и я решил свою проблему. Я также работаю над проектом “генерации текста” (хотя с картами из карточной игры Magic: the Gathering: токены — это карты, а не слова). Я тоже не мог найти другие примеры RNN, выдающих векторы слов.
Отказ от ответственности: Я еще не уверен в работе с RNN, нейронными сетями и Tensorflow/Keras в общем. Я предоставляю свой ответ, потому что пока что никто ничего не опубликовал, у меня была такая же проблема, и теперь у меня есть решение, которое работает для меня. Я включил столько информации, сколько мог. Суть в конце
Вот что я сделал:
Я заранее векторизовал свой словарь (используя Gensim Word2Vec). Затем я разбил свой корпус векторов на тренировочные и тестовые группы. Модель, которую я использовал, взята из этой ссылки: https://machinelearningmastery.com/how-to-develop-a-word-level-neural-language-model-in-keras/
Вот модель из ссылки:
# взято из: https://machinelearningmastery.com/how-to-develop-a-word-level-neural-language-model-in-keras/
model = Sequential()
model.add(Embedding(vocab_size, 50, input_length=seq_length))
model.add(LSTM(100, return_sequences=True))
model.add(LSTM(100))
model.add(Dense(100, activation='relu'))
model.add(Dense(vocab_size, activation='softmax'))
С тремя исключениями:
- Я убрал первый слой “Embedding”, потому что мои “слова” уже были векторизованы. Первым слоем стала “LSTM”.
- Я изменил количество единиц в последнем слое на размер моих векторов слов. Мои векторы длиной 64.
- Я убрал активацию “softmax” в последнем слое. Я не хочу категориального предсказания, я хочу 64 числа (формирующих вектор длиной 64).
Вот моя модель, адаптированная по ссылке:
model = tf.keras.Sequential()
model.add(tf.keras.layers.LSTM(100, return_sequences=True))
model.add(tf.keras.layers.LSTM(100))
model.add(tf.keras.layers.Dense(100, activation='relu'))
model.add(tf.keras.layers.Dense(64))
Наконец, в ссылке модель компилируется с функцией потерь ‘categorical_crossentropy’, которая, я полагаю, подходит для категориальных предсказаний.
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=['accuracy'])
Однако мы смотрим на погрешности между векторами. Я думаю, что хорошим способом сделать это является поиск их косинусного сходства. Косинусное сходство измеряет угол между векторами. (https://en.wikipedia.org/wiki/Cosine_similarity#:~:text=The%20term%20cosine%20distance%20is%20commonly%20used%20for,Schwarz%20inequality%20%E2%80%94and%20it%20violates%20the%20coincidence%20axiom.)
К счастью, Tensorflow имеет функцию потерь на основе косинусного сходства. Вот моя инструкция для компиляции:
model.compile(loss="cosine_similarity", optimizer="adam", metrics=['accuracy'])
Эту модель теперь можно обучать для получения векторов, похожих на целевой вектор. Чтобы декодировать выход назад в слово, просто найдите вектор, ближайший к вашему выходу. Для меня это: word_vector_model.most_similar(prediction_vector)
(модель из Gensim.models.Word2Vec, у нее есть метод “most_similar()”)
С этими параметрами я смог успешно обучить свою модель, чтобы предсказывать последний “вектор карты” из списков из 60 карт. В настоящее время у меня немного переобученная модель из-за небольшого размера набора данных и большого количества эпох. Думаю, что переобучение — это хотя бы хороший признак того, что модель правильно предсказывает векторы.
Суть ————————————————————-
Я немного подправил модель из этой ссылки: https://machinelearningmastery.com/how-to-develop-a-word-level-neural-language-model-in-keras/.
Вот что мне удалось сделать:
# определение модели
model = tf.keras.Sequential()
model.add(tf.keras.layers.LSTM(100, return_sequences=True))
model.add(tf.keras.layers.LSTM(100))
model.add(tf.keras.layers.Dense(100, activation='relu'))
model.add(tf.keras.layers.Dense(64))
# компиляция модели
model.compile(loss="cosine_similarity", optimizer="adam", metrics=['accuracy'])
# обучение модели
model.fit(x_train, y_train, batch_size=120, epochs=100)
print(model.summary())
# сохранить модель в файл
model.save('lstm_models/m5.h5')
Обратите внимание, что у моего последнего слоя нет активации softmax: он предсказывает числа (которые должны находиться в векторе), а не категории. Также обратите внимание, что в последнем слое количество единиц = длина(word_vector) (64 для меня).
Пожалуйста, дайте мне знать, если это работает для вас, а если нет, то что вы сделали, так как это может помочь мне с моим проектом 🙂
Ответ или решение
Ответ на вопрос о генерации текста на уровне слов с использованием векторов слов и выходом вектора вместо вероятностного распределения
При исследовании задачи генерации текста с использованием рекуррентных нейронных сетей (RNN) вы столкнулись с интересной идеей: вместо того чтобы использовать стандартный метод предсказания следующего слова с помощью вероятностного распределения (например, через one-hot векторы), вы хотите выводить непосредственно вектор, который представляет следующее слово. Это действительно интересный подход, и он имеет своё название и применения в сообществе.
Подход, который вы описали, можно считать частью методов векторного представления слов, которые успешно применяются в различных задачах обработки естественного языка (NLP). Один из наиболее близких методов к вашему интересу – это декодирование векторов слов, основанное на векторном представлении, таком как Word2Vec, GloVe и т.д. Выход вашей модели будет представлять собой вектор, который затем может быть сопоставлен с ближайшим вектором из предобученного словаря с использованием метода, подобного косинусному сходству.
Ваше предположение о том, что это будет задача регрессии, верно, поскольку вы стремитесь минимизировать ошибку между предсказанным вектором и целевым вектором. Это все делает задачу несколько похожей на модели, подобные автоэнкодерам, но с учетом того, что вам нужно работать с временными последовательностями, поэтому LSTM (долгосрочная краткосрочная память) будет хорошим выбором для вашей модели.
Подход к решению задачи:
-
Предобучение векторов слов: Как вы уже делали, используйте библиотеку Gensim для создания векторного представления вашего словаря. Убедитесь, что ваши векторы имеют фиксированную размерность, например 64.
-
Создание модели: Как вы правильно поняли, вам стоит избавиться от слоя Embedding, если у вас уже есть векторы слов. Начните вашу сеть с LSTM-блоков, а затем добавьте полносвязный слой для предсказания вектора:
model = tf.keras.Sequential() model.add(tf.keras.layers.LSTM(100, return_sequences=True)) model.add(tf.keras.layers.LSTM(100)) model.add(tf.keras.layers.Dense(100, activation='relu')) model.add(tf.keras.layers.Dense(64)) # Размер вектора слова
-
Компиляция модели: Вместо кросс-энтропии вы сможете использовать функцию потерь, основанную на косинусном сходстве (cosine similarity), что будет более подходящим для вашей задачи:
model.compile(loss="cosine_similarity", optimizer="adam", metrics=['accuracy'])
-
Обучение модели: Обучите свою модель на подготовленных данных. Убедитесь, что у вас достаточное количество данных для минимизации переобучения.
-
Декодирование выходного вектора: После предсказания используйте метод
most_similar()
из Gensim для нахождения ближайшего слова к выходному вектору. Это позволит вам интерпретировать ваш результат в контексте текста.
Заключение
Ваш подход к тому, чтобы выводить вектора вместо вероятностных распределений, является важным дополнением к традиционным методам. Этот метод может привести к лучшему пониманию контекстуального значения слов и более естественной генерации текста, так как он учитывает семантические связи между словами.
Удачи в вашем проекте! Если у вас возникнут дополнительные вопросы по имплементации или дальнейшему улучшению модели, не стесняйтесь обращаться за помощью.