Переосмысление Плутарха с помощью Tensorflow 2.0
Плутарх "Жизни благородных греков и римлян через вложения слов в TensorFlow 2.0"
Преамбула
Жизни благородных греков и римлян Плутарха, также называемые Параллельные жизни или просто Жизни Плутарха, представляют собой серию биографий знаменитых древних греков. и римляне, от Тесея и Ликурга до Марка Антония.
В недавно опубликованной статье мы рассмотрели возможность обучения нашим собственным вложениям слов с помощью библиотеки gensim. Здесь мы в первую очередь сосредоточимся на слое встраивания слов, использующем платформу TensorFlow 2.0; цель состоит в том, чтобы лучше понять, как работает слой и как он способствует успеху более крупных моделей НЛП.
Чтобы упростить репликацию, я адаптировал код для Google Colab и выделил уникальные особенности этой платформы - в противном случае весь код можно запустить на вашем локальном компьютере с помощью Python 3.6+ и соответствующих пакетов. Код представлен на протяжении всей статьи, но я пропущу некоторые дополнительные или второстепенные коды - весь код можно найти в моем репозитории Github.
Текст, использованный в этом анализе, был предоставлен Проектом Гутенберг.
Настройка вещей
В Colab изменим Runtime Type на GPU, а затем импортируем последнюю версию TensorFlow - этот фрагмент ниже будет работать только в Colab, в противном случае просто используйте команды pip или conda install, чтобы загрузить последнюю версию TensorFlow на свой компьютер.
Нам также понадобятся ОС и библиотеки регулярных выражений, а затем мы сохраним и распечатаем путь к файлу для дальнейшего использования:
import os import re fpath = os.getcwd(); fpath
Давайте импортируем текст (Plutarch.txt) на диск Google Colab - нам нужно иметь в виду, что наши файлы там недолговечны, и нам нужно будет загружать их каждый раз после длительного перерыва в использовании платформы:
Приведенный выше код также доступен на вкладке Code Snippets в Colab - среди многих других очень полезных. При выполнении этого кода мы увидим, как Colab загружает файл, а затем мы можем щелкнуть вкладку Colab Files слева, чтобы убедиться, что файл находится там вместе с каталогом образцов данных Google по умолчанию.
Давайте прочитаем текст и выполним несколько основных операций с регулярными выражениями:
import re corpus = open(fpath + '/Plutarch.txt', 'rb').read().lower().decode(encoding='utf-8') corpus = re.sub('\n', ' ', corpus) #remove new line corpus = re.sub('\r', ' ', corpus) #remove "return"
Поскольку мы будем разбивать текст на предложения, новая строка не имеет значения для нашего анализа. Кроме того, при использовании текстового токенизатора я заметил, что наличие «\ r» (обозначающего возврат каретки) создает ложные уникальные слова, такие как «мы» и «мы \ r» - опять же, неважно в нашем случае. Следовательно, оба символа «\ n» и «\ r» должны быть удалены.
Создание словаря
По мере того, как мы приближаемся к фактическому встраиванию слов, давайте разберем текст на предложения:
import nltk from nltk.tokenize import sent_tokenize nltk.download('punkt') #need in Colab upon resetting the runtime # tokenize at sentence level sentences = nltk.sent_tokenize(corpus) print("The number of sentences is {}".format(len(sentences)))
Мы увидим, что в тексте всего 16 989 предложений. Затем нам нужно рассчитать количество слов в самых длинных предложениях - причина станет очевидной позже в уроке:
from nltk.tokenize import word_tokenize word_count = lambda sentence: len(word_tokenize(sentence)) longest_sentence = max(sentences, key=word_count) length_longest_sentence = len(word_tokenize(longest_sentence)) print("The longest sentence has {} words".format(length_longest_sentence))
Оказывается, самое длинное предложение состоит из 370 слов. Затем давайте преобразуем весь текст в положительные числа, чтобы мы могли говорить на одном языке с TensorFlow:
Из вышесказанного мы также выясняем, что текст содержит 20241 уникальное слово, поскольку токенизатор присваивает только одно число для одного и того же слова. Чтобы стандартизировать длину всех предложений (т.е. превратить входные данные в один тензор одинаковой формы, чтобы сделать их обрабатываемыми / упрощенными для модели - мы здесь, чтобы удовлетворить потребности машин), нам нужно преобразовать список чисел, представляющих слова (sent_numeric) в фактический словарь (word_index), и добавить заполнение. Мы также можем комбинировать усечение очень длинных предложений с заполнением коротких предложений, но в этом случае мы просто увеличим длину самого длинного предложения.
Размер словарного запаса (он же количество уникальных слов) увеличится на 1 до 20 242 в результате добавления 0 для заполнения. Введите «данные [0]» (т. Е. Первое предложение), чтобы увидеть, как будет выглядеть первое предложение с заполнением.
Чтобы иметь возможность переводить между словами и их числовыми представлениями, нам нужно добавить обратный указатель слов для поиска:
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()]) def decode_data(text): return ' '.join([reverse_word_index.get(i, '?') for i in text])
Имеет смысл перепроверить индексирование слов и преобразование - одна ошибка, скорее всего, отбросит весь набор данных и сделает его непонятным. Примеры перекрестной проверки - до и после конвертации - доступны в моем репозитории Github.
Модель
Наконец, давайте построим и запустим модель. TensorFlow предоставляет хороший учебник, который мы адаптируем к нашим потребностям.
Но сначала мы можем просто запустить только слой встраивания, который создаст массив встраивания. Я читал, что такой массив можно сохранить и использовать в другой модели - да, может, но помимо пропуска этапа внедрения в новую модель, я не так уверен в полезности, поскольку векторы, сгенерированные для каждого слова, агностик к решаемой проблеме:
Мы не будем тратить много времени на вышеизложенное, а сосредоточимся на моделях, в которых встраивание является лишь первой частью.
Давайте продолжим и построим новую, очень простую архитектуру модели после импорта соответствующих библиотек:
Слой внедрения, который обычно может использоваться в качестве первого уровня в модели, преобразует последовательности уникальных слов с числовой кодировкой (в качестве напоминания, 20 241 из них плюс заполнение, закодированное как ноль) в последовательности векторов, последние изучаются как модель поезда. Каждый вектор будет иметь 100 измерений (embedding_dim = 100), следовательно, в результате у нас будет матрица 20242 x 100 .. Длина ввода будет фиксирована на длину самого длинного предложения, то есть 370 слов, как каждое отдельное слово. воспринимается моделью как имеющий одинаковый размер из-за заполнения. Mask_zero сообщает модели, является ли входное значение 0 специальным значением заполнения, которое должно быть замаскировано, что особенно полезно в повторяющихся слоях, где модель может обрабатывать переменные входные длины.
После обучения на достаточно значимых данных слова с похожими значениями, вероятно, будут иметь похожие векторы.
Вот сводка модели (модель с дополнительным плотным слоем находится в репозитории github):
В сводке модели мы увидим, что количество параметров для слоя внедрения составляет 2 024 200, что на 20 242 слова умножено на размер встраивания, равный 100.
В ранее упомянутом руководстве TensorFlow используется набор данных обзоров, в котором каждый из обзоров имеет отметку 1 или 0 в зависимости от положительного или отрицательного настроения. У нас нет роскошных этикеток, но мы все же хотим протестировать эту модель, поэтому просто создадим массив нулей и прикрепим к каждому из предложений; модель требует такой конструкции. Это будет не первый и не последний раз, когда машинный интеллект сталкивается с неразрешимой задачей, но все же требует от нас решения. Обучим эту модель:
import numpy as np adam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) batch_size = 16989 #number of sentences data_labels = np.zeros([batch_size, 1]) history = model.fit( data, data_labels, epochs=200, batch_size=batch_size, verbose = 0)
Вложения обучены. Прежде чем перейти к визуализации, давайте быстро проверим сходство слов в gensim. Во-первых, нам нужно создать файл векторов - временно сохранить его в Colab или загрузить на локальный компьютер:
f = open('vectors.tsv' ,'w') f.write('{} {}\n'.format(vocab_size-1, embedding_dim)) vectors = model.get_weights()[0] for words, i in tokenizer.word_index.items(): str_vec = ' '.join(map(str, list(vectors[i, :]))) f.write('{} {}\n'.format(words, str_vec)) f.close() # download the file to the local machine by double-clicking the Colab file or using this: try: from google.colab import files except ImportError: pass else: files.download('vectors.tsv')
Во-вторых, давайте
import gensim w2v = gensim.models.KeyedVectors.load_word2vec_format('./vectors.tsv', binary=False) w2v.most_similar('rome')
Наконец, давайте проверим сходство между Помпеем и Цезарем, которое показало высокие результаты в модели CBOW, которую мы ранее обучили:
round(w2v.similarity('pompey', 'caesar'),4)
Связь между словами высокая. Кроме того, как и следовало ожидать, Цезарь очень похож на Рим.
Для тех, кто интересуется более сложными моделями, в моем файле Github доступны дополнительные варианты, включая рекуррентные нейронные сети (Long Short-Term Memory), но имейте в виду, что они будут обучаться намного медленнее, чем простая модель выше.
Визуализация
Для визуализации эмбеддингов сложно превзойти проектор TensorFlow, поэтому давайте создадим векторные и мета-файлы (то есть слова, соответствующие этим векторам) для его использования:
Импортируйте файлы локально, а затем мы можем перейти в TensorFlow’s Projector, загрузить файлы, чтобы заменить данные по умолчанию, и попробовать различные варианты, доступные на сайте. Вот вид анализа основных компонентов всего векторного пространства текста:
А вот только векторное пространство для 100 слов, которые оказались наиболее похожими на «Рим».
Вывод
В этой статье мы кратко рассмотрели роль слоя встраивания слов в модели глубокого обучения. В контексте такой модели уровень поддерживает решение конкретной задачи НЛП - например, классификация текста - и посредством итераций тренирует словарные векторы, чтобы они были наиболее подходящими для минимизации потерь модели. После обучения модели мы можем проверить вывод слоя внедрения с помощью вычислений подобия и визуализаций.
Слой внедрения также можно использовать для загрузки предварительно обученных встраиваний слов (например, GloVe, BERT, FastText, ELMo), что, как я считаю, обычно было бы более продуктивным способом использования моделей, требующих таких встраиваний - отчасти из-за «промышленного уровня». ”Усилия и объем данных, необходимые для их создания. Однако в случаях специализированного текста и особенно если корпус, на котором могут быть обучены вложения слов, велик, обучение собственных встраиваний все еще может быть более эффективным.