Управление моделями для моделей LoRA с использованием Llama2 и Amazon SageMaker

Повышение эффективности модельного менеджмента в системе LoRA с применением Llama2 и Amazon SageMaker

В эпоху больших данных и искусственного интеллекта компании постоянно ищут способы использовать эти технологии для достижения конкурентного преимущества. Одной из самых горячих областей в искусственном интеллекте сейчас является генеративный искусственный интеллект, и это не просто так. Генеративный искусственный интеллект предлагает мощные решения, расширяющие границы возможного в терминах креативности и инноваций. В основе этих передовых решений лежит модель основы (FM), высокоэффективная модель машинного обучения, которая предварительно обучается на огромных объемах данных. Многие из этих базовых моделей показали замечательные способности к пониманию и генерации текста, похожего на человеческий, что делает их ценным инструментом для различных приложений, от создания контента до автоматизации обслуживания клиентов.

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

Существуют два основных подхода к тонкой настройке базовых моделей: традиционная тонкая настройка и параметрическая тонкая настройка. Традиционная тонкая настройка предполагает обновление всех параметров предварительно обученной модели для конкретной последующей задачи. С другой стороны, параметрическая тонкая настройка включает в себя различные техники, позволяющие настраивать модель без обновления всех исходных параметров модели. Одной из таких техник является метод “Низкопараметрическая адаптация” (LoRA). Он предполагает добавление небольших, специфичных для задачи модулей к предварительно обученной модели и их обучение с сохранением остальных параметров, как показано на следующем изображении.

Источник: Искусственный интеллект на AWS (O’Reilly, 2023)

Метод LoRA недавно приобрел популярность по нескольким причинам. Он предлагает более быстрое обучение, снижение требований к памяти и возможность повторного использования предварительно обученных моделей для нескольких последующих задач. Более того, базовая модель и адаптер могут храниться отдельно и комбинироваться в любое время, что облегчает хранение, распространение и обмен настроенными версиями. Однако это возникает новая проблема: как правильно управлять этими новыми типами настроенных моделей. Следует ли объединять базовую модель и адаптер или хранить их отдельно? В этой статье мы рассмотрим bewt практики управления настроенными моделями LoRA на Amazon SageMaker для решения этого возникающего вопроса.

Работа с FM в Model Registry на SageMaker

В этой статье мы рассмотрим пример от начала и до конца настройки модели Llama2 большого языкового модели (LLM) с использованием метода QLoRA. QLoRA сочетает преимущества параметрической тонкой настройки с квантизацией на 4/8 битов для дальнейшего сокращения ресурсов, необходимых для настройки FM под конкретную задачу или использование. Для этого мы будем использовать предварительно обученную модель Llama2 с 7 миллиардами параметров и настраивать ее на наборе данных databricks-dolly-15k. Подобные LLM, как Llama2, имеют миллиарды параметров и предварительно обучены на огромных наборах текстовых данных. Настройка позволяет адаптировать LLM к последующей задаче с использованием меньшего набора данных. Однако настройка больших моделей требует больших вычислительных затрат. Вот почему мы будем использовать метод QLoRA для квантования весов при настройке для сокращения вычислительных затрат.

В наших примерах вы найдете два блокнота (llm-finetune-combined-with-registry.ipynb и llm-finetune-separate-with-registry.ipynb). Каждый из них демонстрирует различные способы работы с настроенными моделями LoRA, как показано на следующей диаграмме:

  1. Во-первых, мы загружаем предварительно обученную модель Llama2 с 7 миллиардами параметров с помощью блокнотов SageMaker Studio. LLM, например Llama2, показали выдающуюся производительность в задачах обработки естественного языка (NLP) при донастройке на специализированных данных.
  2. Затем мы донастраиваем Llama2 на наборе данных databricks-dolly-15k с использованием метода QLoRA. QLoRA сокращает вычислительные затраты на донастройку путем квантования весов модели.
  3. Во время донастройки мы интегрируем SageMaker Experiments Plus с API Transformers, чтобы автоматически записывать метрики, такие как градиент, потери и т. д.
  4. Затем мы версионируем модель Llama2 после донастройки в реестре моделей SageMaker, используя два подхода:
    1. Хранение полной модели
    2. Хранение адаптера и базовой модели отдельно.
  5. Наконец, мы размещаем донастроенные модели Llama2 с помощью служб Deep Java Library (DJL) на конечной точке реального времени SageMaker.

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

Предварительные требования

Выполните следующие предварительные требования, чтобы начать экспериментировать с кодом.

  • Создайте домен SageMaker Studio: Amazon SageMaker Studio, в частности блокноты Studio, используется для запуска задачи донастройки Llama2, а затем регистрации и просмотра моделей в реестре моделей SageMaker. SageMaker Experiments также используется для просмотра и сравнения журналов задач донастройки Llama2 (потери обучения/потери теста и т. д.).
  • Создайте хранилище простой службы хранения Amazon (S3): Для хранения артефактов обучения и моделей требуется доступ к хранилищу S3. Инструкции по созданию хранилища можно найти в разделе Создание хранилища. В примере кода, используемом в этом посте, используется хранилище S3 по умолчанию SageMaker, но вы можете настроить его для использования любого соответствующего хранилища S3.
  • Настройте сборник моделей (IAM-разрешения): Обновите свою роль выполнения SageMaker с разрешениями на ресурсные группы, как указано в руководстве разработчика Модельной коллекции, чтобы реализовать группировку реестра моделей с помощью сборников моделей.
  • Примите условия использования модели Llama2: Вам потребуется принять лицензионное соглашение конечного пользователя и политику допустимого использования для использования базовой модели Llama2.

Примеры доступны в репозитории GitHub. Файлы блокнотов проверены с использованием блокнотов Studio, работающих на ядре PyTorch 2.0.0 для Python 3.10 и типе экземпляра ml.g4dn.xlarge с оптимизацией для GPU.

Интеграция аналитики с обратным вызовом Experiments plus

Amazon SageMaker Experiments позволяет организовывать, отслеживать, сравнивать и оценивать эксперименты и версии моделей машинного обучения (ML) из любой интегрированной среды разработки (IDE), включая локальные блокноты Jupyter, с помощью SageMaker Python SDK или boto3. Он предоставляет гибкость для записи метрик модели, параметров, файлов, артефактов, построения диаграмм на основе различных метрик, сбора различных метаданных, поиска и поддержки воспроизводимости модели. Ученым-исследователям быстро доступны визуальные диаграммы и таблицы для сравнения результатов и гиперпараметров модели. Они также могут использовать SageMaker Experiments для загрузки созданных диаграмм и предоставления результатов оценки модели заинтересованным лицам.

Обучение LLM может быть медленным, дорогостоящим и итеративным процессом. Очень важно отслеживать эксперименты LLM в масштабе, чтобы предотвратить несогласованный опыт настройки модели. Интерфейсы программирования приложений HuggingFace позволяют отслеживать метрики во время задач обучения с помощью обратных вызовов. Обратные вызовы – это фрагменты кода только для чтения, которые позволяют настраивать поведение цикла обучения в тренажере PyTorch и могут проверять состояние цикла обучения для отчетности о прогрессе, ведения журнала в TensorBoard или SageMaker Experiments Plus с помощью собственной логики (которая включена в эту кодовую базу).

Вы можете импортировать код обратного вызова SageMaker Experiments, включенный в репозиторий кода этого сообщения, как показано в следующем блоке кода:

# импортирует пользовательскую реализацию обратного вызова экспериментовfrom smexperiments_callback import SageMakerExperimentsCallback......# Создает экземпляр Trainer с обратным вызовом экспериментов SageMakertrainer = Trainer(    model=model,    args=training_args,    train_dataset=train_dataset,    eval_dataset=validation_dataset,    data_collator=default_data_collator,    callbacks=[SageMakerExperimentsCallback] # Добавляет нашу функцию Experiments Plus Callback)

Этот обратный вызов автоматически регистрирует следующую информацию в SageMaker Experiments в рамках обучения:

  • Параметры обучения и гиперпараметры
  • Значения потерь модели обучения и проверки на шаге, эпохе и финале
  • Входные и выходные артефакты модели (обучающий набор данных, проверочный набор данных, местоположение вывода модели, отладчик обучения и другое)

На следующем графике показаны примеры диаграмм, которые можно отобразить, используя эту информацию.

Это позволяет легко сравнивать несколько запусков с помощью функции анализа SageMaker Experiments. Вы можете выбрать запуски экспериментов, которые вы хотите сравнить, и они будут автоматически заполнять графики сравнения.

Регистрация донастроенных моделей в коллекциях реестра моделей

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

Метод полного копирования модели

Первый метод объединяет базовую модель и адаптер LoRA и сохраняет модель донастройки. В следующем коде показан процесс объединения модели и сохранения объединенной модели с использованиемmodel.save_pretrained().

if args.merge_weights:            trainer.model.save_pretrained(temp_dir, safe_serialization=False)    # очистить память    del model    del trainer    torch.cuda.empty_cache()        from peft import AutoPeftModelForCausalLM    # загрузить модель PEFT в формате fp16    model = AutoPeftModelForCausalLM.from_pretrained(        temp_dir,        low_cpu_mem_usage=True,        torch_dtype=torch.float16,    )      # объединить адаптер LoRA и базовую модель и сохранить    model = model.merge_and_unload()            model.save_pretrained(        args.sm_model_dir, safe_serialization=True, max_shard_size="2GB"    )

Совмещение адаптера LoRA и базовой модели в одном артефакте модели после донастройки имеет свои преимущества и недостатки. Объединенная модель является самодостаточной и может быть независимо управляемой и развернутой без необходимости оригинальной базовой модели. Модель может быть отслеживаема как самостоятельная сущность с именем версии, отражающим базовую модель и данные донастройки. Мы можем применить номенклатуру, используя base_model_name + fine-tuned dataset_name для организации групп моделей. Вариантно можно ассоциировать коллекции моделей с оригинальными и улучшенными моделями, но это может быть необязательно, поскольку объединенная модель является самостоятельной. В следующем фрагменте кода показано, как зарегистрировать настроенную модель.

# Переменные группы пакетов моделейft_package_group_name = f"{model_id.replace('/', '--')}-{dataset_name}"ft_package_group_desc = "QLoRA для модели Mikael110/llama-2-7b-{dataset_name}-fp16".........model_package_group_input_dict = {    "ModelPackageGroupName" : ft_package_group_name,    "ModelPackageGroupDescription" : ft_package_group_desc,    "Tags": ft_tags}create_model_pacakge_group_response = sm_client.create_model_package_group(**model_package_group_input_dict)

Вы можете использовать оценщик обучения для регистрации модели в Model Registry.

inference_image_uri = sagemaker.image_uris.retrieve(    "djl-deepspeed", region=region, version="0.23.0")print(f"Используемое изображение ---- > {inference_image_uri}")model_package = huggingface_estimator.register(    content_types=["application/json"],    response_types=["application/json"],    inference_instances=[        "ml.p2.16xlarge", .........    ],    image_uri = inference_image_uri,    customer_metadata_properties = {"training-image-uri": huggingface_estimator.training_image_uri()},  #Сохраняем URL изображения тренировки    model_package_group_name=ft_model_pkg_group_name,    approval_status="Approved")model_package_arn = model_package.model_package_arnprint("ARN модели пакета: ", model_package_arn)

Из Model Registry вы можете получить модельный пакет и развернуть эту модель напрямую.

endpoint_name = f"{name_from_base(model_group_for_base)}-endpoint"model_package.deploy(    initial_instance_count=1,    instance_type="ml.g5.12xlarge",    endpoint_name=endpoint_name)

Однако этот подход имеет свои недостатки. Совмещение моделей приводит к неэффективности хранения и дублированию, так как базовая модель дублируется в каждой тонкой настроенной версии. При увеличении размера модели и количества настроенных моделей это экспоненциально увеличивает потребности в хранилище. Например, модель llama2 7b имеет размер около 13 ГБ, а настроенная модель – 13,6 ГБ. 96% модели необходимо дублировать после каждой тонкой настройки. Кроме того, распространение и обмен очень большими файлами моделей также становится сложнее и представляет операционные проблемы, поскольку стоимость передачи и управления файлами возрастает с увеличением размера модели и задач параметризации.

Разделить адаптер и базовый метод

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

    ..    ..    ..    else:           # сохраняем настроенную модель LoRA, а затем токенизатор для прогнозирования        trainer.model.save_pretrained(            args.sm_model_dir,             safe_serialization=True        )    tokenizer.save_pretrained(        args.sm_model_dir    )

Сохранение базовых и адаптерных весов имеет преимущества и недостатки, аналогичные методу полного копирования модели. Одним из преимуществ является экономия места на диске. Базовые веса, которые являются самым большим компонентом настроенной модели, сохраняются только один раз и могут быть использованы повторно с другими весами адаптера, настроенными для разных задач. Например, базовые веса Llama2-7B занимают около 13 ГБ, но каждая задача настройки требует сохранения примерно 0,6 ГБ весов адаптера, что составляет экономию места в 95%. Еще одним преимуществом является возможность управления базовыми весами отдельно от весов адаптера с использованием реестра моделей только с базовыми весами. Это может быть полезно для доменов SageMaker, работающих в режиме только VPC без интернет-шлюза, поскольку базовые веса могут быть получены без необходимости подключения к Интернету.

Создание группы пакетов моделей для базовых весов

### Cоздание группы пакетов моделейbase_package_group_name = model_id.replace('/', '--')base_package_group_desc = "Источник: https://huggingface.co/Mikael110/llama-2-7b-guanaco-fp16".........model_package_group_input_dict = {    "ModelPackageGroupName" : base_package_group_name,    "ModelPackageGroupDescription" : base_package_group_desc,    "Tags": base_tags}create_model_pacakge_group_response = sm_client.create_model_package_group(**model_package_group_input_dict)>>>Создана группа пакетов моделей Arn: arn:aws:sagemaker:us-west-2:376678947624:model-package-group/Mikael110--llama-2-7b-guanaco-fp16.........### Регистрация базовых весов моделиfrom sagemaker.huggingface import HuggingFaceModel# создание класса модели Hugging Facehuggingface_model = HuggingFaceModel(    transformers_version='4.28',    pytorch_version='2.0',    py_version='py310',    model_data=model_data_uri, # это путь к ваших базовым весам в формате *.tar.gz на S3    role=role,)_response = huggingface_model.register(    content_types=["application/json"],    response_types=["application/json"],    inference_instances=[    "ml.p2.16xlarge",    ...    ],    transform_instances=[    "ml.p2.16xlarge",    ...    ],    model_package_group_name=base_model_pkg_group_name,    approval_status="Approved" )

Создание группы пакетов моделей для весов QLoRA

Следующий код показывает, как пометить веса QLoRA с типом набора данных/задачи и зарегистрировать отдельные веса с дельтой после настройки в отдельном реестре моделей и отслеживать дельту весов отдельно.

### Создание группы пакетов моделей для дельтовых весовft_package_group_name = f"{model_id.replace('/', '--')}-принастроенный-sql"ft_package_group_desc = "QLoRA для модели Mikael110/llama-2-7b-guanaco-fp16"ft_tags = [    {    "Key": "ТипМодели",    "Value": "QLoRAModel"    },    {    "Key": "Принастроенный",    "Value": "True"    },    {    "Key": "ИсточникНабораДанных",    "Value": f"{dataset_name}"    }]model_package_group_input_dict = {    "ИмяГруппыПакетаМоделей" : ft_package_group_name,    "ОписаниеГруппыПакетаМоделей" : ft_package_group_desc,    "Теги": ft_tags}create_model_pacakge_group_response = sm_client.create_model_package_group(**model_package_group_input_dict)print(f'Создан ARN группы ModelPackageGroup : {create_model_pacakge_group_response["ModelPackageGroupArn"]}')ft_model_pkg_group_name = create_model_pacakge_group_response["ModelPackageGroupArn"]>>> Создан ARN группы ModelPackageGroup : arn:aws:sagemaker:us-east-1:811828458885:model-package-group/mikael110--llama-2-7b-guanaco-fp16-finetuned-sql.........### Регистрация дельтовых весов QLoRA Моделиhuggingface_model = HuggingFaceModel(    transformers_version='4.28',    pytorch_version='2.0',      py_version='py310',    model_data="s3://sagemaker-us-east-1-811828458885/huggingface-qlora-2308180454/output/model.tar.gz", OR #huggingface_estimator.model_data    role=role,)_response = huggingface_model.register(    content_types=["application/json"],    response_types=["application/json"],    inference_instances=[    "ml.p2.16xlarge",    ...    ],    transform_instances=[    "ml.p2.16xlarge",    ...    ],    model_package_group_name=ft_model_pkg_group_name,    approval_status="Approved")>>>Статус создания коллекции моделей: {'added_groups': ['arn:aws:sagemaker:us-east-1:811828458885:model-package-group/mikael110--llama-2-7b-guanaco-fp16-finetuned-sql'], 'failure': []}

В следующем фрагменте показано представление в Реестре моделей, где модели разделены на базовые и принастроенные веса.

Управление моделями, наборами данных и задачами для гиперперсонализированных LLM-моделей может быстро стать сложной задачей. Коллекции Реестра моделей SageMaker могут помочь вам группировать связанные модели и организовывать их иерархически для улучшения обнаружения моделей. Это упрощает отслеживание связей между базовыми весами, весами адаптера и наборами данных для настройки. Вы также можете создавать сложные связи между моделями.

Создать новую коллекцию и добавить базовые веса модели в эту коллекцию

# create model collectionbase_collection = model_collector.create(    collection_name=model_group_for_base # например, "Website_Customer_QnA_Bot_Model")# Добавить базовые веса на первом уровне коллекций моделей, так как все будущие модели # будут настраиваться на базовых весах_response = model_collector.add_model_groups(    collection_name=base_collection["Arn"],    model_groups=[base_model_pkg_group_name])print(f"Статус создания коллекции моделей: {_response}")>>>Статус создания коллекции моделей: {'added_groups': ['arn:aws:sagemaker:us-west-2:376678947624:model-package-group/Mikael110--llama-2-7b-guanaco-fp16'], 'failure': []}
# Создание коллекции моделей для Fine-Tuned и связываем ее с базовой finetuned_collection = model_collector.create( collection_name=model_group_for_finetune, parent_collection_name=model_group_for_base)# Добавление группы моделей Fine-Tuned в новую коллекцию finetuned response = model_collector.add_model_groups( collection_name=model_group_for_finetune, model_groups=[ft_model_pkg_group_name])print(f"Статус создания коллекции моделей: {_response}")>>>Статус создания коллекции моделей: {'added_groups': ['arn:aws:sagemaker:us-east-1:811828458885:model-package-group/mikael110--llama-2-7b-guanaco-fp16-finetuned-sql'], 'failure': []}

Это приведет к иерархии коллекций, которые связаны типами модели/задания и использованными наборами данных для настройки базовой модели.

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

!aws s3 cp {base_model_package.model_data} .!tar -xvf {model_tar_filename} -C ./deepspeed/!mv ./deepspeed/{model_id} ./deepspeed/base!rm -rf ./deepspeed/{model_id}

Затем загрузите и упакуйте самые новые веса финетьюнинга адаптера LoRA.

!aws s3 cp {LoRA_package.model_data} .!mkdir -p ./deepspeed/lora/!tar -xzf model.tar.gz -C ./deepspeed/lora/

Поскольку вы будете использовать DJL сервис с deepspeed для размещения модели, ваша директория вывода должна иметь следующий вид.

deepspeed    |-serving.properties    |-requirements.txt    |-model.py    |-base/        |-...    |-lora/        |-...

Наконец, упакуйте пользовательский код вывода, базовую модель и адаптер LoRA в один файл .tar.gz для развертывания.

!rm -f model.tar.gz!tar czvf model.tar.gz -C deepspeed .s3_code_artifact_deepspeed = sagemaker_session.upload_data("model.tar.gz", default_bucket, f"{s3_key_prefix}/inference")print(f"S3 Код или модель tar для deepspeed загружены по адресу --- > {s3_code_artifact_deepspeed}")

Очистка

Очистите свои ресурсы, следуя инструкциям в разделе очистки блокнота. Подробнее см. Стоимость использования Amazon SageMaker для получения подробной информации о стоимости экземпляров вывода.

Заключение

В этой статье мы рассмотрели bew practices для управления моделями, оптимизированными с помощью LoRA, в Amazon SageMaker. Мы рассмотрели два основных подхода: объединение базовой модели и адаптерных весов в одну самодостаточную модель и разделение базовой модели и адаптерных весов. Оба подхода имеют свои преимущества и недостатки, но разделение весов помогает оптимизировать хранение и позволяет применять продвинутые техники управления моделью, такие как реестр моделей SageMaker Collections. Это позволяет создавать иерархии и связи между моделями для улучшения организации и обнаружения. Мы рекомендуем вам попробовать образец кода в репозитории GitHub, чтобы самостоятельно попробовать эти методы. Поскольку генеративный ИИ быстро развивается, следование bew practices управления моделями поможет вам отслеживать эксперименты, найти подходящую модель для вашей задачи и эффективно управлять специализированными моделями LLM масштабируемым способом.

Литература