Почти за всем хорошим ML стоят хорошие данные. И так получилось, что таких данных часто нет и их приходится добывать, а даже добыв, из них нужно сделать что-то подходящее, и (если сильно огрубить) такой процесс называется разметкой.
Разметка — такая штука, когда все в индустрии делают примерно одно и то же, но чуть-чуть или сильно по разному. Разметка — очень нудная штука сама по себе, и потому ее запуском, отладкой и настройкой инженеры заниматься вот совсем не любят. Сам процесс довольно монотонен, но когда у тебя мультимодальный конвейер из поступающих данных, то делать всяческие инструменты для разметки и предлагать инженерам решения без их участия — это весело!
Одна из наших важнейших метрик, помимо качества результата, это позаимствованный у бизнеса термин ttm (time to market), что в нашем случае — время от момента прихода клиента с идеей по момент продуманного запуска его задачи в разметку.
В этой статье — пошагово о том, как мы не только ускорили написание инструкций, но и даже попутно повысили их качество. Идея — гениально проста, рецепт — повторяем, эффект — огонь.
Расчехляйте вашу LLM, закатайте рукава, тут есть много работки!
Процесс запуска задачи — достаточно муторная штука и вот почему. Независимо от типа ваших разметчиков, вам все равно необходимо максимально детально объяснить задачу разметчикам. Если мы хотим получить идеальный результат (а если нет, то для чего мы здесь вообще собрались?), то нужно расписать для чего это делается, почему именно так, привести примеры хорошо/плохо — вообщем, написать много текста с картинками. Любая детализация — это хорошо, она сыграет в плюс.
Но вариаций задач слишком много, повторюсь, все делают плюс-минус одно и то же, но вот в деталях начинаешь закапываться. И, кажется, будто бы унифицировать это практически невозможно.
Или нет?
Идея о том, что можно писать инструкции автоматом пришла после того, как в мир LLM с двух ног влетел RAG, то есть, способ добавления информации из собственной базы знаний. Кажется, будто бы это ровно то, что нам нужно.
В целом, хорошая инструкция — довольно унифицированная вещь, и это то, от чего стоит отталкиваться в предположении, что ее можно решить через LLM. Мы взяли GigaChat, просто в силу его корпоративности для нас, но наш рецепт — универсален, можно подключить любую другую.
Еще одной причиной желания переложить это на LLM была «проблема первого слова», когда инструкцию понятно как писать, но инженеру или заказчику сложно с чего-то начать.
Хорошая инструкция состоит из:
Описание в общем виде (что и для чего мы делаем) — это важно написать, чтобы люди понимали контекст того, что они будут размечать
Специфика конкретной задачи
Техническая информация и правила (как мы делаем разметку, инструменты) — описание требований к размерам bbox, требования к интервалам в видео и тд
Примеры (плохо/хорошо) — обязательная часть
Служебная информация — «что делать, если», тайминг выполнения, время приемки и тд
Ободрительные слова — «у вас все получится!»
Выглядит, будто бы часть из этих пунктов можно переложить на LLM. Более того, большинство новых инструкций копипастились из уже проверенных старых, после чего правились под новые условия. Это тоже добавляет уверенности, что все решаемо.
Но для начала давайте попробуем зайти с другого ракурса.
Если человек что-то хочет сделать, то в большинстве случаев выбирает подходящий для этого инструмент. И по наличию этого инструмента в руках, мы можем предположить, что человеку нужно будет сделать. Аналогия из мира ремонта: если мы видим человека с перфоратором, то врядли он будет заливать стяжку, а если мы видим человека с бензопилой, то с самой большой вероятностью он будет что-то пилить.
Этот концепт, что «человек с бензопилой собирается что-то пилить» — и есть основополагающий в нашем решении. В нем есть две вещи — «пилить» и «что-то».
«Пилить» — это в принципе понятный и описываемый процесс. Его можно в общем виде описать.
«Что-то» — штука прикладная и сильно сложнее, человек с бензопилой все равно не будет пилить бетон, человека (если дело не в Питере) или еду, список на «что-то» — все равно конечный.
Возвращаясь в мир AI, «выделять объекты в CV» — понятный процесс, а «что именно мы хотим выделять» — конечный список. Нет, все конкретные вариативности мы не сможем перебрать, это правда, но типы заданий конечны — мы выделяем либо объекты, либо зону интереса, либо позу и так далее.
Это немаленький, но конечный список.
Понятность и конечность позволяют нам сделать предположение о том, что мы можем собрать базу знаний.
Создать базу знаний было не очень сложно. Мы прошлись по всем инструментам, прошлись по сотням уже сделанных заданий и выделили максимально типовые.
Первым разбиением был тип контента — очевидно, что мы слишком по разному работаем, например, с видео и текстом.
Вторым разбиением стал тип задачи — сегментация это, SBS, оценка и так далее. Если мы вернемся к тому, из чего состоит инструкция, то накидать общий шаблон можно по всему списку пунктов, кроме примеров.
Это и было проделано. Мы не углублялсь в RAG в плане специальных БД, векторного поиска и так далее, наша задача вполне решалась более привычными способами. Если кого-то вдруг стриггерит (почему?), что RAG-то у нас ненастоящий, то - ну уж извините, я заранее готов признать, что это «RAG», для меня в целом это отличная идея, нежели конкретная реализация.
База знаний состояла из списка решаемых задач вообще и множества базовых инструкций по ним в зависимости от типа контента и верхнеуровневой задачи.
Промпт был написан почти сходу, без явного процесса его первой версии и последующего последовательного улучшайзинга. Задача промпта — на основе базы добавить специфики конкретной задачи заказчика.
В него просто были вложены все черные (и не очень) хаки, проявившие свою эффективность — рефрейминг («назначь себя экспертом в CV с 10 летним опытом»), следование инструкции («подчиняйся»), CoT, жесткое описание формата выхода (блоки ###вставь сюда####) и так далее.
Я не буду выкладывать промпт целиком, но магии там нет, он достаточно легко написабелен.
Впринципе, хороший промпт сам по себе может сгенерировать вам недурную инструкцию, но нам был нужен унифицированный и структурированный документ.
Ожидаемая и однообразная инструкция играет в плюс для разметчика, так как снижает время на ее ознакомление.
Приведу аналогию: в большом супермаркете возле дома вы всегда знаете где какой отдел, а когда вам надо купить что-то в большом незнакомом магазине — начинаются блуждания и трата времени. Процесс «купить мороженое» в известном магазине разительно по кпд отличается от неизвестного.
Каждый раз новый формат инструкции — это плохо. Еще более плохо, это попытка суммаризовать инструкцию через LLM (я, к сожалению, такое тоже видел в живом проекте лол) или играться с инструкцией в любом виде без проверки человеком, так как любая вольность в трактовке инструкций сильно снижает качество результата. Инструкция — документ, и он должен быть понятен, структурирован и ему нужно следовать неукоснительно.
Инструкцию надо заставлять читать, а не помогать ее пропускать.
Базовая инструкция с описанием и техническими требованиями — есть. Служебную информацию (о том, сколько у разметчика есть времени, время проверки и так далее) можно сгенерировать из заполненой формы и добавить просто текстом в конце. Подбадривающие тексты — тоже.
Чтобы уместить демо в гифку, пришлось отказаться от промпта и сильно урезать базовую инструкцию, а потом все ускорить в 4 раза.
Примеры — то единственное, что стоит сделать заказчику сознательно. Заказчики тоже не читают инструкции (сюрприз), поэтому здесь можно попытаться сгенерировать примеры (для текста и, может быть, картинок), но лучше чтобы все примеры были собраны из живого датасета, который предстоит размечать.
Итого: сначала мы визуально накидываем шаблон задания (это легко делается сразу в UI), после чего добавляем к нему промпт. Uuid шаблона и промпт уходят на бэк, где мы анализируем содержимое шаблона, достаем базовую инструкцию по такому типу заданий из базы знаний, после чего совмещаем с промптом и передаем в LLM-класс, который подключает конкретную LLM и все ей передает.
На выходе получается вполне себе похожий на правду результат. Это обязательно надо будет вычитывать и проверять человеком. Сейчас мы аккуратно выложили это (β, как принято делать) только на наших спецов поддержки, которые понимают механику генерации и записывают все предложения/проблемы и в целом занимаются улучшайзингом этой фичи, но эксперимент — однозначно удачный.
И самое приятное — в нем огромное пространство для маневра и тюнинга.
Сейчас LLM куда только не пихают, но нам было важно совместить приятное именно с полезным и порешать конкретную прикладную задачу, на которую тратилось много времени людей. Задача поставлена — задача решена.
По скорости — все понятно, по качеству за счет проработанности базовой инструкции итог может в среднем получиться в целом попродуманнее, чем если писать его с нуля, просто в силу наличия множества важных деталей в базовой инструкции.
Мы избавились от регулярного копипаста и лишней траты времени, да и в целом выглядит все приятно.
P.S.:
Следующие планы — создавать еще и шаблон самого задания целиком из текстового описания, задачка посложнее, но теперь тоже видится решаемой. Возможно, потребуется еще поуточнять у заказчика конкретные вопросы, но это уже поле для моих следующих экспериментов. В идеале его потом автоматом без людей и размечать, но это тоже отдельный вопрос.
Промпт:
«Мне нужна выделить все автомобили на трассе»
CoT:
Это задача CV на сегментацию
Скорее всего, модель будет работать в реальном времени
В реальном времени используются bbox для быстродействия
Добавляем класс автомобиль. Или несколько автомобилей по типу (фура, легковушка и тд). Уточняем у заказчика.
Описываем
.....
X) Сгенерировать инструкцию, json готово задания
Если вам понравилась статья, то предлагаю прочитать мои предыдущие:
Заменят ли LLM людей в разметке данных для AI?
Приключение SAM в Японии или как компьютерное зрение видит гейшу
AI-тренер, нейровоспитатель, ассесор, крауд и разметчик — кто все эти люди и в чем разница?
Спасибо!