Я пытаюсь сохранить свою модель, чтобы не приходилось заново загружать базовую модель каждый раз, когда я хочу ее использовать, но у меня ничего не получается. Мне бы очень хотелось, чтобы вы помогли с этим.
Для обучения используются следующие параметры:
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
Я ищу способ, который не потребует его загрузки, если это возможно, я не хочу, чтобы платформа «зависала» на долгое время, пока она загружает и загружает ее каждый раз, когда пользователь входит в нее.
Точная настройка осуществляется с помощью обучающих адаптеров поверх базовой модели. И после обучения вы сохраняете только адаптер, а не базовую модель. Итак, рабочий процесс следующий:
Во время обучения:
Во время вывода
Шаг 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, то если каждый раз, когда он загружает базовую модель, загрузка будет занимать много времени
Чтобы предотвратить повторную загрузку модели, вам необходимо установить каталог HF-кэша os.environ['HF_HOME']
. В этом случае базовая модель будет сохранена в заранее указанном каталоге и будет загружена при следующем вызове AutoModelForCausalLM.from_pretrained
Другой вариант — сохранить предварительно обученную (базовую) модель после ее загрузки и квантования: model.save_pretrained(base_quantized_path)
и tokenizer.save_pretrained(base_quantized_path)
Что касается вашего второго варианта, как мне сделать это локально, а затем загрузить модель в мою программу Streamlit, чтобы пользователю не приходилось ждать, пока модель загрузится?
Привет, Лидор, я не уверен, в чем именно проблема. Не могли бы вы поделиться полным кодом приложения Streamlit и отредактировать свой вопрос относительно проблемы. Обычно вы копируете пользователю приложение Streamlit и файлы модели. А потом при первом запуске Streamlit вы предварительно загружаете модель в одну из переменных.
Эй, да, я сделаю это сегодня вечером. а насчет того, что вы сказали, это правда, приложение Streamlit загружает модель и скачивает базовую. но это занимает много времени, поэтому мне было интересно, есть ли способ сохранить все на своем сервере с помощью приложения Streamlit, чтобы модель была доступна и ее не нужно было повторно загружать и перезагружать?
Например, возьмем ChatGPT, когда вы заходите в него, вы не ждете загрузки модели, она там и готова для вас, как только вы к ней зайдете.
Хорошо, тогда вопрос в том, как это сделать конкретно в Streamlit. Потому что подход различается в зависимости от фреймворков, которые вы используете. Я бы порекомендовал просмотреть эту статью: docs.streamlit.io/develop/concepts/architecture/caching И посмотреть пример загрузки моделей с помощью @st.cache_resource
.
Я пробовал использовать и @st.cache_resource
, и os.environ['HF_HOME']
на своем диске D, но он все равно каждый раз загружает его на мой диск C и вылетает из-за нехватки места.
Привет, Лидор, было бы очень полезно, если бы можно было предоставить точный код Streamlit, который вы используете. Спасибо.
Привет, после этого комментария я обновил свой ответ на то, что, по моему мнению, должно быть лучшим вариантом для сохранения/загрузки модели. Но опять же, если вы ответите о Streamlit, я бы порекомендовал опубликовать код, который вы используете, потому что Streamlit может потребовать использования некоторых специальных функций Stremlit для быстрого сохранения/загрузки моделей.
Я прочитал предоставленный вами код, и он кажется лучше: когда вы сохраняете базовую модель, а затем загружаете ее из каталога кеша, она не будет повторно загружаться и будет быстрее? (Джонни Чизкаттер). Что вы думаете об ответе? @ЛидорЭлиягуШелеф
Вам следует проверить несколько вещей: 1) HF повторно загружает контрольные точки модели из Интернета? (выключите Wi-Fi, чтобы проверить это, если вы не уверены); 2) HF загружает КПП модели из файлов или памяти? При первом вызове он должен загрузить модель из файла, а во второй раз его следует вызвать из памяти, иначе вы создадите дубликат объекта в памяти и тем самым также можете использовать дополнительную память графического процессора;
3) Перезагружает ли Streamlit модель из файла каждый раз, когда вы вызываете приложение (или когда два разных пользователя открывают приложение/когда вы открываете приложение в двух разных вкладках или браузерах) или использует общий объект из памяти? Streamlit построен таким образом, что для каждого пользователя он перезапускает все конвейеры с нуля. По сути,streamlit клонирует все, начиная с кода Python, для каждого пользователя.
Таким образом, по моему мнению, было бы полезно увидеть точный потоковый код, используемый для загрузки точно настроенной модели.
С какими ошибками вы столкнулись? Обычно он также должен кэшировать модель локально и загружать ее только один раз.