Необходимо было разработать русскоязычную систему для извлечения ответов на вопросы (Extractive QA). Основная цель – найти и извлечь ответ в виде стартовых и конечных токенов из текста вопроса, где содержится контекст.
Для реализации extractive QA наилучшим подходом оказалось использование моделей с поиском start/end токенов. Такие модели обеспечивает высокую точность и скорость, что делает его оптимальным для задач, где ответ уже присутствует в контексте (как и требуется в данной задаче). Полный анализ различных методов представлен в ноутбуке.
Поскольку задача заключалась в создании русскоязычной QA-системы, выбор моделей был ограничен многоязычными и специализированными русскоязычными моделями. Одними из лучших вариантов оказались multilingual DistilBERT и RuBERT, результаты экспериментов с которыми можно найти в ноутбуках.
Для обучения был выбран датасет Sberquad, поскольку этот датасет специально разработан для русскоязычных QA-задач, что полностью соответствует требованиям проекта. Система была развернута в виде Telegram-бота для удобства интеграции и тестирования.
ru_qa_system/
├── bot/
│ ├── __init__.py
│ ├── bot.py
│ └── main.py
├── model/
│ ├── __init__.py
│ ├── train.py
│ ├── inference.py
│ ├── dataset.py
│ ├── input_preprocessing.py
│ └── utils.py
├── trained_models/
│ └── rubert-v3/
│ └── (модель)
└── notebooks/
└── (ноутбуки с модальными экспериментами)
Взаимодействие между модулями из папок bot и model организовано следующим образом:
- bot использует модули из model для выполнения ключевых задач, таких как предобработка текста и выполнение запросов к модели. В частности, он импортирует класс TextSplitter из model.input_preprocessing, который отвечает за разделение входного текста (как сообщение пользователя) на вопрос и контекст.
- bot обращается к классу QAModel из model.inference для получения ответов на вопросы пользователей, основываясь на обученной модели.
- Внутри модуля model файл train.py использует класс QADataset из dataset для работы с данными.
Класс QADataset загружает и предобрабатывает датасет. После загрузки данных применяется метод предобработки данных preprocess_data, который токенизирует вопросы и контексты и формирует метки для начальных и конечных позиций ответов. Затем создаются DataLoader’ы для тренировочного и валидационного наборов. Класс предоставляет методы для получения исходного датасета, предобработанных тренировочного и валидационного датасетов, а также соответствующих DataLoader'ов для удобного взаимодействия с данными.
В ходе экспериментов были протестированы две предобученные модели: многоязычный DistilBERT и RuBERT. Для каждой из моделей были попробованы различные параметры обучения, включая различные значения скорости обучения, количество эпох и оптимизаторы. Но лучшие результаты для обеих моделей были показаны при использовании оптимизатора AdamW c темпом обучения равным 3е-5. Результаты метрик для каждой модели представлены в таблицах ниже.
Эпоха | Exact (%) | F1 (%) |
---|---|---|
1 | 53.06 | 73.12 |
2 | 54.77 | 74.41 |
Эпоха | Exact (%) | F1 (%) |
---|---|---|
1 | 62.49 | 82.10 |
В случае многоязычного DistilBERT наилучшие результаты были достигнуты после двух эпох обучения, с улучшением метрик во второй эпохе. RuBERT, с другой стороны, продемонстрировала более высокие показатели уже после первой эпохи, однако дальнейшее обучение привело к ухудшению метрик, что указывает на возможное переобучение модели.
Эти результаты свидетельствуют о том, что RuBERT является более мощным инструментом для задач русскоязычного QA, но требует осторожного подхода в процессе настройки. Это может быть связано с тем, что RuBERT был специально разработан для русского языка, что позволяет ему лучше улавливать лексические и синтаксические особенности русского текста, чем многоязычные модели.
В результате эксперимента, было решено обучать RuBERT для данной задачи.
Для обучения модели RuBERT были использованы следующие параметры обучения:
Параметр | Значение |
---|---|
Оптимизатор | AdamW |
Планировщик | Линейный |
Ускоритель | Accelerator |
Точность обучения | fp16 |
Размер батча | 16 |
Темп обучения | 3e-5 |
Количество эпох | 1 |
В процессе тренировки модели проводилась регулярная валидация модели на валидационном датасете по окончании каждой эпохи обучения. Ключевыми метриками для оценки качества модели были Exact Match, отражающая процент правильно предсказанных ответов, и F1-score, показывающая баланс между точностью и полнотой. Но также немаловажную роль играет время выполнения запроса, это было оценено на практике при запуске бота.
Также можно визуально сравнить результаты работы на тренированной модели DistilBERT и RuBERT в ноутубке.
Метрика | Значение |
---|---|
Exact match | 62.49 |
F1-score | 82.10 |
Average inference time | 0.4 сек |
Max inference time | 1 сек |
Для предобработки входных сообщений от пользователя был реализован класс TextSplitter, который имплементирует очень простой метод для разделения текста на вопросы и контекст. При инициализации класса автоматически загружается токенизатор NLTK для работы с русским языком. Метод split_question_context принимает входной текст, разбивает его на предложения, и проверяет каждое на наличие знака вопроса в конце. Вопросительные предложения добавляются в список, а остальные предложения собираются в общий текст контекста.
Этот подход позволяет быстро выделять вопросы и контекст, но имеет свои недостатки. Например, метод полагается на наличие знака вопроса в конце предложения, что может привести к пропуску вопросов, если они не оформлены корректно или содержат разные знаки препинания. Также реализованное решение не способно обрабатывать сложные структуры и семантику предложений.
-
Скорость работы: Использование быстрой модели в сочетании с простым и эффективным методом разделения входного текста на вопрос и ответ обеспечивает высокую скорость обработки запросов.
-
Точность ответов: Модель всегда извлекает ответ непосредственно из предоставленного контекста, что гарантирует высокую точность результатов.
-
Строгий формат входных данных: Решение требует, чтобы входные данные были строго оформлены, например, наличие вопросительного знака в вопросе (и только в вопросе). Это ограничивает гибкость системы и может привести к непредсказуемому поведению, если формат данных не соблюдается.
-
Ограниченность в понимании контекста: Модели, основанные на поиске start/end токенов, не справляются с более сложными вопросами, требующими глубокого анализа смысла контекста.
Телеграм-бот доступен по ссылке (если лимиты бесплатного тарифа еще не исчерпаны). Для хостинга я использовала платформу Railway. Однако при развертывании модели на Railway время выполения запроса возросло до почти минуты. Вероятно, Railway предоставляет ограниченные ресурсы для бесплатных проектов, что может влиять на скорость инференса.
Поэтому я рекомендую запускать бота локально, так как хостинг был организован исключительно для удобства тестирования моей работы в рамках отбора на смену по машинному обучению.
-
Клонируйте репозиторий
git clone https://github.com/MilyaushaShamsutdinova/ru_qa_system.git cd ru_qa_system
-
Откомментируйте 17-ую строку в Dockerfile и 16-ую строку в input_preprocessing.py
Эти строчки были закомментированны для деплоя телеграм бота. Для локального запуска они необходимы.
-
Создайте файл
.env
В файле
.env
укажите токен для бота:- BOT_TOKEN — токен для вашего бота, который можно получить в BotFather в Телеграме.
-
Соберите и запустите контейнер
docker-compose up --build
Возможно после запуска контейнера необходимо подождать минуту-две, прежде чем тестировать.
Теперь бот работает, можно использовать!
Чтобы отключить бота, остановите контейнер:
docker-compose down
Вы также можете скачать обученную QA модель с платформы Hugging Face и использовать в своих целях.