Построить классификатор выявляющий плохие ответы пользователя на языке Python(реализовать в виде класса). Подобрать или создать датасет и обучить модель. Продемонстрировать зависимость качества классификации от объема и качества выборки. Продемонстрировать работу вашего алгоритма. Обосновать выбор данного алгоритма машинного обучения.
Датасет было решено создать на основе комментариев к статьям на ресурсе Geektimes.
Внимание! Возможно, что скрипты загрузки комментариев работать не
будут, т.к. Geektimes недавно объединили с Habrahabr, в следствие чего
ссылки на статьи перестали быть валидными.
Чтобы комментарии относились к одной предметной области, был выбран хаб "Регулирование в IT". В данном хабе всегда много сильно хороших и сильно плохих ("заминусованных") комментариев из-за огромного количества статей с политическим уклоном.
Комментарии извлекались из html страницы для мобильной версии Geektimes. Там гораздо меньше "вёрстки", благодаря чему парсинг страницы проходи быстрее. Для парсинга использовалась библиотека BeautifulSoup4 для Python3. Комментарии выбирались из принципа плюс - хороший, минус - плохой. Не отмеченные пользователями комментарии не попали в датасет. После этого, комментарии сохранялись в формате JSON в файлы good_comments.json и bad_comments.json.
Были обработаны все(!) существующие на момент работы скрипта статьи из выбранного хаба. В результате были получено 11345 хороших комментариев и 57738 плохих. Из-за огромной разницы было решено плохие комментарии перемешать, после чего выбрать первые 11345 из них.
Забегая вперёд, скажу, что обучать мы будем нейросеть CNTK от Microsoft. Как именно, пока не вожно. Важно то, что каждый комментарий должен быть представлен как n-мерный вектор, которому будет соответствовать число 0 (плохой комментарий) или 1 (хороший). Для этого будем использовать библиотеку nltk для Python3.
Для векторизации данных нам необходимо:
- Разобрать тест на токены. (nltk.tokenize)
- Убрать так называемые "стоп-слова" (предлоги, союзы и т.п.). (nlkt.corpus)
- Оставшиеся слова на привести в одну форму (так называемый "стемминг") (nltk.stem.SnowballStemmer)
- По текстам построить словарь
- Учитывая позицию слова в словаре, построить вектора, используя разреженную матрицу из scipy.sparse.
- Нормировать вектора.
Теперь мы имеем набор векторов и результатов, им соответствующим. Перед началом обучения данные следует "рандомно" перемешать и разделить на две выборки в соотношении 2 к 1.
Код для создания нейросети:
import cntk
import numpy as np
import matplotlib.pyplot as plt
INPUT_DIM = 47459 # размер словаря
OUTPUT_DIM = 1
EPOCHS_COUNT = 200
LEARNING_RATE = 0.15
input_ = cntk.input_variable(INPUT_DIM, 'float32')
output_ = cntk.input_variable(OUTPUT_DIM, 'float32')
def create_model(input_):
with cntk.layers.default_options(activation=C.sigmoid, init=C.glorot_uniform()):
model = cntk.layers.Sequential([
cntk.layers.Dense(2),
cntk.layers.Dense(1),
cntk.layers.Dense(OUTPUT_DIM)
])
return model(input_)
z = create_model(input_)
# Загрузка векторизированных комментариев в переменную X,
# Выходных данных (0,1) в Y.
lr_schedule = cntk.learning_rate_schedule(LEARNING_RATE,
cntk.UnitType.minibatch)
learner = cntk.adam(z.parameters, lr_schedule, momentum=0.9)
loss = cntk.squared_error(z, output_)
trainer = cntk.Trainer(z, loss, [learner])
datamap = {
input_: X,
output_: Y
}
losses = []
for i in range(EPOCHS_COUNT):
trainer.train_minibatch(datamap)
loss = trainer.previous_minibatch_loss_average
losses.append(loss)
Данная работа могла бы быть выложена на Хабрахабре как "пятничная статья". К сожалению, не удалось заставить CNTK работать c разреженными матрицами. (Поиск решения привёл к просмотру многих открытых issue на github).
Следует отметить, что нейросети прочно вошли в инструментарий, используемый разработчиками ПО. Этому способствует большой выбор средств для обучения нейросетей (CNTK, TensorFlow, CatBoost из Yandex) и относительно высокая доступность "железа" для обучения.