Сохранение точно настроенной модели Falcon HuggingFace LLM

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

Для обучения используются следующие параметры:

hf_model_name = "tiiuae/falcon-7b-instruct"
dir_path = 'Tiiuae-falcon-7b-instruct'
model_name_is = f"peft-training"
output_dir = f'{dir_path}/{model_name_is}'
logs_dir = f'{dir_path}/logs'
model_final_path = f"{output_dir}/final_model/"
EPOCHS = 3500
LOGS = 1
SAVES = 700
EVALS = EPOCHS / 100
compute_dtype = getattr(torch, "float16")
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type = "nf4",
    bnb_4bit_compute_dtype=compute_dtype,
    bnb_4bit_use_double_quant=False,
)
model = AutoModelForCausalLM.from_pretrained(
        "tiiuae/falcon-7b-instruct",
        quantization_config=bnb_config,
        device_map = {"": 0},
        trust_remote_code=False
)
peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.05, # 0.1
    r=64,
    bias = "lora_only", # none
    task_type = "CAUSAL_LM",
    target_modules=[
        "query_key_value"
    ],
)
model.config.use_cache = False
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
tokenizer = AutoTokenizer.from_pretrained("tiiuae/falcon-7b-instruct", trust_remote_code=False)
tokenizer.pad_token = tokenizer.eos_token
training_arguments = TrainingArguments(
    output_dir=output_dir,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,
    optim='paged_adamw_32bit',
    max_steps=EPOCHS,
    save_steps=SAVES,
    logging_steps=LOGS,
    logging_dir=logs_dir,
    eval_steps=EVALS,
    evaluation_strategy = "steps",
    fp16=True,
    learning_rate=0.001,
    max_grad_norm=0.3,
    warmup_ratio=0.15, # 0.03
    lr_scheduler_type = "constant",
    disable_tqdm=True,
)
model.config.use_cache = False
trainer = SFTTrainer(
    model=model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    peft_config=peft_config,
    dataset_text_field = "text",
    max_seq_length=448,
    tokenizer=tokenizer,
    args=training_arguments,
    packing=True,
)
for name, module in trainer.model.named_modules():
    if "norm" in name:
        module = module.to(torch.float32)
train_result = trainer.train()

А сохранение я сделал так:

metrics = train_result.metrics
max_train_samples = len(train_dataset)
metrics["train_samples"] = min(max_train_samples, len(train_dataset))
# save train results
trainer.log_metrics("train", metrics)
trainer.save_metrics("train", metrics)
# compute evaluation results
metrics = trainer.evaluate()
max_val_samples = len(eval_dataset)
metrics["eval_samples"] = min(max_val_samples, len(eval_dataset))
# save evaluation results
trainer.log_metrics("eval", metrics)
trainer.save_metrics("eval", metrics)

model.save_pretrained(model_final_path)

Теперь я пробовал много разных способов загрузить его или загрузить и сохранить разными способами снова и снова (например, добавляя lora_model.merge_and_unload(), просто используя local_model = AutoModelForCausalLM.from_pretrained(after_merge_model_path) и т. д.), но у меня, кажется, ничего не работает, все приводило к ошибкам (иногда одни и те же ошибки, иногда разные), здесь мне нужна ваша помощь.

Если вы считаете, что это лучше подходит, я тоже открыл вопрос здесь Форум HuggingFace

С какими ошибками вы столкнулись? Обычно он также должен кэшировать модель локально и загружать ее только один раз.

Daraan 18.07.2024 16:39

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

Lidor Eliyahu Shelef 20.07.2024 23:36
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
144
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Точная настройка осуществляется с помощью обучающих адаптеров поверх базовой модели. И после обучения вы сохраняете только адаптер, а не базовую модель. Итак, рабочий процесс следующий:

Во время обучения:

  • вы загружаете базовую модель из HF и сохраняете ее в каталоге кеша
  • вы тренируете адаптер PEFT и сохраняете его

Во время вывода

  • Загрузить кэшированную базовую модель HF
  • Загрузите сохраненный адаптер peft и примените его к базовой модели.

Шаг 1. Загрузите модель HF в предопределенный кешированный каталог:

import os
from pathlib import Path

# set cache for pretrained model
os.environ['HF_HOME'] = '/content/assets/hf_cache/'
os.environ['HF_DATASETS_CACHE'] = '/content/assets/hf_datasets/'

dir_path = Path('/content')
adapter_final_path = dir_path / f"output" / "final_adapter"
base_quantized_path = dir_path / f"output" / "base_model_q"

hf_model_name = "tiiuae/falcon-7b-instruct"

# load the tokenizer
tokenizer = AutoTokenizer.from_pretrained(hf_model_name, 
                              trust_remote_code=False)
        
tokenizer.pad_token = tokenizer.eos_token


# load the model
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type = "nf4",
    bnb_4bit_compute_dtype=torch.float16,
    bnb_4bit_use_double_quant=False,
)


model = AutoModelForCausalLM.from_pretrained(
        hf_model_name,
        quantization_config=bnb_config,
        device_map = {"": 0},
        trust_remote_code=False
)

model.save_pretrained(base_quantized_path)
tokenizer.save_pretrained(base_quantized_path)
...

После обучения сохраните пефт-адаптеры:

... train the model...

train_result = trainer.train()


model.save_pretrained(adapter_final_path)

Во время вывода перезагрузите базовую модель и адаптер peft:


# load base model
model = AutoModelForCausalLM.from_pretrained(base_quantized_path)
tokenizer = AutoTokenizer.from_pretrained(base_quantized_path)

# apply saved adapter to the model
model.load_adapter(adapter_final_path)

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

Lidor Eliyahu Shelef 20.07.2024 10:09

Чтобы предотвратить повторную загрузку модели, вам необходимо установить каталог HF-кэша os.environ['HF_HOME']. В этом случае базовая модель будет сохранена в заранее указанном каталоге и будет загружена при следующем вызове AutoModelForCausalLM.from_pretrained

Johnny Cheesecutter 20.07.2024 18:51

Другой вариант — сохранить предварительно обученную (базовую) модель после ее загрузки и квантования: model.save_pretrained(base_quantized_path) и tokenizer.save_pretrained(base_quantized_path)

Johnny Cheesecutter 20.07.2024 19:11

Что касается вашего второго варианта, как мне сделать это локально, а затем загрузить модель в мою программу Streamlit, чтобы пользователю не приходилось ждать, пока модель загрузится?

Lidor Eliyahu Shelef 20.07.2024 23:30

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

Johnny Cheesecutter 21.07.2024 14:30

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

Lidor Eliyahu Shelef 21.07.2024 15:12

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

Lidor Eliyahu Shelef 21.07.2024 15:22

Хорошо, тогда вопрос в том, как это сделать конкретно в Streamlit. Потому что подход различается в зависимости от фреймворков, которые вы используете. Я бы порекомендовал просмотреть эту статью: docs.streamlit.io/develop/concepts/architecture/caching И посмотреть пример загрузки моделей с помощью @st.cache_resource.

Johnny Cheesecutter 21.07.2024 18:45

Я пробовал использовать и @st.cache_resource, и os.environ['HF_HOME'] на своем диске D, но он все равно каждый раз загружает его на мой диск C и вылетает из-за нехватки места.

Lidor Eliyahu Shelef 22.07.2024 08:55

Привет, Лидор, было бы очень полезно, если бы можно было предоставить точный код Streamlit, который вы используете. Спасибо.

Johnny Cheesecutter 22.07.2024 19:15

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

Johnny Cheesecutter 24.07.2024 18:24

Я прочитал предоставленный вами код, и он кажется лучше: когда вы сохраняете базовую модель, а затем загружаете ее из каталога кеша, она не будет повторно загружаться и будет быстрее? (Джонни Чизкаттер). Что вы думаете об ответе? @ЛидорЭлиягуШелеф

Dolev Mitz 25.07.2024 05:36

Вам следует проверить несколько вещей: 1) HF повторно загружает контрольные точки модели из Интернета? (выключите Wi-Fi, чтобы проверить это, если вы не уверены); 2) HF загружает КПП модели из файлов или памяти? При первом вызове он должен загрузить модель из файла, а во второй раз его следует вызвать из памяти, иначе вы создадите дубликат объекта в памяти и тем самым также можете использовать дополнительную память графического процессора;

Johnny Cheesecutter 25.07.2024 12:40

3) Перезагружает ли Streamlit модель из файла каждый раз, когда вы вызываете приложение (или когда два разных пользователя открывают приложение/когда вы открываете приложение в двух разных вкладках или браузерах) или использует общий объект из памяти? Streamlit построен таким образом, что для каждого пользователя он перезапускает все конвейеры с нуля. По сути,streamlit клонирует все, начиная с кода Python, для каждого пользователя.

Johnny Cheesecutter 25.07.2024 12:41

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

Johnny Cheesecutter 25.07.2024 13:12

Другие вопросы по теме