КОМПОНЕНТЫ HAYSTACK

За пределами "ванильного" ответа на вопрос: начните использовать классификацию, обобщение и генеративное обеспечение качества

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

С Haystack вы можете настроить полнофункциональную систему ответов на вопросы (QA) менее чем за десять минут. Но знаете ли вы, что вы можете добавлять узлы в свой конвейер, чтобы использовать все виды языковых моделей на основе Transformer? Например, вы можете включить модуль для анализа настроений или модуль, который суммирует выходные данные конвейера.

В этом посте мы покажем вам, как извлечь выгоду из широкого спектра предварительно обученных моделей Transformer. Как всегда, цель состоит в том, чтобы повысить как эффективность вашего конвейера, так и качество его вывода. В частности, мы рассмотрим три разных узла: сумматор, узел классификации и генератор. Давайте прямо сейчас!

Создание метаданных с помощью узла классификации

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

Он дополняет наш хорошо зарекомендовавший себя Классификатор запросов. Однако вместо классификации запросов этот узел классифицирует варианты ответов, выбранные Retriever.

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

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

Классификатор в действии

Чтобы использовать классификатор, нам нужно установить последнюю версию Haystack с мастера:

pip install git+https://github.com/deepset-ai/haystack.git

В этом примере мы будем работать с классификатором для анализа настроений - задачей обозначения настроения или отношения к определенному тексту. Положительный или отрицательный, или что-то среднее? Мы выбираем предварительно обученный двоичный классификатор настроений из Hugging Face Model Hub и передаем его имя в FARMClassifier:

from haystack.classifier import FARMClassifier
classifier_model = 'textattack/bert-base-uncased-imdb'
classifier = FARMClassifier(model_name_or_path=classifier_model)

Затем мы инициализируем конвейер как обычно, на этот раз добавляя узел Classifier сразу после узла Retriever:

pipeline = Pipeline()
pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"])
pipeline.add_node(component=classifier, name='Classifier', inputs=['Retriever'])

В качестве практических примеров в этом посте мы будем работать с фрагментом Игрушки и игры из большого набора данных Обзоры Amazon. Мы зачитали отзывы в хранилище документов, сохранив идентификаторы элементов в качестве метаданных. Для следующего поиска мы хотим посмотреть только обзоры this slurpee maker, поэтому передаем фильтр в наш конвейер:

filter = {'item_id': ['B007X9DRWO']}
result = pipeline.run(query='How is the quality of this product?', filters=filter, top_k_retriever=30)

Конвейер возвращает результат нашему запросу в виде вложенного словаря. Под ключом «документы» мы находим ответные документы, каждый из которых получил метку от узла классификации: «LABEL_1» для положительного мнения или «LABEL_0» для отрицательного. Давайте посмотрим на первый положительно классифицированный отзыв:

documents = result['documents']
[doc.text for doc in documents if doc.meta['classification']['label'] == 'LABEL_1'][0]
>>> "Children will love this toy. As we all know, kids (and a good number of adults as well, I might add) love Slurpees. And this product, which enables the children to create their own drink, is a sure winner. Cleanup isn't much, either, so this Slurpee Maker comes recommended - would definitely make a nice gift."

А как насчет первого отрицательного отзыва?

[doc.text for doc in documents if doc.meta['classification']['label'] == 'LABEL_0'][0]
>>> 'I wish I could rate this higher because I love Slurpee brand. The plastic this product is made from is so cheap, it breaks easily and since it\'s for kids - described as a "toy" it should be more durable. They made it completely disassemble, which is great for cleaning, but makes it a mess to wash, dry, and store, besides the fact that when you are moving it or trying to use it it keeps falling apart. You must have salt to make the contraption work and kids get tired of turning the pump to make it work. The'

Ради этого примера мы проигнорировали тот факт, что к данным Amazon Reviews на самом деле прилагается ярлык настроения. Если вы работаете с данными, которые не содержат такой информации, добавление узла классификации в конвейер может дать ценную информацию о характере ваших результатов.

Сократите время чтения с помощью Summarizer

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

Сумматор в действии

Чтобы построить систему реферирования, мы объединим Retriever и Summarizer в конвейер. При инициализации Summarizer мы указываем минимальное и максимальное количество слов в сводке. Установка для параметра generate_single_summary значения «True» дает нам одну сводку всех возвращенных документов, а установка «False» создает одну сводку для каждого документа:

from haystack.summarizer import TransformersSummarizer
summarizer = TransformersSummarizer(model_name_or_path='t5-large', min_length=10, max_length=300, generate_single_summary=True)

Готовый класс SearchSummarizationPipeline позволяет настроить весь конвейер в одной строке:

pipeline = SearchSummarizationPipeline(retriever=retriever, summarizer=summarizer)

Создадим аннотацию к этой карточной игре для детей. При работе с Summarizer мы обычно хотим использовать запросы по ключевым словам, а не вопросы на естественном языке:

filter = {'item_id': ['B0039S7NO6']}
result = pipeline.run(query='preschooler suitability', filters=filter, top_k_retriever=5)

На этот раз «результирующий» словарь представляет собой список с одним документом. Давайте посмотрим на сводку, которую мы получили по нашему запросу, который мы находим под ключом «текст»:

result['documents'][0].text
>>> "'this game is surprisingly fun, and entertains for quite a while. even my three-year-old plays almost as well as the rest of the family. the game is for all genders and ages 4+."

Чтобы убедиться, что этот результат действительно представляет собой недавно созданную сводку всех документов, полученных в ответ на наш запрос, давайте взглянем на варианты ответов. Они хранятся в объединенном формате как часть метаданных под ключом context:

result['documents'][0].meta['context']
>>> "The best thing about this game is that even a 5 year old can play it and explain it to friends without adult supervision.  Fun, quick and easy to pack. This is a fun game for a group of friends or just our kids (ages 6-10) and us! Easy to play and understand. I bought this game for my daughters (ages 3 & 5) for Christmas after reading several reviews.  It's a simple game, you simply have to figure out which figures match on two game cards, but it's surprisingly fun, and entertains for quite a while.  What I like about it is that even my three-year-old plays almost as well as the rest of the family. This is a great game (with multiple playing options), good for a quick five minutes, or playing variation after variation.  My 4 year old enjoys the game, as do my husband and I.  This game is for all genders and ages 4+.  Great birthday gift to have waiting in the closet. Fun, simple, and inexpensive game for children of all ages. The younger kids (3-5) can play cooperatively and older kids 6+ can play more competitively. "

Объединение Ranker и Summarizer

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

Получите ответы, написанные специально для вас, с помощью генератора

Языковые модели на основе трансформера уже впечатляют нас своей способностью интерпретировать естественный язык. Но совсем другое дело - видеть, как они создают утверждения с нуля. С помощью узла «Генератор» вы можете добавить эту возможность в конвейер ответов на вопросы.

Генератор в действии

В отличие от других моделей, упомянутых в этой статье, генератор работает только в тандеме с методом поиска плотных проходов (DPR). Обязательно сначала инициализируйте DPR Retriever, так как его необходимо передать как генератору, так и объекту конвейера:

from haystack.generator.transformers import RAGenerator
from haystack.pipeline import GenerativeQAPipeline
generator = RAGenerator(
model_name_or_path="facebook/rag-sequence-nq",
  retriever=dpr_retriever,
  top_k=1,
  min_length=2)
pipeline = GenerativeQAPipeline(generator=generator, retriever=dpr_retriever)

Поскольку набор данных обзора по своей сути основан на мнении, мы зададим нашей системе субъективный вопрос:

result = pipelines.run(query='What are the best party games for adults?', top_k_retriever=20)
result['answers'][0]['answer']
>>> "wit's & wagers & darts"

Похоже на веселый вечер! Более пристальный взгляд на извлеченные документы (которые слишком длинные для отображения здесь) показывает, что во всех обзорах правильно написано Сообразительность и ставки. Опечатка в ответе подтверждает, что вместо простого извлечения названия игры из одного из документов узел сгенерировал его с нуля.

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

Еще больше магии НЛП

Как мы видели, Haystack выходит далеко за рамки простых систем ответов на вопросы. Но есть еще кое-что: знаете ли вы, что вы также можете использовать генератор вопросов для создания вопросов с нуля? Это пригодится при создании новых наборов данных QA! Мы готовим подробное руководство по этому узлу, так что следите за обновлениями.

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

Изучите ответы на вопросы и многое другое в Haystack

Хотите узнать больше о том, что инструменты обработки естественного языка Haystack могут сделать для вас?

Перейдите в наш репозиторий GitHub. Если вам нравится то, что вы видите, дайте нам звезду :)