?

Log in

No account? Create an account

Компьютерная лингвистика

Новостная лента www.solarix.ru

Previous Entry Share Next Entry
Оценки для задачи "бинарная классификация - является ли реплика продолжением диалога"
kelijah
Сделал оценки нескольких методов для определения, является ли реплика допустимым продолжением диалога.
Датасет - Толока. Взято 100,000 реплик. (Был еще контест в 2018 от Я с похожей задачей, тамошний датасет, по-моему, грязноват в сравнении с Толокой.)
В качестве истории бралась одна предшествующая фраза другого собеседника.
Негативные сэмплы добавлялись в количестве 1 на 1 позитивный.
Оценки получены кроссвалидацией на 3х фолдах.

Baseline - LinearSVC на символьных шинглах roc auc=0.55
LightGBM на символьных шинглах ruc auc=0.645
Нейросетка поверх pretrained ruBERT из deeppavlov roc auc=0.709

PS: Если увеличить обучающий набор до 200,000 позитивных пар, roc auc BERT-классификатора вырастает до 0.723.


  • 1
1) Раз рост есть от числа предъявленных пар. Лучше все таки негативные семплы добавить в большем числе и скорректировать весом.

2) Можно попробовать брать не одну фразу, а всю историю предыдущую

3) А сейчас какая структура сетки?

Я предлагал что такое (естественно тут поправка на LSTM и эмбендинг нужна)

main_input <- layer_input(shape = c(784),
name = 'main_input')

aux_input <- layer_input(shape = c(784),
name = 'aux_input')

share_part <- keras_model_sequential(name = "share_part")
share_part %>% layer_dense(units = 256,
activation = 'relu',
input_shape = c(784)) %>%
layer_batch_normalization() %>%
layer_dropout(rate = 0.4) %>%
layer_dense(units = 128, activation = 'relu') %>%
layer_batch_normalization() %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 64, activation = 'relu') %>%
layer_batch_normalization() %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 32, activation = 'relu') %>%
layer_batch_normalization() %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 16, activation = 'relu') %>%
layer_batch_normalization()

compare_part <- keras_model_sequential(name = "compare_part")
compare_part %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 2, activation = 'softmax')

main_out <- main_input %>% share_part
aux_out <- aux_input %>% share_part

main_output <- layer_subtract(c(main_out, aux_out)) %>% compare_part

model <- keras_model(
inputs = c(main_input, aux_input),
outputs = c(main_output)
)

Ну и фитить с весами, не теряя случаев

class_weight = list("0"=0.1, "1"=0.9)

>1) Раз рост есть от числа предъявленных пар. Лучше все таки негативные семплы добавить в большем числе и скорректировать весом.

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

>2) Можно попробовать брать не одну фразу, а всю историю предыдущую
Да, есть такая мысль. Главная сложность в том, что в используемом датасете довольно много идущих подряд реплик одного собеседника:

1:> привет!
2:> Привет)
2:> Как твои дела?
1:> кто ты, таинственный незнакомец? я например студентка
2:> Ого
2:> На кого учишься?

Отсюда возникает вопрос, как учитывать в истории такие идущие подряд реплики. Я сейчас беру одну из реплик собеседника 1 и одну из реплик собеседника 2 в соседних сегментах. Упаковывать много реплик в одну входную фразу мне показалось как-то неправильным, хотя кто знает... В общем, для случая более 1 реплики в истории количество вариантов очень сильно возрастает.


>3) А сейчас какая структура сетки?

Она в gridsearch'е подбирается, но в принципе конфигурация что-то типа такого, ага.

Кстати, спасибо, что напомнил про dropout, я его забыл добавить :)

> если делать по 10 негативных на позитивную пару

можно менее агрессивно добавлять (и веса у случаев не обязательно точно соответствуют пропорции примеров при обучении)

>

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

>

Еще представляется важным размерность выходного слоя шаред сетки... наверное её надо вообще "прямоугольной" делать или "расширяющейся книзу". Там по сути "вектор поднятых тем" представлен.

>

А учить всю систему в два этапа, на первом до предела с максимально простым решателем после шаред слоя, а потом прибить веса шаред слоя гвоздями и добавить "решатель" многослойный и учить уже его отдельно. Может ещё выжать пару процентов получиться.

>Не обязательно википедия какая базой должна служить, просто загрузить с флибусты тексты. Можно даже несколько таких представлений "тематических" "стекировать" просто.

Я не хочу переобучать BERT. Точнее не могу, так как по опыту даже после скручивания сложности до самого минимума обучение на каком-то миллионе фраз занимает несколько суток. Переобучать полномасштабный BERT с сотней миллионов параметров на обычных GPU это ваще нереально :) Как я понимаю, перцы из гугла это дело обучали на TPU, в которых по 64 Gb на борту.

Поэтому приходится мириться с тем, что либо в модели multilingual BERT куча ненужных мне языков. Либо модель от deeppavlov обучена на Википедии, а я через нее гоняю сообщения из чата. Хотя вот классификатор интентов для RASA получился достаточно неплохим.

Остается только файнтюнить сетку поверх BERT'а. Ну тут да, gridsearch в зубы и перебор вариантов. Для классификатора интентов, например, перебор упорно считает, что двух слоев поверх эмбеддинга BERT достаточно, ну и т.д.

Мне представляется стекирование векторов посильных w2w перспективным. Только корпус текстов в каждом w2w отдельно должен и "тематически" формироваться.

Например все "сборники анекдотов" в w2w юмор, все абстракты статей по билогии и учебники биологии в раздел "биология". Ну и т.д. "медицина", "стихи", "история", "физика".... Десятичная система Дьюи короче :) (в принципе можно классификацию текстов через какой LSA объективной сделать)

Обычный word2vec довольно быстрый.

> Остается только файнтюнить

gridsearch не умеет "веса слоев фиксировать" при обучении сети как "параметр обучения".

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

(ну или вообще лучшую сетку после обучения заставить писать "сырой выхлоп" и отправить его в наш самый популярный ML метод)

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

  • 1