Рекуррентные нейронные сети на примере Python

Использование рекуррентной нейронной сети для написания рефератов патентов

В первый раз, когда я попытался изучить рекуррентные нейронные сети, я совершил ошибку, попытавшись сначала изучить теорию, лежащую в основе таких вещей, как LSTM и GRU. После нескольких разочаровывающих дней изучения уравнений линейной алгебры я наткнулся на следующий отрывок из Глубокое обучение с помощью Python:

Таким образом, вам не нужно понимать все о конкретной архитектуре ячейки LSTM; как человек, не ваша работа понимать это. Просто имейте в виду, для чего предназначена ячейка LSTM: позволять повторно вводить прошлую информацию в более позднее время.

Это был автор библиотеки Керас (Франсуа Шоле), эксперт в области глубокого обучения, и сказал мне, что мне не нужно понимать все на фундаментальном уровне! Я понял, что моя ошибка заключалась в том, что я начал с теории, а не просто пытался построить повторяющуюся нейронную сеть.

Вскоре после этого я сменил тактику и решил попробовать наиболее эффективный способ изучения техники обработки данных: найти проблему и решить ее!

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

В этой статье рассказывается, как создать и использовать рекуррентную нейронную сеть в Keras для написания рефератов патентов. В статье нет теории, но, работая над проектом, вы обнаружите, что усвоите то, что вам нужно знать по ходу дела. В конечном итоге вы можете создать полезное приложение и выяснить, как работает метод глубокого обучения для обработки естественного языка.

Полный код доступен в виде серии Блокноты Jupyter на GitHub. Я также предоставил все предварительно обученные модели, так что вам не придется тренировать их несколько часов самостоятельно! Чтобы как можно быстрее приступить к работе и изучить модели, см. Быстрый старт для рекуррентных нейронных сетей, а для более подробных объяснений см. Глубокое погружение в рекуррентные нейронные сети.

Рекуррентная нейронная сеть

Прежде чем приступить к реализации, полезно понять хотя бы некоторые основы. На высоком уровне рекуррентная нейронная сеть (RNN) обрабатывает последовательности - будь то ежедневные цены акций, предложения или измерения датчиков - по одному элементу за раз, сохраняя память (называемую состоянием) что было раньше в последовательности.

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

Эта память позволяет сети узнавать долгосрочные зависимости в последовательности, что означает, что она может учитывать весь контекст при прогнозировании, будь то следующее слово в предложении, классификация настроений и т. Д. или следующее измерение температуры. RNN имитирует человеческий способ обработки последовательностей: при формировании ответа мы учитываем все предложение, а не слова сами по себе. Например, рассмотрим следующее предложение:

«Концерт был скучным первые 15 минут, пока группа разогревалась, но потом был ужасно захватывающим».

Модель машинного обучения, которая рассматривает слова по отдельности, например модель мешка слов, вероятно, сделает это предложение отрицательным. RNN, напротив, должна уметь видеть слова но и ужасно возбуждающе и понимать, что предложение меняется с отрицательного на положительное, потому что в нем просматривается вся последовательность. Чтение всей последовательности дает нам контекст для обработки ее значения, концепцию, закодированную в повторяющихся нейронных сетях.

В основе RNN лежит слой ячеек памяти. Самой популярной ячейкой на данный момент является Долгосрочная кратковременная память (LSTM), которая поддерживает состояние ячейки, а также перенос для обеспечения того, чтобы сигнал (информация в форме градиента) не терялся в виде последовательность обрабатывается. На каждом временном шаге LSTM учитывает текущее слово, перенос и состояние ячейки.

LSTM имеет 3 различных логических элемента и весовых вектора: есть вентиль «забыть» для отбрасывания нерелевантной информации; «входной» вентиль для обработки текущего входа и «выходной» вентиль для создания прогнозов на каждом временном шаге. Однако, как указывает Шолле, бесполезно пытаться придать конкретное значение каждому элементу в ячейке.

Функция каждого элемента ячейки в конечном итоге определяется параметрами (весами), которые изучаются во время обучения. Не стесняйтесь маркировать каждую часть ячейки, но это не обязательно для эффективного использования! Напомним, преимущество рекуррентной нейронной сети для обучения последовательности состоит в том, что она поддерживает память всей последовательности, предотвращая потерю предыдущей информации.

Постановка проблемы

Есть несколько способов, которыми мы можем сформулировать задачу обучения RNN написанию текста, в данном случае патентных рефератов. Однако мы предпочтем обучить его как преобразователю последовательностей "многие-к-одному". То есть мы вводим последовательность слов и обучаем модель предсказывать следующее слово. Слова будут сопоставлены с целыми числами, а затем с векторами с использованием матрицы встраивания (предварительно обученной или обучаемой) перед передачей на уровень LSTM.

Когда мы идем писать новый патент, мы передаем начальную последовательность слов, делаем прогноз для следующего слова, обновляем входную последовательность, делаем еще один прогноз, добавляем слово в последовательность и продолжаем, сколько слов хотим генерировать.

Шаги подхода изложены ниже:

  1. Преобразование отрывков из списка строк в список списков целых чисел (последовательностей)
  2. Создание объектов и меток из последовательностей
  3. Создание модели LSTM с использованием слоев Embedding, LSTM и Dense.
  4. Загрузить предварительно обученные вложения
  5. Обучите модель предсказывать следующую работу в последовательности
  6. Делайте прогнозы, переходя в начальную последовательность

Имейте в виду, что это только одна формулировка проблемы: мы также можем использовать модель уровня персонажа или делать прогнозы для каждого слова в последовательности. Как и в случае со многими концепциями машинного обучения, нет одного правильного ответа, но этот подход хорошо работает на практике.

Подготовка данных

Даже при наличии мощной репрезентативной способности нейронной сети получение качественного и чистого набора данных имеет первостепенное значение. Необработанные данные для этого проекта поступают из USPTO PatentsView, где вы можете искать информацию по любому патенту, поданному в США. Я искал термин нейронная сеть и скачал получившиеся рефераты патентов - всего 3500. Я посчитал, что лучше обучаться по узкой теме, но не стесняйтесь пробовать с другим набором патентов.

Мы начнем с рефератов патентов в виде списка строк. Основные этапы подготовки данных для нашей модели:

  1. Удалите знаки препинания и разбейте строки на списки отдельных слов.
  2. Преобразуйте отдельные слова в целые числа

Оба эти шага можно выполнить с помощью класса Keras Tokenizer. По умолчанию при этом удаляются все знаки препинания и строчные буквы, а затем слова преобразуются в sequences целых чисел. Tokenizer сначала fit в списке строк, а затем преобразует этот список в список списков целых чисел. Это показано ниже:

Вывод первой ячейки показывает исходное резюме, а вывод второй - токенизированную последовательность. Каждый реферат теперь представлен в виде целых чисел.

Мы можем использовать атрибут idx_word обученного токенизатора, чтобы выяснить, что означает каждое из этих целых чисел:

Если вы присмотритесь, то заметите, что Tokenizer убирает все знаки препинания и переводит все слова в нижний регистр. Если мы воспользуемся этими настройками, то нейросеть не выучит правильный английский! Мы можем отрегулировать это, изменив фильтры на Tokenizer, чтобы не удалять знаки препинания.

# Don't remove punctuation or uppercase
tokenizer = Tokenizer(num_words=None, 
                     filters='#$%&()*+-<=>@[\\]^_`{|}~\t\n',
                     lower = False, split = ' ')

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

Характеристики и ярлыки

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

Дайте сети последовательность слов и научите ее предсказывать следующее слово.

Количество слов остается параметром; мы будем использовать 50 для показанных здесь примеров, что означает, что мы даем нашей сети 50 слов и обучаем ее предсказывать 51-е. Другими способами обучения сети было бы предсказание следующего слова в каждой точке последовательности (прогнозирование для каждого входного слова, а не один раз для всей последовательности) или обучение модели с использованием отдельных символов. Используемая здесь реализация не обязательно оптимальна - не существует принятого лучшего решения - но работает хорошо!

Создание функций и меток относительно просто, и для каждого абстрактного (представленного в виде целых чисел) мы создаем несколько наборов функций и меток. Мы используем первые 50 слов как признаки с 51-м как метку, затем используем слова 2–51 как признаки и предсказываем 52-е и так далее. Это дает нам значительно больше обучающих данных, что полезно, потому что производительность сети пропорциональна количеству данных, которые она видит во время обучения.

Ниже представлена ​​реализация создания функций и меток:

Функции заканчиваются формой (296866, 50), что означает, что у нас есть почти 300 000 последовательностей, каждая из которых содержит 50 токенов. На языке рекуррентных нейронных сетей каждая последовательность имеет 50 временных шагов, каждая с 1 функцией.

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

Чтобы найти слово, соответствующее строке в label_array, мы используем:

После того, как все наши функции и метки отформатированы должным образом, мы хотим разделить их на набор для обучения и проверки (подробности см. В блокноте). Одним из важных моментов здесь является одновременное перемешивание функций и меток, чтобы одни и те же абстракты не попали в один набор.

Построение рекуррентной нейронной сети

Keras - невероятная библиотека: она позволяет нам создавать современные модели в несколько строк понятного кода Python. Хотя другие библиотеки нейронных сетей могут быть быстрее или обеспечивать большую гибкость, ничто не может сравниться с Keras по времени разработки и простоте использования.

Ниже приведен код простого LSTM со следующим объяснением:

Мы используем Keras Sequential API, что означает, что мы строим сеть на один уровень за раз. Слои следующие:

  • Embedding, который отображает каждое входное слово в 100-мерный вектор. Встраивание может использовать предварительно обученные веса (подробнее через секунду), которые мы указываем в параметре weights. trainable можно установить False, если мы не хотим обновлять вложения.
  • Слой Masking для маскировки любых слов, не имеющих предварительно обученного вложения, который будет представлен как все нули. Этот слой не следует использовать при обучении вложений.
  • Сердце сети: слой LSTM cells с выпадением во избежание переобучения. Поскольку мы используем только один слой LSTM, он не возвращает последовательности, для использования двух или более слоев обязательно возвращайте последовательности.
  • Полностью связанный Dense слой с relu активацией. Это добавляет к сети дополнительную репрезентативную емкость.
  • Слой Dropout для предотвращения переобучения обучающих данных.
  • Dense полностью подключенный выходной слой. Это дает вероятность для каждого слова в словаре с использованием softmax активации.

Модель скомпилирована с помощью оптимизатора Adam (вариант стохастического градиентного спуска) и обучена с использованием categorical_crossentropy потерь. Во время обучения сеть будет пытаться минимизировать потерю журнала, регулируя обучаемые параметры (веса). Как всегда, градиенты параметров вычисляются с использованием обратного распространения и обновляются с помощью оптимизатора. Поскольку мы используем Keras, нам не нужно беспокоиться о том, как это происходит за кулисами, только о правильной настройке сети.

Без обновления эмбеддингов в сети будет гораздо меньше параметров для обучения. Входными данными для слоя LSTM является (None, 50, 100), что означает, что для каждого пакета (первое измерение) каждая последовательность имеет 50 временных шагов (слов), каждый из которых имеет 100 функций после встраивания. Вход в слой LSTM всегда имеет форму (batch_size, timesteps, features).

Есть много способов структурировать эту сеть, и есть несколько других, рассмотренных в записной книжке. Например, мы можем использовать два LSTM слоя, наложенных друг на друга, Bidirectional LSTM слой, который обрабатывает последовательности с обоих направлений, или несколько Dense слоев. Я обнаружил, что описанная выше установка работает хорошо.

Предварительно обученные вложения

После того, как сеть построена, мы все равно должны снабдить ее предварительно обученными вложениями слов. Существуют многочисленные вложения, которые вы можете найти в Интернете, обученные на разных корпусах (большие объемы текста). Те, которые мы будем использовать, доступны из Стэнфорда и имеют размеры 100, 200 или 300 (мы будем придерживаться 100). Эти вложения взяты из алгоритма GloVe (глобальные векторы для представления слов) и были обучены в Википедии.

Несмотря на то, что предварительно обученные вложения содержат 400 000 слов, в нашем словаре есть некоторые слова, которые включены. Когда мы представляем эти слова с вложениями, они будут иметь 100-мерные векторы всех нулей. Эту проблему можно решить, обучив наши собственные вложения или установив для параметра Embedding слоя trainable значение True (и удалив слой Masking).

Мы можем быстро загрузить предварительно обученные вложения с диска и создать матрицу встраивания с помощью следующего кода:

При этом каждому слову в словаре присваивается 100-мерный вектор. Если слово не имеет предварительно обученного вложения, тогда в этом векторе будут все нули.

Чтобы исследовать вложения, мы можем использовать косинусное сходство, чтобы найти слова, наиболее близкие к заданному слову запроса в пространстве вложения:

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

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

Обучение модели

Подготовив данные для обучения и проверки, построив сеть и загруженные вложения, мы почти готовы к использованию нашей модели, чтобы научиться писать рефераты патентов. Однако при обучении нейронных сетей рекомендуется использовать ModelCheckpoint и EarlyStopping в форме обратных вызовов Keras:

  • Контрольная точка модели: сохраняет лучшую модель (измеряемую потерями при проверке) на диске для использования лучшей модели
  • Ранняя остановка: останавливает обучение, когда потеря валидации больше не уменьшается

Использование Early Stopping означает, что мы не переусердствуем с данными обучения и не будем тратить время на обучение для дополнительных эпох, которые не улучшают производительность. Контрольная точка модели означает, что мы можем получить доступ к лучшей модели, и, если наше обучение прервется через 1000 эпох, мы не потеряем весь прогресс!

Затем модель можно обучить с помощью следующего кода:

На инстансе Amazon p2.xlarge (зарезервировано 0,90 доллара США в час) это заняло чуть более часа. После завершения обучения мы можем загрузить обратно в наиболее сохраненную модель и оценить окончательное время проверки данных.

from keras import load_model
# Load in model and evaluate on validation data
model = load_model('../models/model.h5')
model.evaluate(X_valid, y_valid)

В целом модель с использованием предварительно обученных встраиваний слов достигла точности проверки 23,9%. Это довольно хорошо, учитывая, что мне, как человеку, чрезвычайно трудно предсказать следующее слово в этих отрывках! Наивное угадывание наиболее употребительного слова («the») дает точность около 8%. Показатели для всех моделей ноутбука показаны ниже:

Лучшая модель использовала предварительно обученные вложения и ту же архитектуру, что и показанная выше. Я рекомендую всем попробовать тренироваться с другой моделью!

Патентное реферат поколения

Конечно, хотя высокие показатели - это хорошо, важно то, может ли сеть выдавать разумные патентные рефераты. Используя лучшую модель, мы можем изучить возможность создания модели. Если вы хотите запустить это на собственном оборудовании, вы можете найти блокнот здесь, а предварительно обученные модели - на GitHub.

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

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

Выход неплохой! Иногда бывает сложно определить, что сгенерировано компьютером, а что - машиной. Частично это связано с природой рефератов патентов, которые в большинстве случаев не выглядят так, как будто они были написаны человеком.

Другое использование сети - это заполнение ее нашей собственной начальной последовательностью. Мы можем использовать любой текст, какой захотим, и посмотреть, куда его ведет сеть:

Опять же, результаты не совсем правдоподобны, но они напоминают английский язык.

Человек или машина?

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

Какое ваше предположение? Ответ заключается в том, что секунда - это реферат, написанный человеком (ну, это то, что было на самом деле в реферате. Я не уверен, что эти рефераты написаны людьми). Вот еще один:

На этот раз у третьего был писатель из плоти и крови.

Есть дополнительные шаги, которые мы можем использовать для интерпретации модели, например, определение того, какие нейроны загораются с разными входными последовательностями. Мы также можем посмотреть изученные вложения (или визуализировать их с помощью Projector tool). Мы оставим эти темы на другой раз и сделаем вывод, что теперь мы знаем , как реализовать повторяющуюся нейронную сеть для эффективного имитации человеческого текста.

Выводы

Важно понимать, что повторяющаяся нейронная сеть не имеет понятия о понимании языка. По сути, это очень сложная машина для распознавания образов. Тем не менее, в отличие от таких методов, как цепи Маркова или частотный анализ, rnn делает прогнозы на основе упорядочения элементов в последовательности. Немного пофилософствуя здесь, вы можете утверждать, что люди - это просто экстремальные машины для распознавания образов, и поэтому рекуррентная нейронная сеть действует только как человеческая машина.

Использование рекуррентных нейронных сетей выходит далеко за рамки генерации текста и включает машинный перевод, подпись изображений и идентификацию авторства. Хотя это приложение, которое мы здесь рассмотрели, не вытеснит людей, вполне вероятно, что с большим количеством обучающих данных и более крупной моделью нейронная сеть сможет синтезировать новые разумные отрывки из патентов.

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

Как всегда, я приветствую отзывы и конструктивную критику. Со мной можно связаться в Twitter @koehrsen_will или на моем веб-сайте willk.online.