Ru_SBERT для всех или как легко и просто влиться в генерацию текстов

 Публичный пост
14 октября 2022  125
Держи месяц

Хочу немного рассказать чем я занимаюсь и показать самое простое

В современной генерации текста есть 2 больших направления GPT(энкодер-декодер) - мы пишем слово и дальше нейронка что считает нужным то и генерит и BERT(энкодер и если мы смотрим всякие ответвления то и с декодером бывают штуки ,те же самые модели переводчики seq2seq).

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

Делается это через получение косинуса эмбеддингов данных предложений . Звучит страшно но всё , на самом деле, легко.

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

Модель не умеет просто так сравнивать 2 текста. Чтобы это сделать сначала нам нужно получить "эмбеддинг" нашего текста. Эмбеддинг это по сути матрица векторов. В каждой матрице(в каждом эмбеддинге) у нас по 128 векторов и в каждом векторе по 768 значений.

Эта самая матрица это как бы отражение "смысла" фразы в многовекторном пространстве изначальной модели. Т о , сравнив 2 матрицы мы можем сказать на сколько они "похожи" друг на друга.

Сравнить 2 матрицы мы можем очень легко....Так как эмбеддинг это вектора, нам всего лишь нужно выяснить косинус угла между этими векторами. И чем ближе они к единице, тем по смыслу очень похожи 2 фразы.

Для написания кода нужно минимальное знание пайтона.
Реализовывать можно всё в колабах или ставить себе питон на комп и какую нибудь среду обработки.

Если что, я сделал колаб в котором всё работает . Нажимаем play и всё само сделаетсяю Тут же я просто расскажу что да как и почему

Начнем со скачивание фреймворка для работы, его подключения и подключения модели

!pip install sentence_transformers
from sentence_transformers import SentenceTransformer, util
ce_rerank = SentenceTransformer('sberbank-ai/sbert_large_nlu_ru')

Далее я напишу функцию, которая будет у нас сортировать полученные пассажи по убыванию значения косинуса относительно "вопроса"

def rerank(question, passages, include_rank: int = 10):
    d = {}
    return_list = []

# тут у нас происходит как раз магия получения эмбеддинга предложений
    query_embedding = ce_rerank.encode(question) 
    passage_embedding = ce_rerank.encode(passages)
    
#А тут мы махом сравниваем все эмбеддинги между собой
    a_list = util.cos_sim(query_embedding, passage_embedding).tolist()[0]
    
#Сопоставляем косинусы эмбеддингов и сами предложения
    for n in range(len(passages)):
        d[passages[n]] = a_list[n]
#Сортируем что получилось чтобы сначала шли самые "похожие" предложения
    sorted_tuple = sorted(d.items(),reverse=True, key=lambda x: x[1])

    counter = 0
    for n in sorted_tuple:
        if counter < include_rank:
            counter +=1
            if n not in return_list:
                return_list.append(n[0])

    return return_list

Далее мы вводим данные , с которыми будем работать : вопрос и варианты текстов.

title = "почему птицы не летают?"
context_passages = ["Нелетающие птицы — птицы, утратившие в процессе эволюции способность к полёту.",
                    "Способность к полёту теряли многие группы птиц независимо друг от друга[1]. Нелетающие птицы принадлежат ко многим семействам и отрядам. В одних из них (пингвинообразные, страусообразные) все виды нелетающие, в других (пастушковые) — только некоторые.",
                    "Известно 38 видов и эндемичных островных подвидов или рас наземных нелетающих птиц и 26 — водных[2].",
                    "Размер и масса нелетающих птиц колеблются от 15 см и 35 г у тристанского пастушка до свыше 2,5 м и 150 кг у страусов.",
                    "Потеря способности к полёту открывает возможность для увеличения размеров птиц: масса отдельных видов пингвинов достигает 40 кг, казуаров, африканских страусов — 80-100 кг. Некоторые виды вымерших нелетающих птиц, таких как эпиорнисы и моа, видимо, достигали массы 300—400 кг.",
                    "У многих нелетающих птиц из-за неспособности к полёту сильно ограничен ареал; особенно много таких видов птиц на островах. Из-за этого большинство видов находятся под угрозой исчезновения, особенно при проникновении чужеродных видов. Так были истреблены дронты, не умевшие ни летать, ни плавать, ни быстро бегать, но спокойно жившие на островах из-за отсутствия врагов.",
                    "Много нелетающих обитают в Новой Зеландии — киви, султанка такахе, пастушок-уэка, несколько видов пингвинов, попугай какапо.",
                    "К нелетающим птицам не относят малолетающих птиц (многие курообразные), так как они не утратили способность к полёту, хотя и не совершают дальних перелётов. У нелетающих птиц крылья очень малы для их массы или вообще сильно редуцированы.",
                    "Полёт — основной способ передвижения большинства видов птиц, помогающий им искать пищу, мигрировать и спасаться от хищников. Полёт является наиболее специфической формой передвижения птиц, определившей основные черты организации этого класса. Способность птиц к полёту вызвала ряд адаптаций для обеспечения полёта, взлёта и посадки, ориентирования в пространстве и навигации.",
                    "Характеристики полёта птиц в значительной мере зависят от величины птицы и её экологической ниши. Хотя определённые биологические адаптации (к примеру, минимизация массы тела) характерны для всех летающих птиц, другие (например, форма крыльев) характерны только для отдельных групп."
                    ]

Основная часть готова, пришло время сравнить текста и получить абзасы самые похожие относительно основного вопроса

context_passages_title = rerank(title, context_passages, include_rank=5)
('Нелетающие птицы — птицы, утратившие в процессе эволюции способность к полёту.', 0.5626955628395081)
('У многих нелетающих птиц из-за неспособности к полёту сильно ограничен ареал; особенно много таких видов птиц на островах. Из-за этого большинство видов находятся под угрозой исчезновения, особенно при проникновении чужеродных видов. Так были истреблены дронты, не умевшие ни летать, ни плавать, ни быстро бегать, но спокойно жившие на островах из-за отсутствия врагов.', 0.49199628829956055)
('Полёт — основной способ передвижения большинства видов птиц, помогающий им искать пищу, мигрировать и спасаться от хищников. Полёт является наиболее специфической формой передвижения птиц, определившей основные черты организации этого класса. Способность птиц к полёту вызвала ряд адаптаций для обеспечения полёта, взлёта и посадки, ориентирования в пространстве и навигации.', 0.4879446029663086)
('Способность к полёту теряли многие группы птиц независимо друг от друга[1]. Нелетающие птицы принадлежат ко многим семействам и отрядам. В одних из них (пингвинообразные, страусообразные) все виды нелетающие, в других (пастушковые) — только некоторые.', 0.48090660572052)
('Много нелетающих обитают в Новой Зеландии — киви, султанка такахе, пастушок-уэка, несколько видов пингвинов, попугай какапо.', 0.44233664870262146)

Как можно видеть, сначала у нас идёт самый похожий абзац и за ним всё менее и менее похожие.
Но это еще не всё. Мы разобьем абзацы на предложения и сделаем реранк для отдельных предложений и сразу выведем конечный текст

context_sentences = []
for n in context_passages_title:
    passages = n.split(".")
    for p in passages:
        if p not in context_sentences:
            context_sentences.append(p)

context_passages_title = rerank(title, context_sentences, include_rank=5)

print(context_passages_title)
['Полёт — основной способ передвижения большинства видов птиц, помогающий им искать пищу, мигрировать и спасаться от хищников', 'Нелетающие птицы — птицы, утратившие в процессе эволюции способность к полёту', 'Способность к полёту теряли многие группы птиц независимо друг от друга[1]', ' Нелетающие птицы принадлежат ко многим семействам и отрядам', 'У многих нелетающих птиц из-за неспособности к полёту сильно ограничен ареал; особенно много таких видов птиц на островах']

Как можно видеть, у нас на выходе получает сомнительно связанный текст по теме, но всё таки текст. GPT из коробки выдаёт качество куда хуже и с большим кол-вом артефактов.

Чтобы улучшить результат , как вариант, мы можем:

  • использовать всякие методы декодеров( sampling по TOP-K и TOP-P или beams), но для данных предложений;
  • отсеивать на выходе предложения по порогу сходства( как сверху так и снизу);
  • сравнивать каждое отдельное предложение с каждым;

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

7 комментариев 👇
Филипп Лапшин , Предприниматель, разработчик автор 15 октября в 05:24

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

  Развернуть 1 комментарий

Осталось понять как на этом можно сгенерить сотню сайтов с почти нормальным контентом )

Можно спарсить ТОП 20 сайтов, определить в них контент и прогнать через SBERT, так мы получим самые похожие предложения на наш запрос. Это дело бы еще немного уникализировать, чтобы не просто куски с разных сайтов. Да и не понятно, как это скушает Яндекс.

  Развернуть 1 комментарий

@caleynikov, Да, можно:)

Под уникализацию есть модель от deep pavlov, но она убогая, да и Яндекс к копепасте с 20 источников норм относится

Тут больше проблема в кластеризации запросов по теме и сборе заголовков.
Можно взять заголовки с источников ( с условием что они длиннее 2) и из них самых похожих ,условно, 5

И пытаться собрать ответы по этим заголовкам

  Развернуть 1 комментарий

@caleynikov, По поводу индексации. Я это в бурже активно пользую, но в яндексе должно работать аналогично.
Если есть старый сайт на который вроде посещалки нет, но бот активно шастает. Так вот. Кто нам мешает поставить 301 редик при заходе на эту страницу? Бот успешно редиректается на новую страницу и ее кушает. Проиндексирует он ее или нет это второй вопрос. Краулинг это совсем не индексинг, но в очередь на обработку страница встанет.

По опыту гугла от 40 до 70% страниц отправленных таким образом попадают в индекс( до того как придет ИИ проверки кач-ва :) ).

Еще по поводу гугла в РУ. Он куда должен быть мягче чем в EN просто потому что они оценку качества развернули только в EN и постепенно выводят на тех языках где у них рынки. Так вот, боюсь до РУ это дойдёт совсем не скоро, а значит подобная копипаста должна себя чувствовать нормально, особенно если делать структуру на основе сущностей через https://kgsearch.googleapis.com

  Развернуть 1 комментарий
Андрей Алферов , Добываю сео трафик под бурж и Яндекс 16 октября в 05:07

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

  Развернуть 1 комментарий
Алексей Сорокин , Руковожу клубом предпринимателей 14 октября в 13:34

Охренеть! Просто охренеть!

Очень неожиданная и очень крутая статья! Спасибо!

  Развернуть 1 комментарий

Круто! Всегда было интересно, как оно работает.

  Развернуть 1 комментарий

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб