- PVSM.RU - https://www.pvsm.ru -

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 1

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

Статья посвящена визуализации при помощи t-SNE рассчитанных Word2Vec многомерных векторных представлений слов. Визуализация позволит полнее понять принцип работы Word2Vec и то, как следует интерпретировать отношения между векторами слов перед дальнейшем использованием в нейросетях и других алгоритмах машинного обучения. В статье акцентируется внимание именно на визуализации, дальнейшее исследование и анализ данных не рассматриваются. В качестве источника данных мы задействуем статьи из Google News и классические произведения Л.Н. Толстого. Код будем писать на Python в Jupyter Notebook.

T-distributed Stochastic Neighbor Embedding

T-SNE — алгоритм машинного обучения для визуализации данных на основе метода нелинейного снижения размерности, который подробно описан в оригинальной статье [1] и на Хабре [1]. Базовый принцип работы t-SNE заключается в сокращении попарных расстояний между точками при сохранении их относительного расположения. Иными словами, алгоритм отображает многомерные данные на пространство более низкой размерности, при этом сохраняя структуру соседства точек.

Векторные представления слов и Word2Vec

Прежде всего нам необходимо представить слова в векторном виде. Для этой задачи я выбрал утилиту дистрибутивной семантики Word2Vec, которая предназначена для отображения семантического значения слов в векторное пространство. Word2Vec находит взаимосвязи между словами согласно предположению, что в схожих контекстах встречаются семантически близкие слова. Подробнее о Word2Vec можно прочитать в оригинальной статье [2], а также тут [2] и тут [3].

В качестве входных данных мы возьмем статьи из Google News и романы Л.Н. Толстого. В первом случае воспользуемся предобученными на датасете Google News (около 100 млрд слов) векторами, опубликованными Google на странице проекта [4].

import gensim

model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)

В дополнение к предварительно обученным векторам при помощи библиотеки Gensim [3] мы обучим еще одну модель на текстах Л.Н. Толстого. Поскольку Word2Vec в качестве входных данных принимает массив предложений, мы используем предобученную модель Punkt Sentence Tokenizer из пакета NLTK для автоматического разбиения текста на предложения. Модель для русского языка можно скачать отсюда [5].

import re
import codecs


def preprocess_text(text):
    text = re.sub('[^a-zA-Zа-яА-Я1-9]+', ' ', text)
    text = re.sub(' +', ' ', text)
    return text.strip()


def prepare_for_w2v(filename_from, filename_to, lang):
    raw_text = codecs.open(filename_from, "r", encoding='windows-1251').read()
    with open(filename_to, 'w', encoding='utf-8') as f:
        for sentence in nltk.sent_tokenize(raw_text, lang):
            print(preprocess_text(sentence.lower()), file=f)

Далее с помощью библиотеки Gensim обучим Word2Vec-модель со следующими параметрами:

  • size = 200 — размерность признакового пространства;
  • window = 5 — количество слов из контекста, которое анализирует алгоритм;
  • min_count = 5 — слово должно встречаться минимум пять раз, чтобы модель его учитывала.

import multiprocessing
from gensim.models import Word2Vec


def train_word2vec(filename):
    data = gensim.models.word2vec.LineSentence(filename)
    return Word2Vec(data, size=200, window=5, min_count=5, workers=multiprocessing.cpu_count())

Визуализация векторных представлений слов с помощью t-SNE

T-SNE крайне полезен для визуализации сходства между объектами в многомерном пространстве. С увеличением количества данных становится всё сложнее и сложнее построить наглядный график, поэтому на практике близкие слова объединяют в группы для дальнейшей визуализации. Возьмем для примера несколько слов из словаря предварительно обученной на Google News Word2Vec-модели.

keys = ['Paris', 'Python', 'Sunday', 'Tolstoy', 'Twitter', 'bachelor', 'delivery', 'election', 'expensive',
        'experience', 'financial', 'food', 'iOS', 'peace', 'release', 'war']

embedding_clusters = []
word_clusters = []
for word in keys:
    embeddings = []
    words = []
    for similar_word, _ in model.most_similar(word, topn=30):
        words.append(similar_word)
        embeddings.append(model[similar_word])
    embedding_clusters.append(embeddings)
    word_clusters.append(words)

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 2
Рисунок 1. Группы схожих слов из Google News с разным значением параметра preplexity.

Далее переходим к самому примечательному фрагменту статьи — конфигурации t-SNE. Здесь в первую очередь следует обратить внимание на следующие гиперпараметры:

  • n_components — количество компонентов, т.е., размерность пространства значений;
  • perplexity — перплексия, значение которой в t-SNE можно приравнять к эффективному количеству соседей. Она родственна количеству ближайших соседей, которое используется в других моделях, обучающихся на базе многообразий (см. картинку выше). Ее значение рекомендуется [1] устанавливать в диапазоне 5—50;
  • init — тип первоначальной инициализации векторов.

tsne_model_en_2d = TSNE(perplexity=15, n_components=2, init='pca', n_iter=3500, random_state=32)
embedding_clusters = np.array(embedding_clusters)
n, m, k = embedding_clusters.shape
embeddings_en_2d = np.array(tsne_model_en_2d.fit_transform(embedding_clusters.reshape(n * m, k))).reshape(n, m, 2)

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

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 3
Рисунок 2. Группы схожих слов из Google News (preplexity=15).

from sklearn.manifold import TSNE

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
% matplotlib inline


def tsne_plot_similar_words(labels, embedding_clusters, word_clusters, a=0.7):
    plt.figure(figsize=(16, 9))
    colors = cm.rainbow(np.linspace(0, 1, len(labels)))
    for label, embeddings, words, color in zip(labels, embedding_clusters, word_clusters, colors):
        x = embeddings[:,0]
        y = embeddings[:,1]
        plt.scatter(x, y, c=color, alpha=a, label=label)
        for i, word in enumerate(words):
            plt.annotate(word, alpha=0.5, xy=(x[i], y[i]), xytext=(5, 2), 
                         textcoords='offset points', ha='right', va='bottom', size=8)
    plt.legend(loc=4)
    plt.grid(True)
    plt.savefig("f/г.png", format='png', dpi=150, bbox_inches='tight')
    plt.show()


tsne_plot_similar_words(keys, embeddings_en_2d, word_clusters)

Иногда бывает нужно построить не отдельные кластеры слов, а весь словарь целиком. Для этой цели давайте проанализируем «Анну Каренину», великую историю страсти, измены, трагедии и искупления.

prepare_for_w2v('data/Anna Karenina by Leo Tolstoy (ru).txt', 'train_anna_karenina_ru.txt', 'russian')
model_ak = train_word2vec('train_anna_karenina_ru.txt')

words = []
embeddings = []
for word in list(model_ak.wv.vocab):
    embeddings.append(model_ak.wv[word])
    words.append(word)
    
tsne_ak_2d = TSNE(n_components=2, init='pca', n_iter=3500, random_state=32)
embeddings_ak_2d = tsne_ak_2d.fit_transform(embeddings)

def tsne_plot_2d(label, embeddings, words=[], a=1):
    plt.figure(figsize=(16, 9))
    colors = cm.rainbow(np.linspace(0, 1, 1))
    x = embeddings[:,0]
    y = embeddings[:,1]
    plt.scatter(x, y, c=colors, alpha=a, label=label)
    for i, word in enumerate(words):
        plt.annotate(word, alpha=0.3, xy=(x[i], y[i]), xytext=(5, 2), 
                     textcoords='offset points', ha='right', va='bottom', size=10)
    plt.legend(loc=4)
    plt.grid(True)
    plt.savefig("hhh.png", format='png', dpi=150, bbox_inches='tight')
    plt.show()


tsne_plot_2d('Anna Karenina by Leo Tolstoy', embeddings_ak_2d, a=0.1)

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 4

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 5
Рисунок 3. Визуализация словаря Word2Vec-модели, обученной на романе «Анна Каренина».

Картина может стать еще более информативной, если мы используем трехмерное пространство. Взглянем на «Войну и мир», один из главных романов мировой литературы.

prepare_for_w2v('data/War and Peace by Leo Tolstoy (ru).txt', 'train_war_and_peace_ru.txt', 'russian')
model_wp = train_word2vec('train_war_and_peace_ru.txt')

words_wp = []
embeddings_wp = []
for word in list(model_wp.wv.vocab):
    embeddings_wp.append(model_wp.wv[word])
    words_wp.append(word)
    
tsne_wp_3d = TSNE(perplexity=30, n_components=3, init='pca', n_iter=3500, random_state=12)
embeddings_wp_3d = tsne_wp_3d.fit_transform(embeddings_wp)

from mpl_toolkits.mplot3d import Axes3D


def tsne_plot_3d(title, label, embeddings, a=1):
    fig = plt.figure()
    ax = Axes3D(fig)
    colors = cm.rainbow(np.linspace(0, 1, 1))
    plt.scatter(embeddings[:, 0], embeddings[:, 1], embeddings[:, 2], c=colors, alpha=a, label=label)
    plt.legend(loc=4)
    plt.title(title)
    plt.show()


tsne_plot_3d('Visualizing Embeddings using t-SNE', 'War and Peace', embeddings_wp_3d, a=0.1)

Google News и Лев Толстой: визуализация векторных представлений слов с помощью t-SNE - 6
Рисунок 4. Визуализация словаря Word2Vec-модели, обученной на романе «Война и Мир».

Исходники

Код доступен на GitHub [6]. Там же вы можете найти код для отрисовки анимаций.

Источники

  1. Maaten L., Hinton G. Visualizing data using t-SNE //Journal of machine learning research. – 2008. – Т. 9. – С. 2579-2605.
  2. Distributed Representations of Words and Phrases and their Compositionality //Advances in Neural Information Processing Systems. – 2013. – С. 3111-3119.
  3. Rehurek R., Sojka P. Software framework for topic modelling with large corpora //In Proceedings of the LREC 2010 Workshop on New Challenges for NLP Frameworks. – 2010.

Автор: sismetanin

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/302164

Ссылки в тексте:

[1] Хабре: https://habr.com/post/267041/

[2] тут: https://habr.com/company/ods/blog/329410/

[3] тут: https://habr.com/post/249215/

[4] на странице проекта: https://code.google.com/archive/p/word2vec/

[5] отсюда: https://github.com/mhq/train_punkt

[6] GitHub: https://github.com/sismetanin/word2vec-tsne

[7] Источник: https://habr.com/post/426113/?utm_campaign=426113