Учим компьютер писать как Толстой, том I

— Eh bien, mon prince. Gênes et Lucques ne sont plus que des apanages, des поместья, de la famille Buonaparte. Non, je vous préviens que si vous ne me dites pas que nous avons la guerre, si vous vous permettez encore de pallier toutes les infamies, toutes les atrocités de cet Antichrist (ma parole, j'y crois) — je ne vous connais plus, vous n'êtes plus mon ami, vous n'êtes plus мой верный раб, comme vous dites 1. Ну, здравствуйте, здравствуйте. Je vois que je vous fais peur 2, садитесь и рассказывайте.

ТОМ ПЕРВЫЙ


ЧАСТЬ ПЕРВАЯ. Анна Каренина


Недавно на хабре наткнулся на эту статью https://habrahabr.ru/post/342738/. И захотелось написать про word embeddings, python, gensim и word2vec. В этой части я постараюсь рассказать о обучении базовой модели w2v.


Итак, приступаем.


  • Качаем anaconda. Устанавливаем.
  • Еще нам пригодится C/C++ tools от visual studio.
  • Теперь устанавливаем gensim. Именно для него нам и нужен c++.
  • Устанавливаем nltk.
  • При установке не забудьте качать библиотеки для Anaconda, а не для стандартного интерпретатора. Иначе все кончится крахом.
  • Качаем Анну Каренину в TXT.
  • Советую открыть файл и вырезать оттуда рекламу и заголовки. Потом сохранить в формате utf-8.
  • Можно приступать к работе.

Первым делом надо скачать данные для nltk.


import nltk
nltk.dwonload()

В открывшемся окошке выбираем все, и идем пить кофе. Это займет около получаса.
По умолчанию в библиотеке русского языка нет. Но умельцы все сделали за нас. Качаем https://github.com/mhq/train_punkt и извлекаем все в папку
C:\Users\<username>\AppData\Roaming\nltk_data\tokenizers\punkt и
C:\Users\<username>\AppData\Roaming\nltk_data\tokenizers\punkt\PY3.


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


conda create -n tolstoy-like

Активируем.


activate tolstoy

Туда же кидаем текст. Назовем файл anna.txt
Для обладателей PyCharm можно просто создать проект и в качестве интерпретатора выбрать анаконду, не создавая окружения.


Создаем скрипт train-I.py.


  • Подключаем зависимости.


    # -*- coding: utf-8 -*-
    # imports
    import gensim
    import string
    from nltk.tokenize import sent_tokenize
    from nltk.corpus import stopwords
    from nltk.tokenize import word_tokenize

  • Считываем текст.


    # load text
    text = open('./anna.txt', 'r', encoding='utf-8').read()

  • Теперь очередь токенизатора русских предложений.


    def tokenize_ru(file_text):
    # firstly let's apply nltk tokenization
    tokens = word_tokenize(file_text)
    
    # let's delete punctuation symbols
    tokens = [i for i in tokens if (i not in string.punctuation)]
    
    # deleting stop_words
    stop_words = stopwords.words('russian')
    stop_words.extend(['что', 'это', 'так', 'вот', 'быть', 'как', 'в', '—', '–', 'к', 'на', '...'])
    tokens = [i for i in tokens if (i not in stop_words)]
    
    # cleaning words
    tokens = [i.replace("«", "").replace("»", "") for i in tokens]
    
    return tokens

    На этом остановимся по подробнее. В первой строчке мы разбиваем предложение (строку) на слова (массив строк). Затем удаляем пунктуацию, которую nltk, почему-то выносит как отдельное слово. Теперь стоп-слова. Это такие слова, от которых нашей модели пользе не будет, они лишь будут сбивать ее с основного текста. К ним относят междометия, союзы и некоторые местоимения, а также любимые некоторыми слова-паразиты. Затем убираем кавычки которых в этом романе через край.


  • Теперь разбиваем текст на предложения, а предложения на массив слов.


    sentences = [tokenize_ru(sent) for sent in sent_tokenize(text, 'russian')]

  • Для интереса выведем количество предложений и парочку из них.


    print(len(sentences))  # 20024
    print(sentences[200:209])  # [['Она', 'чувствовала', 'боится', 'боится', 'предстоящего', 'свидания'],...]

  • Теперь начинаем обучать модель. Не бойтесь это не займет и получасу — 20024 предложения для gensim просто расплюнуть.


    # train model
    model = gensim.models.Word2Vec(sentences, size=150, window=5, min_count=5, workers=4)

  • Теперь сохраняем модель в файл.
    # save model
    model.save('./w2v.model')
    print('saved')

Сохраняем файл. Чтобы запустить, тем кто работает в PyCharm или Spyder достаточно нажать run. Кто пишет вручную с блокнота или другого редактора придется запустить Anaconda Promt (для этого достаточно вбить это в поиск в меню), перейти в директорию со скриптом и запустить командой


python train-I.py

Готово. Теперь вы можете с гордостью сказать, что обучали word2vec.


ЧАСТЬ ВТОРАЯ. Война и Мир


Как бы мы не старались, но Анны Каренины для обучении модели мало. Поэтому воспользуемся вторым произведением автора — Война и Мир.


Скачать можно отсюда, также в формате TXT. Перед использованием придется соединить два файла в один. Кидаем в директорию из первой главы, называем war.txt. Одной из прелестью использования gensim является то, что любую загруженную модель можно доучить с новыми данными. Этим мы и займемся.
Создаем скрипт train-II.py


  • Думаю, что эта часть не нуждается в объяснениях, так как в ней нет ничего нового.


    # -*- coding: utf-8 -*-
    # imports
    import gensim
    import string
    from nltk.tokenize import sent_tokenize
    from nltk.corpus import stopwords
    from nltk.tokenize import word_tokenize
    # load text
    text = open('./war.txt', 'r', encoding='utf-8').read()
    def tokenize_ru(file_text):
    # firstly let's apply nltk tokenization
    tokens = word_tokenize(file_text)
    
    # let's delete punctuation symbols
    tokens = [i for i in tokens if (i not in string.punctuation)]
    
    # deleting stop_words
    stop_words = stopwords.words('russian')
    stop_words.extend(['что', 'это', 'так', 'вот', 'быть', 'как', 'в', '—', '–', 'к', 'на', '...'])
    tokens = [i for i in tokens if (i not in stop_words)]
    
    # cleaning words
    tokens = [i.replace("«", "").replace("»", "") for i in tokens]
    
    return tokens
    # tokenize sentences
    sentences = [tokenize_ru(sent) for sent in sent_tokenize(text, 'russian')]
    print(len(sentences))  # 30938
    print(sentences[200:209])  # [['Он', 'нагнув', 'голову', 'расставив', 'большие', 'ноги', 'стал', 'доказывать', 'Анне', 'Павловне', 'почему', 'полагал', 'план', 'аббата', 'химера'],...]

  • Затем загружаем нашу модель, и скармливаем ей новые данные.


    # train model part II
    model = gensim.models.Word2Vec.load('./w2v.model')
    model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)

    Здесь я немного остановлюсь. total_examples устанавливает количество слов, в нашем случае это весь словарь модели (model.corpus_count), включая новые. А `epochs количество итераций. Честное слово, сам не знаю, что значит model.iter взял из документации. Кто знает, напишите, пожалуйста, в комментариях — исправлю.


  • И снова сохраняем.
    # save model
    model.save('./w2v-II.model')
    print('saved')

Не забудьте запустить.


ЭПИЛОГ. А где же тесты?


Их нет. И пока не будет. Модель еще не совсем совершенна, откровенно говоря, она ужасна. В следующей статье я обязательно расскажу как это исправить. Но вот вам на последок:


# -*- coding: utf-8 -*-

# imports
import gensim

model = gensim.models.Word2Vec.load('./w2v-II.model')

print(model.most_similar(positive=['княжна', 'сестра'], negative=['князь'], topn=1))

P.S


Вообще-то не все так плохо. Получившийся словарь содержит около 5 тысяч слов с их зависимостями и отношениями. В следующей статье я приведу более совершенную модель (15000 слов). Побольше расскажу о подготовке текста. И наконец в третьей части опубликую финальную модель и расскажу как с помощью нейронных сетей написать программу генерирующую текст в стиле Толстого.

Ссылки и используемая литература.



Успехов вам в машинном обучении.


Надеюсь моя статья вам хоть немного понравилась.

Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 20
  • +3
    писать как Толстой
    Модель еще не совсем совершенна, откровенно говоря, она ужасна.

    Короче говоря, как обычно, на деле получилось нечто далёкое от словесного анонса. :)
    • +2
      Все жду статью по машинному обучению- «и вот в результате компьютер выдал эту статью»
      • 0
        Неужели все так плохо?
        • 0
          Да нет не плохо, просто размах декларированной цели поражает наповал. Может лучше немного спустить планку и попробовать научить компьютер сгенерировать читабельную статью для geektimes в стиле ализара?
          • 0
            попробовать научить компьютер сгенерировать читабельную статью для geektimes в стиле ализара?

            Ну я хочу научить генерировать в стиле Толстого. Ну а так, да. С названием не подумал. Надо было по другому называть. Но все-таки надеюсь что хоть что-нибудь полезное вы для себя узнали. Потом еще есть идеи написать статьи по seq2seq. Может результат будет более близкий к цели
      • 0
        Вообще-то не все так плохо. Получившийся словарь содержит около 5 тысяч слов с их зависимостями и отношениями. В следующей статье я приведу более совершенную модель (15000 слов). Побольше расскажу о подготовке текста. И наконец в третьей части опубликую финальную модель и расскажу как с помощью нейронных сетей написать программу генерирующую текст в стиле толстого
        • 0
          Всё как в известной поговорке: «На словах ты Лев Толстой, а на деле Пётр Толстой».
          • 0
            Я как бы на неё старательно и намекал… :)
        • 0
          Спасибо за попытку! Я бы привел результаты тестов, как бы ужасны они ни были
          • 0
            В конце я привел один из примеров. Так же вы можете сами попытаться поискать в интернете, почитать документацию по gensim. Там есть примеры предсказывания слова на основе предыдущих
          • 0

            Может, просто, научить писать компьютер по какой -то другой книге?

            • 0
              Как вариант, но у Толстого очень объемные главы и много слов в предложениях. Мне кажется так лучше для быстрого обучения модели. Или не очень?
              • 0
                Вы правы. В моей новой модели, основанной на большом количестве книг Толстого, около 15000 слов. Для обучения и использования это очень неплохо. Хотя гугл предоставляет модели и на миллионы слов, правда и весят они парочку гигабайт. Хотя есть и отрицательная сторона — французский язык. Кстати в следующей статье приведу способ отличать французские предложения от русских с помощью nltk.
              • 0

                Угу, по Библии. ;) Было бы занятно почитать машинное Евангелие.

              • +1
                Снова все готово

                Меня всегда это поражало. «Все готово, но не работает.»
                Почему вы пишете что все готово? Вы сами заметили, что не готово. Может у вас вообще подход в принципе неверный?
                Весьма вероятно, что вы действительно исправите что-то в следующей итерации или уже исправили, но пока что статья читается как будто вы нагуглили куски кода (нерабочие) и пишете об этом статью. Не надо так.
                • 0
                  Подход верный. Но сразу публиковать готовый код не интересно. Этой статьей я только хотел разжечь читателя. Дать ему отправную точку для саморазвития. Ждите следующую статью, будет интереснее.

                  P.S. Зря вы в коде сомневаетесь. Во первых он рабочий, во вторых я не гуглил. Тему с машинным обучением и обработкой натурального языка я знаю отлично. Не первый год интересуюсь… Но ваши замечания постараюсь учесть.
                • +1
                  — А что это у вас там за лампа? — подозри­тельно спросил Фарфуркис.

                  Старичок ударил по клавишам, потом быстро вырвал из машинки листок бумаги и рысцой под­нес его Фарфуркису. Фарфуркис прочитал вслух:

                  — «Вопрос: что у нея… гм… у нея внутре за лпч?..» Лэпэчэ… Кэпэдэ, наверное? Что еще за лэпэчэ?

                  — Лампочка, значит,— сказал старичок, хихи­кая и потирая руки. — Кодируем помаленьку...».
                  • 0
                    И всё же, когда следующая статья? Хотелось бы попробовать, но пока ведь нечего :)
                  • 0
                    Уже пишу. Мне не хватает только какого нибудь эффектного теста. Подготовил новую модель. Сейчас делаю датасеты чтобы вам не приходилось обрабатывать весь огромный текст по новой.

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