Можно сказать, что это часть 1.5 😅 моей мини-серии Создание комплексных приложений на базе LLM без API Open AI.
О чем пока идет речь в сериале
- Интеграция пользовательского LLM с использованием langchain (пример GPT4ALL)
- Управление конфигурацией приложений на базе LLM
- Подключение LLM к базе знаний (скоро)
- Обслуживание LLM с использованием Fast API (скоро)
- Тонкая настройка LLM с использованием преобразователей и его интеграция в существующий конвейер для конкретных вариантов использования (скоро)
- Собираем все вместе в простое облачное приложение на базе LLM (скоро)
Давайте начнем
Но почему? Почему я должен заботиться о файлах конфигурации? Потому что перед созданием сквозных приложений очень важно иметь правильно организованные структурированные конфигурации для управления проектами. Есть несколько причин, по которым вам следует позаботиться об управлении конфигурацией. Вот некоторые из них по отношению к нашему проекту:
- Управление путями моделей. Возможно, вам потребуется изменить путь к модели или ссылку S3. И зависимости пути могут быть отражены в нескольких файлах проекта.
- Управление гиперпараметрами. Предположим, у вас есть конвейер тонкой настройки или конвейер вывода. Гиперпараметры, такие как скорость обучения, выбор оптимизатора и т. д., становятся трудными для управления, если они инициализируются в файлах проекта. В наших случаях такие конфиги, как надо стримить или нет, температура, top_p, top_k и т.д.
- Конфигурации действуют как настройки. Как и все приложения (даже ваши приложения для Android/iOS) имеют встроенные настройки. Точно так же файлы конфигурации также действуют как настройки, которые также могут быть изменены вне внутренней структуры кода, но могут сообщать о том, как должен работать ваш код. Даже файлы конфигурации очень полезны при написании кода инфраструктуры для обслуживания приложений.
Отсутствие управления конфигурацией может вызвать серьезные проблемы во время производства при масштабировании систем или настройке/обновлении параметров.
То же самое касается структуры проекта. Создание модульной структуры проекта очень важно. Современные облачные приложения требуют надлежащей структуризации проектов, чтобы большинство модулей были отделены (независимы) друг от друга и могли обрабатываться или масштабироваться независимо друг от друга. Теперь, когда вы получили некоторое представление о написании файлов конфигурации, теперь давайте перейдем непосредственно к созданию структуры нашего проекта и напишем наши файлы конфигурации. Для структуры проекта мы будем использовать CookieClutter для создания шаблона нашего проекта, а для управления конфигурацией мы будем использовать Hydra.
Структурирование нашего проекта
CookieClutter — это утилита командной строки, которая создает структуру проекта из уже существующих шаблонов проекта. Вы можете установить cookiecutter с помощью
pip install cookiecutter
Затем мы будем использовать популярный репозиторий шаблонов под названием наука о данных cookieclutter. Мы можем легко настроить его с помощью этой команды
cookiecutter -c v1 https://github.com/drivendata/cookiecutter-data-science
Это приведет вас к простому приложению CLI, где вам нужно ввести такие вещи, как имена приложений, описания и т. д. И это создаст базовый шаблон. Но поскольку мы здесь не занимаемся наукой о данных, я удалил некоторые файлы и папки, и структура, которую я использую, теперь выглядит так.
. ├── configs │ ├── config.yaml │ ├── knowledge_base │ │ └── default.yaml │ └── model │ └── default.yaml ├── data │ ├── diff_lm.pdf │ └── llama2.pdf ├── LICENSE ├── main.py ├── Makefile ├── README.md ├── requirements.txt ├── setup.py ├── src │ ├── data │ │ └── __init__.py │ ├── __init__.py │ └── models │ └── __init__.py ├── test_environment.py ├── tests └── tox.ini
Вот некоторая информация, которую вам нужно знать о том, для чего предназначена каждая папка.
configs
: Это в основном для хранения различных конфигураций для каждого из компонентов в наших приложениях. Примеры: модели, база знаний, векторная база данных и т. д.data
: Это используется для сохранения всех наших документов для нашей базы знаний. Однако на практике документы должны храниться внутри такого сервиса, как Amazon S3.src
: он содержит все наши исходные файлы с подпапками, такими какdata
, которые будут содержать все файлы для создания и управления нашей базой знаний иmodels
для создания и управления нашими LLM.tests
: Здесь мы будем хранить все наши файлы для тестирования, такого как модульное тестирование, интеграционное тестирование и т. д.main.py
: На данный момент это будет наш основной файл Python, который будет использовать исходные файлы в качестве помощника и запускать основной код. Мы запустим этот код для нашего чат-бота.Makefile
полезен для быстрой настройки нашего проекта, такой как установка зависимостей, линтинг, форматирование, быстрое тестирование и т. д.
Код из нашего предыдущего блога будет находиться внутри src/models
папки. Сегодня мы сосредоточимся на написании файлов конфигурации в папке configs
. Я предполагаю, что читатели уже знакомы с моим предыдущим блогом о том, как мы интегрировали собственный LLM с открытым исходным кодом (используя gpt4all
и langchain
). Потому что сегодня мы будем писать файлы конфигурации для наших моделей.
Сценарий
Короче говоря, давайте представим себе этот сюжет. Предположим, ваше приложение позволяет пользователям общаться с различными типами данных и с различными вариантами LLM с открытым исходным кодом. Доступ к различным LLM с открытым исходным кодом осуществляется через разных поставщиков, таких как LLAMA.cpp
, GPT4ALL
, HugggingFace
и т. д. Теперь каждая из моделей, написанных с использованием разных библиотек, может иметь разные оптимальные конфигурации. Как ты собираешься с ними справиться? Ответ заключается в написании файлов конфигурации. Здесь мы будем писать наши конфигурации для наших моделей gpt4all
LLM.
Гидра 101
Начнем с установки Гидры. Мы можем сделать это с помощью этой команды
pip install hydra-core==1.1.0
Hydra работает поверх
OmegaConf
, которая представляет собой иерархическую систему конфигурации на основеYAML
с поддержкой объединения конфигураций из нескольких источников (файлов, аргументов CLI, переменных среды), обеспечивая согласованный API независимо от того, как была создана конфигурация.
Написание ваших первых файлов конфигурации
Давайте начнем с создания простого файла yaml
с именем config.yaml
, а содержимое файла yaml
будет таким:
gpt4all: gpt4all_model_name: ggml-gpt4all-j-v1.3-groovy.bin gpt4all_model_folder_path: /home/anindya/.local/share/nomic.ai/GPT4All/ gpt4all_backend: llama
Выше приведен файл конфигурации, который я написал с помощью yaml. Теперь я мог бы также написать то же самое, как это
gpt4all_model_name: ggml-gpt4all-j-v1.3-groovy.bin gpt4all_model_folder_path: /home/anindya/.local/share/nomic.ai/GPT4All/ gpt4all_backend: llama
Этот тоже действителен. Но все зависит. Давайте рассмотрим, что первый yaml — это формат 1, а второй — формат 2. Формат 1 позволяет мне одновременно добавлять конфигурации разных поставщиков моделей. Например, если я сейчас хочу добавить конфигурации обнимающих лиц, я мог бы сделать что-то вроде этого.
gpt4all: gpt4all_model_name: ggml-gpt4all-j-v1.3-groovy.bin gpt4all_model_folder_path: /home/anindya/.local/share/nomic.ai/GPT4All/ gpt4all_backend: llama hugging_face: hugging_face_model_id: some model name hugging_face_adapter_name: some adapter id hugging_face_dataset: some dataset source id
В то время как в формате 2 я мог бы сделать то же самое, но в разных файлах. В этом случае один файл будет называться gpt4all_config.yaml
, другой — huggingface_config.yaml
. Все зависит от того, насколько сложны наши проекты, и исходя из этого мы должны выбрать нашу
Теперь давайте загрузим этот файл с помощью Hydra
и воспользуемся печатью конфигураций.
# file name: main.py import hydra @hydra.main(config_path='.', config_name='config') def main(cfg): print('GPT4ALL Configurations') print(' Model name: ', cfg.gpt4all.gpt4all_model_name) print(' Model stored in path: ', cfg.gpt4all.gpt4all_model_folder_path) print(' Model using LLM backend of: ', cfg.gpt4all.gpt4all_backend) print('\nHuggingFace Configurations') print(' Hugging face model name: ', cfg.hugging_face.hugging_face_model_id) print(' Hugging face adapter name: ', cfg.hugging_face.hugging_face_adapter_name) print(' Hugging face dataset name: ', cfg.hugging_face.hugging_face_dataset) if __name__ == '__main__': main()
Я предполагаю, что интуитивно вы можете обнаружить, что все необходимое гидры здесь заключается в том, что какую бы конфигурацию мы ни предоставили через кучу файлов yaml, она предоставляет хороший объектно-ориентированный интерфейс, так что он может быть легко доступен. Запуск этого будет печатать следующее
GPT4ALL Configurations Model name: ggml-gpt4all-j-v1.3-groovy.bin Model stored in path: /home/anindya/.local/share/nomic.ai/GPT4All/ Model using LLM backend of: llama HuggingFace Configurations Hugging face model name: some model name Hugging face adapter name: some adapter id Hugging face dataset name: some dataset source id
Есть еще несколько вещей, которыми знаменита Гидра. Одной из таких вещей является переопределение конфигураций. Это означает, что мы можем изменять конфигурации во время выполнения и соответственно запускать наше приложение. Вот пример, когда я запускаю это приложение.
python3 main.py \ gpt4all.gpt4all_model_name="my latest model name" \ gpt4all.gpt4all_model_folder_path="my latest folder" \ gpt4all.gpt4all_backend="GPTJ"
И это будет печатать
GPT4ALL Configurations Model name: my latest model name Model stored in path: my latest folder Model using LLM backend of: GPTJ HuggingFace Configurations Hugging face model name: some model name Hugging face adapter name: some adapter id Hugging face dataset name: some dataset source id
Думаю, этой информации достаточно, чтобы вы все начали работу с нашим существующим проектом. Однако, если вам интересно узнать больше, ознакомьтесь с потрясающей документацией самой Hydra. Кроме того, большая часть этого 101 была вдохновлена этим потрясающим блогом Raviraja Ganta. Он использовал Hydra, чтобы показать нам, как управлять конфигурациями при создании комплексных приложений машинного обучения.
Применение Hydra к нашему проекту для управления нашей моделью
Ранее я показал вам, как создать один файл yaml и использовать его в качестве наших конфигураций. Но в реальных сценариях нам придется обрабатывать гораздо более сложные вещи. Вы можете просто взять наши примеры приложений. Сейчас мы просто имеем дело с нашей моделью. В дальнейшем нам предстоит сделать то же самое для нашей векторной базы данных (базы знаний), API, сервировки и т. д. Поэтому лучше создавать конфиги для разных компонентов. Вот пример нашей структуры папок config
.
configs ├── config.yaml ├── knowledge_base │ └── default.yaml └── model └── default.yaml
Думайте о config.yaml
внутри configs
как о оркестраторе конфигурации. Это означает, что config.yaml
знает, где находятся другие конфигурации каждого компонента, и через config.yaml
мы можем загружать и управлять другими компонентами. Теперь внутри model
и knowledge_base
есть этот default.yaml
, который имеет конфигурации по умолчанию для нашей модели и нашей базы знаний (мы поговорим о базе знаний в последующих частях нашего блога). Теперь давайте посмотрим на наш файл config.yaml
.
defaults: - model: default - knowledge_base: default
Если мы просто воспользуемся своей интуицией, то понять это будет несложно. В нем говорится, что наши default
конфигурации следующие. Конфигурации модели по умолчанию будут использовать default.yaml
внутри configs/models
и то же самое для нашей базы знаний. Теперь аналогичным образом configs/models
может содержать другие файлы конфигурации, такие как model_dev.yaml
(все конфигурации модели для этапа разработки), model_production.yaml
(нетронутые конфигурации для производства, мы также можем сделать его доступным только для чтения с помощью Hydra, если захотим). И затем мы можем использовать это в нашей ссылке config.yaml
. Но пока оставим эту настройку.
После этого давайте посмотрим, как выглядит наш configs/models/default.yaml
.
gpt4all_model: gpt4all_model_name: ggml-gpt4all-j-v1.3-groovy.bin gpt4all_model_folder_path: /home/anindya/.local/share/nomic.ai/GPT4All/ gpt4all_backend: llama gpt4all_allow_streaming: true gpt4all_allow_downloading: false gpt4all_temperature: 1 gpt4all_top_p: 0.1 gpt4all_top_k: 40 gpt4all_n_batch: 8 gpt4all_n_threads: 4 gpt4all_n_predict: 256 gpt4all_max_tokens: 200 gpt4all_repeat_last_n: 64 gpt4all_penalty: 1.18
Теперь мы записали все изменяемые параметры внутри конфига, и мы также сделали ссылки на наш config.yaml
. Теперь внутри нашего файла main.py
давайте используем его, чтобы проверить, работают ли наши конфиги. А также во время выполнения main.py
мы настроим некоторые параметры, как это было сделано ранее в нашем фиктивном примере, чтобы увидеть, работает ли это и в этом случае.
Вот наш файл main.py
.
import hydra from src.models.gpt4all_model import MyGPT4ALL # reference the ./configs folder to tell hydra where the configs are located # also tell hydra that our master config (which manages all other config) # name is config. @hydra.main(config_path='./configs', config_name='config') def main(cfg): # instantiate the model and populate the arguments using hydra chat_model = MyGPT4ALL( model_folder_path=cfg.model.gpt4all_model.gpt4all_model_folder_path, model_name=cfg.model.gpt4all_model.gpt4all_model_name, allow_download=cfg.model.gpt4all_model.gpt4all_allow_downloading, allow_streaming=cfg.model.gpt4all_model.gpt4all_allow_streaming, ) while True: query = input('Enter your Query: ') if query == 'exit': break # use hydra to fill the **kwargs response = chat_model( query, n_predict=cfg.model.gpt4all_model.gpt4all_n_predict, temp=cfg.model.gpt4all_model.gpt4all_temperature, top_p=cfg.model.gpt4all_model.gpt4all_top_p, top_k=cfg.model.gpt4all_model.gpt4all_top_k, n_batch=cfg.model.gpt4all_model.gpt4all_n_batch, repeat_last_n=cfg.model.gpt4all_model.gpt4all_repeat_last_n, repeat_penalty=cfg.model.gpt4all_model.gpt4all_penalty, max_tokens=cfg.model.gpt4all_model.gpt4all_max_tokens, ) print() if __name__ == '__main__': main()
Я считаю, что этот файл достаточно прост для понимания. Все, что он делает, это создает экземпляр chat_model
, используя наши конфигурации гидры, а также вызывает **kwargs
при использовании модели в чате с нашими конфигурациями гидры. И если мы просто запустим python3 main.py
, он должен работать, как и ожидалось. Но предположим, что мы хотим настроить некоторые параметры во время выполнения. Взгляните на это, например.
PYTHONPATH=. python3 main.py \ model.gpt4all_model.gpt4all_model_name=ggml-mpt-7b-instruct.bin \ model.gpt4all_model.gpt4all_temperature=1 \ model.gpt4all_model.gpt4all_top_k=50 \ model.gpt4all_model.gpt4all_max_tokens=10 \ model.gpt4all_model.gpt4all_penalty=1.00
Я изменил имя модели, температуру, значения top_k, max_tokens и штраф, и, следовательно, он изменит параметры перед запуском кода. Тоже лучшая часть!!! Это дает нам отличный клиентский интерфейс, не позволяя нам его создавать. Разве это не потрясающе?
Заключение
Поздравляю 🥳🥳. Вы только что завершили очень важную часть общих жизненных циклов машинного обучения производственного уровня, то есть управление конфигурацией. И мы можем применить эти знания при создании наших приложений на базе LLM. Сейчас это может выглядеть не очень круто, но уверяю вас, это упрощает жизнь, когда приложения становятся слишком сложными для обработки. В следующей части нашего блога мы узнаем, как соединять документы и создавать из них базу знаний, чтобы сделать LLM более надежными и отвечать на вопросы по невидимым, частным документам. Все коды, использованные здесь и ранее, сброшены в этот репозиторий GitHub. Не стесняйтесь проверить это. До скорого. 💪
Ссылки и благодарности
- Управление конфигурацией с помощью Hydra от Raviraja Ghanta https://deep-learning-blogs.vercel.app/blog/mlops-hydra-config
- Освоение управления конфигурацией с помощью Hydra https://towardsdatascience.com/mastering-configuration-ml-with-hydra-ef138f1c1852