company_banner

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



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

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

    T-distributed Stochastic Neighbor Embedding


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

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


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

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

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

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

    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)


    Рисунок 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.


    Рисунок 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)




    Рисунок 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)


    Рисунок 4. Визуализация словаря Word2Vec-модели, обученной на романе «Война и Мир».

    Исходники


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

    Источники


    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.
    • +26
    • 6,6k
    • 9
    Mail.ru Group
    850,06
    Строим Интернет
    Поделиться публикацией

    Комментарии 9

      +5
      Не понятно, что означает полученный узор в виде дерева с двумя кронами. Одна крона — война, а другая — мир?
        0
        Очевидно, что это альвеола
          +1
          Скорее одна часть — русские слова, другая — французские)
            0
            Тоже склоняюсь к варианту с русскими и французскими словами, но однозначно дать ответ на вопрос не могу, так как необходимо более подробно изучать данные.
          +2
          3D модель (итоговая картинка, что крутится до ката) похожа на легкие человека. Подумал, что будет что-то около-медицинское. Даже затемнение в легком нашел :)
            0
            3D модель (итоговая картинка, что крутится до ката) похожа на легкие человека.
            «На словах ты Лев Толстой»: мем обретает второе дыхание.
              0
              Возможно, когда-то мы найдём такие закономерности, что сможем диагностировать соматические заболевания по персональному дискурсу. Скормил текстовый контент нейросетке, а она тебе облако словоформ, определяющих недуг в определённом органе или системе.
              0
              Хотелось бы посмотреть не только на tSNE, но и на другие методы нелинейного снижения размерности типа Uniform Manifold Approximation and Projection (UMAP). На практике для кластеризации он лучше пригоден.
                0
                Отличная статья.
                Я делал совершенно то же самое год назад, когда человек отвечающий за помсковик сказал что он вручную мониторит что люди вбивают в поиск. Этим методом от оптимизировал топ 100, а этим методом стало возможно 5000.
                Кому интересно — public.tableau.com/profile/arakel#!/vizhome/Portfolio_30/DataScienceProject

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

                Самое читаемое