Чат-бот на Python (Deep Learning + TensorFlow). Часть II

Предыдущая статья — Чат-бот на Python (Deep Learning + TensorFlow). Часть I

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

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

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

Еще нам нужно учитывать, что, просматривая данный файл, мы можем найти ответ, но позже найти лучший. Один из способов решить эту проблему — отталкиваться от голосов «за». То есть, мы можем брать только те ответы, за которые проголосовали. Вообще, есть очень много способов настройки данных, так что вы не стесняйтесь и делайте, как вам кажется наиболее правильным.

{"author":"Arve","link_id":"t3_5yba3","score":0,"body":"Can we please deprecate the word \"Ajax\" now? \r\n\r\n(But yeah, this _is_ much nicer)","score_hidden":false,"author_flair_text":null,"gilded":0,"subreddit":"reddit.com","edited":false,"author_flair_css_class":null,"retrieved_on":1427426409,"name":"t1_c0299ap","created_utc":"1192450643","parent_id":"t1_c02999p","controversiality":0,"ups":0,"distinguished":null,"id":"c0299ap","subreddit_id":"t5_6","downs":0,"archived":true}

Каждая строка в наших данных подобна приведенной выше. Конечно, нам нужны не все эти данные, но определенно нам пригодятся bodycomment_idи parent_id. Если вы скачали полный торрент или используете базу данных BigQuery, недостатка в данных для работы у вас нет, поэтому мы будем использовать поле score. Мы установим определенные требования к этому параметру и будем использовать только те данные, которые ему удовлетворяют.

Мы могли бы, конечно, работать с определенными подфорумами Reddit (subreddit), чтобы созданный нами искусственный интеллект говорил ровно так, как принято на данном конкретном подфоруме. Но пока мы не будем разделять данные по подфорумам.

Далее, поскольку даже один месяц комментариев может превышать 32 ГБ, мы не можем поместить их в оперативную память. Нам нужно буферизовать эти данные. Мы хотим выполнить буферизацию файлов комментариев, а затем сохранить интересующие нас данные в базе данных SQLite.

Смысл идеи в том, что мы можем вставить данные комментария в эту базу данных. Все комментарии будут располагаться в хронологическом порядке. Поэтому все они изначально будут «родительскими», то есть не имеющими собственного родительского элемента. Но потом появятся и ответы. Мы сможем сохранить этот «ответ», имеющий родительский элемент в базе данных (который также можно извлечь по идентификатору), и создать строки, содержащие родительский комментарий и ответ.

[machinelearning_ad_block]

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

В любом случае, есть несколько способов сделать это, давайте просто начнем! Для начала сделаем нужный нам импорт:

import sqlite3
import json
from datetime import datetime

Мы будем использовать модуль sqlite3 для нашей базы данных, модуль json для загрузки строк из дампа данных, а затем datetime просто для ведения журнала. Хотя в последнем особой необходимости и нет.

Таким образом, дамп данных, скачанный при помощи торрента, поставляется с кучей каталогов по годам. Они содержат фактические дампы данных json, именованные по годам и месяцам (ГГГГ-ММ). Все это сжато в файл с расширением .bz2. Убедитесь, что вы извлекли именно те данные, которые намерены использовать.

Далее, введем некоторые переменные:

timeframe = '2015-05'
sql_transaction = []

connection = sqlite3.connect('{}.db'.format(timeframe))
c = connection.cursor()

Значение переменной timeframe содержит год и месяц (в текстовом формате), данные за который мы будем использовать. Можно создать из них список, а затем его перебирать по мере необходимости. Но пока мы будем работать только с файлом за май 2015 года.

Еще у нас есть переменная sql_transaction. Надо понимать, что коммит в базу данных SQL весьма затратное (по времени) мероприятие. Если вы знаете, что собираетесь вставлять миллионы строк, вы также должны знать, что их не следует коммитить одну за другой. Вместо этого вам нужно объединить все операторы в одной транзакции и выполнить ее, произведя таким образом коммит во все группы.

Затем мы создадим таблицу наших данных. В SQLite база данных, если она еще не существует, создается оператором connect.

def create_table():
    c.execute("CREATE TABLE IF NOT EXISTS parent_reply(parent_id TEXT PRIMARY KEY, comment_id TEXT UNIQUE, parent TEXT, comment TEXT, subreddit TEXT, unix INT, score INT)")

Здесь мы собираемся хранить поля parent_id, comment_id, parent (родительский комментарий), reply (ответ на него), subreddit (подфорум), time (время), и наконец score (оценку данного ответа).

Теперь создадим блок кода main:

if __name__ == '__main__':
    create_table()

На данный момент весь наш код имеет следующий вид:

import sqlite3
import json
from datetime import datetime

timeframe = '2015-05'
sql_transaction = []

connection = sqlite3.connect('{}2.db'.format(timeframe))
c = connection.cursor()

def create_table():
    c.execute("CREATE TABLE IF NOT EXISTS parent_reply(parent_id TEXT PRIMARY KEY, comment_id TEXT UNIQUE, parent TEXT, comment TEXT, subreddit TEXT, unix INT, score INT)")

if __name__ == '__main__':
    create_table()

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

Чат-бот на Python (Deep Learning + TensorFlow). Часть III: буферизация данных.