Размер
Получение параметров команды из человеческой фразы
Play

Получение параметров команды из человеческой фразы

Я нашел пример реализации теггера на Keras и, в лучших традициях своих экспериментов, начал бездумно копировать оттуда куски кода. В примере нейросеть обрабатывает входную строку как последовательность символов, не разделяя ее на слова. Но дальше по тексту есть пример с использованием Embedding слоя. А раз я научился использовать hashing_trick, то я почувствовал острое желание воспользоваться этим навыком.

То, что у меня получилось, обучалось значительно медленнее, чем классификатор. Я включил в Keras отладочный вывод, и, задумчиво глядя на медленно появляющиеся строчки, обратил внимание на значение Loss. Оно не особенно убывало, при этом мне оно показалось достаточно большим. А accuracy при этом была маленькой. Сидеть и ждать результата мне было лень, поэтому я вспомнил одну из рекомендаций Andrew Ng — попробовать свою нейросеть на меньшем по размеру набору учебных данных. По виду зависимости Loss от количества примеров можно оценить, стоит ли ожидать хороших результатов.

Поэтому я остановил обучение, сгенерил новый набор учебных данных — в 10 раз меньше предыдущего — и снова запустил обучение. И почти сразу получил тот же самый Loss и тот же самый Accuracy. Получается, что от увеличения числа учебных примеров лучше не станет.

Я все-таки дождался окончания обучения (около часа, при том, что классификатор обучался за несколько секунд) и решил ее опробовать. И понял, что копировать надо было больше, потому что в случае seq2seq для обучения и для реальной работы нужны разные модели. Еще немного поковырялся с кодом и решил остановиться и подумать, что делать дальше.

Передо мной был выбор — снова взять готовый пример, но уже без самодеятельности, либо же взять готовый seq2seq, или же вернуться к инструменту, который у меня уже работал — sequence tagger на NERModel. Правда чтобы без GloVe.

Я решил попробовать все три в обратном порядке.

NER model из sequence tagging

Желание править существующий код улетучилось сразу же, как только я заглянул внутрь. Поэтому я пошел с другой стороны — надергать из sequence tagging разных классов и методов, взять gensim.models.Word2Vec и это все туда скормить. После часа попыток я смог сделать учебные наборы данных, но вот именно словарь мне подменить не удалось. Я посмотрел на ошибку, прилетевшую откуда-то из глубин numpy, и отказался от этой затеи.

Сделал коммит, чтобы на всякий случай не потерялось.

Seq2Seq

В документации на Seq2Seq описано только как ее приготовить, но не как ей пользоваться. Пришлось найти пример и попытаться опять же подстроить под свое. Еще пара часов экспериментов и результат — точность в процессе обучения стабильно равна 0.83. Независимо от размера учебных данных. Значит я опять что-то где-то перепутал.

Здесь мне в примере не очень понравилось, что, во-первых, вручную идет разбиение учебных данных на куски, а во-вторых, вручную же делается embedding. Я в итоге прикрутил в одну Keras-модель сначала Embedding, потом Seq2Seq, а данные подготовил одним большим куском.

Но красота не спасла — поведение сети не изменилось.

Еще один коммит, перехожу к третьему варианту.

Seq2seq вручную

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

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

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

То есть делает вид, что во фразе всего одно слово, которое не содержит никаких данных (в смысле таких, которые еще не съел классификатор). Смотрим на учебные данные… действительно, порядка 20% фраз именно такие — yes, no, часть ping (то есть всякие hello) и часть acknowledge (всякие thanks).

Начинаем ставить сети палки в колеса. Урезаю количество yes/no в 4 раза, ping/acknowledge в 2 раза и добавляю еще всякого «мусора» в одно слово, но содержащее данные. На этом этапе я решил, что не надо мне в тегах иметь явную привязку к классу, поэтому например B-makiuchi-count превратилось в просто B-count . А новый «мусор» это были просто числа с классом B-count , «время» в виде «4:30» с ожидаемым тегом B-time , указания на дату типа «now», «today» и «tomorrow» с тегом B-when .

Все равно не получается. Сеть уже не выдает однозначного ответа «O и все», но при этом accuracy так и остается на уровне 18%, а ответы совершенно неадекватные.

Интерлюдия — осмысление

Отсутствие результата — тоже результат. У меня появилось пусть и поверхностное, но понимание того, что именно происходит, когда я конструирую модели в Keras. Научился их сохранять, загружать и даже доучивать по мере необходимости. Но при этом я не добился того, чего хотел — перевода «человеческой» речи в «язык бота». Зацепок у меня больше не оставалось.

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

Расчет оправдался — я получил ссылку на Rasa NLU. На первый взгляд это выглядело как что-то очень подходящее.

Rasa NLU

Несколько дней я не возвращался к своим экспериментам. Потом сел и за час с небольшим прикрутил Rasa NLU к своим экспериментальным скриптам. Нельзя сказать, что это было очень сложно.

please, find me some pictures of japanese warriors find what: "japanese warriors" remind me to have a breakfast now, sweetie remind action: "have a breakfast" when: "now" what: "sweetie" … хотя еще есть над чем работать.

Из недостатоков — процесс обучения происходит совсем молча. Наверняка это где-то включается. Впрочем, все обучение заняло около трех минут. Еще для работы spacy все-таки требуется модель для исходного языка. Но она весит значительно меньше, чем GloVe — для английского языка это меньше 300 мегабайт. Правда для русского языка модели еще пока нет — а конечная цель моих экспериментов должна работать именно с русским. Надо будет посмотреть на другие pipeline, доступные в Rasa.

📎📎📎📎📎📎📎📎📎📎