Compare commits
5 Commits
embeddingfix
...
llama2
| Author | SHA1 | Date | |
|---|---|---|---|
| b0d2fe0dc2 | |||
| 68ff19681f | |||
| 4a3e5ddc0f | |||
| 61dfbe287e | |||
| 190d22aa4b |
@@ -7,9 +7,12 @@
|
||||
This repo supports the paper "QLoRA: Efficient Finetuning of Quantized LLMs", an effort to democratize access to LLM research.
|
||||
|
||||
|
||||
|
||||
QLoRA uses [bitsandbytes](https://github.com/TimDettmers/bitsandbytes) for quantization and is integrated with Hugging Face's [PEFT](https://github.com/huggingface/peft) and [transformers](https://github.com/huggingface/transformers/) libraries. QLoRA was developed by members of the [University of Washington's UW NLP group](https://twitter.com/uwnlp?s=20).
|
||||
|
||||
## Updates
|
||||
- 7/19/2023 - Added LLaMA 2 example script and updated version requirements
|
||||
- 7/18/2023 - Fixed non-frozen embeddings when adding new tokens
|
||||
|
||||
## Overview
|
||||
|
||||
We present QLoRA, an efficient finetuning approach that reduces memory usage enough to finetune a 65B parameter model on a single 48GB GPU while preserving full 16-bit finetuning task performance. QLoRA backpropagates gradients through a frozen, 4-bit quantized pretrained language model into Low Rank Adapters (LoRA). Our best model family, which we name Guanaco, outperforms all previous openly released models on the Vicuna benchmark, reaching 99.3% of the performance level of ChatGPT while only requiring 24 hours of finetuning on a single GPU. QLoRA introduces a number of innovations to save memory without sacrificing performance: (a) 4-bit NormalFloat (NF4), a new data type that is information theoretically optimal for normally distributed weights (b) Double Quantization to reduce the average memory footprint by quantizing the quantization constants, and (c) Paged Optimizers to manage memory spikes. We use QLoRA to finetune more than 1,000 models, providing a detailed analysis of instruction following and chatbot performance across 8 instruction datasets, multiple model types (LLaMA, T5), and model scales that would be infeasible to run with regular finetuning (e.g. 33B and 65B parameter models). Our results show that QLoRA finetuning on a small high-quality dataset leads to state-of-the-art results, even when using smaller models than the previous SoTA. We provide a detailed analysis of chatbot performance based on both human and GPT-4 evaluations showing that GPT-4 evaluations are a cheap and reasonable alternative to human evaluation. Furthermore, we find that current chatbot benchmarks are not trustworthy to accurately evaluate the performance levels of chatbots. We release all of our models and code, including CUDA kernels for 4-bit training.
|
||||
@@ -29,9 +32,8 @@ Guanaco is a system purely intended for research purposes and could produce prob
|
||||
You can access [the model response Colab here](https://colab.research.google.com/drive/1kK6xasHiav9nhiRUJjPMZb4fAED4qRHb?usp=sharing) comparing ChatGPT and Guanaco 65B on Vicuna prompts.
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
To load models in 4bits with transformers and bitsandbytes, you have to install accelerate and transformers from source and make sure you have the latest version of the bitsandbytes library (0.39.0). After installing PyTorch (follow instructions [here](https://pytorch.org/get-started/locally/)), you can achieve the above with the following command:
|
||||
To load models in 4bits with transformers and bitsandbytes, you have to install accelerate and transformers from source and make sure you have the latest version of the bitsandbytes library. After installing PyTorch (follow instructions [here](https://pytorch.org/get-started/locally/)), you can achieve the above with the following command:
|
||||
```bash
|
||||
pip install -U -r requirements.txt
|
||||
```
|
||||
|
||||
@@ -309,6 +309,35 @@ def get_accelerate_model(args, checkpoint_dir):
|
||||
|
||||
model.config.torch_dtype=(torch.float32 if args.fp16 else (torch.bfloat16 if args.bf16 else torch.float32))
|
||||
|
||||
# Tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
args.model_name_or_path,
|
||||
cache_dir=args.cache_dir,
|
||||
padding_side="right",
|
||||
use_fast=False, # Fast tokenizer giving issues.
|
||||
tokenizer_type='llama' if 'llama' in args.model_name_or_path else None, # Needed for HF name change
|
||||
use_auth_token=args.use_auth_token,
|
||||
)
|
||||
if tokenizer._pad_token is None:
|
||||
smart_tokenizer_and_embedding_resize(
|
||||
special_tokens_dict=dict(pad_token=DEFAULT_PAD_TOKEN),
|
||||
tokenizer=tokenizer,
|
||||
model=model,
|
||||
)
|
||||
if 'llama' in args.model_name_or_path or isinstance(tokenizer, LlamaTokenizer):
|
||||
# LLaMA tokenizer may not have correct special tokens set.
|
||||
# Check and add them if missing to prevent them from being parsed into different tokens.
|
||||
# Note that these are present in the vocabulary.
|
||||
# Note also that `model.config.pad_token_id` is 0 which corresponds to `<unk>` token.
|
||||
print('Adding special tokens.')
|
||||
tokenizer.add_special_tokens({
|
||||
"eos_token": tokenizer.convert_ids_to_tokens(model.config.eos_token_id),
|
||||
"bos_token": tokenizer.convert_ids_to_tokens(model.config.bos_token_id),
|
||||
"unk_token": tokenizer.convert_ids_to_tokens(
|
||||
model.config.pad_token_id if model.config.pad_token_id != -1 else tokenizer.pad_token_id
|
||||
),
|
||||
})
|
||||
|
||||
if not args.full_finetune:
|
||||
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=args.gradient_checkpointing)
|
||||
|
||||
@@ -339,7 +368,7 @@ def get_accelerate_model(args, checkpoint_dir):
|
||||
if hasattr(module, 'weight'):
|
||||
if args.bf16 and module.weight.dtype == torch.float32:
|
||||
module = module.to(torch.bfloat16)
|
||||
return model
|
||||
return model, tokenizer
|
||||
|
||||
def print_trainable_parameters(args, model):
|
||||
"""
|
||||
@@ -369,33 +398,16 @@ def smart_tokenizer_and_embedding_resize(
|
||||
"""
|
||||
num_new_tokens = tokenizer.add_special_tokens(special_tokens_dict)
|
||||
model.resize_token_embeddings(len(tokenizer))
|
||||
|
||||
input_embeddings = model.get_input_embeddings()
|
||||
output_embeddings = model.get_output_embeddings()
|
||||
|
||||
if num_new_tokens > 0:
|
||||
input_embeddings_data = input_embeddings.weight.data
|
||||
output_embeddings_data = output_embeddings.weight.data
|
||||
input_embeddings_data = model.get_input_embeddings().weight.data
|
||||
output_embeddings_data = model.get_output_embeddings().weight.data
|
||||
|
||||
input_embeddings_avg = input_embeddings_data[:-num_new_tokens].mean(dim=0, keepdim=True)
|
||||
output_embeddings_avg = output_embeddings_data[:-num_new_tokens].mean(dim=0, keepdim=True)
|
||||
|
||||
input_embeddings_data[-num_new_tokens:] = input_embeddings_avg
|
||||
output_embeddings_data[-num_new_tokens:] = output_embeddings_avg
|
||||
model.tie_weights()
|
||||
|
||||
# Temporary bug fix #214:
|
||||
# freeze embeddings otherwise need to store them with checkpoint
|
||||
input_embeddings.weight.requires_grad = False
|
||||
output_embeddings.weight.requires_grad = False
|
||||
# re-register forward hook
|
||||
if hasattr(model, "enable_input_require_grads"):
|
||||
model.enable_input_require_grads()
|
||||
else:
|
||||
|
||||
def make_inputs_require_grad(module, input, output):
|
||||
output.requires_grad_(True)
|
||||
|
||||
model.get_input_embeddings().register_forward_hook(make_inputs_require_grad)
|
||||
|
||||
@dataclass
|
||||
class DataCollatorForCausalLM(object):
|
||||
@@ -656,41 +668,14 @@ def train():
|
||||
if completed_training:
|
||||
print('Detected that training was already completed!')
|
||||
|
||||
model = get_accelerate_model(args, checkpoint_dir)
|
||||
model, tokenizer = get_accelerate_model(args, checkpoint_dir)
|
||||
|
||||
model.config.use_cache = False
|
||||
print('loaded model')
|
||||
set_seed(args.seed)
|
||||
|
||||
# Tokenizer
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
args.model_name_or_path,
|
||||
cache_dir=args.cache_dir,
|
||||
padding_side="right",
|
||||
use_fast=False, # Fast tokenizer giving issues.
|
||||
tokenizer_type='llama' if 'llama' in args.model_name_or_path else None, # Needed for HF name change
|
||||
use_auth_token=args.use_auth_token,
|
||||
)
|
||||
if tokenizer._pad_token is None:
|
||||
smart_tokenizer_and_embedding_resize(
|
||||
special_tokens_dict=dict(pad_token=DEFAULT_PAD_TOKEN),
|
||||
tokenizer=tokenizer,
|
||||
model=model,
|
||||
)
|
||||
if 'llama' in args.model_name_or_path or isinstance(tokenizer, LlamaTokenizer):
|
||||
# LLaMA tokenizer may not have correct special tokens set.
|
||||
# Check and add them if missing to prevent them from being parsed into different tokens.
|
||||
# Note that these are present in the vocabulary.
|
||||
# Note also that `model.config.pad_token_id` is 0 which corresponds to `<unk>` token.
|
||||
print('Adding special tokens.')
|
||||
tokenizer.add_special_tokens({
|
||||
"eos_token": tokenizer.convert_ids_to_tokens(model.config.eos_token_id),
|
||||
"bos_token": tokenizer.convert_ids_to_tokens(model.config.bos_token_id),
|
||||
"unk_token": tokenizer.convert_ids_to_tokens(
|
||||
model.config.pad_token_id if model.config.pad_token_id != -1 else tokenizer.pad_token_id
|
||||
),
|
||||
})
|
||||
data_module = make_data_module(tokenizer=tokenizer, args=args)
|
||||
|
||||
trainer = Seq2SeqTrainer(
|
||||
model=model,
|
||||
tokenizer=tokenizer,
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
bitsandbytes==0.39.0
|
||||
transformers @ git+https://github.com/huggingface/transformers.git
|
||||
peft @ git+https://github.com/huggingface/peft.git
|
||||
accelerate @ git+https://github.com/huggingface/accelerate.git
|
||||
bitsandbytes==0.40.0
|
||||
transformers==4.31.0
|
||||
peft==0.4.0
|
||||
accelerate==0.21.0
|
||||
einops==0.6.1
|
||||
evaluate==0.4.0
|
||||
scikit-learn==1.2.2
|
||||
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
python qlora.py \
|
||||
--model_name_or_path meta-llama/Llama-2-7b-hf \
|
||||
--use_auth \
|
||||
--output_dir ./output/llama-2-guanaco-7b \
|
||||
--logging_steps 10 \
|
||||
--save_strategy steps \
|
||||
--data_seed 42 \
|
||||
--save_steps 500 \
|
||||
--save_total_limit 40 \
|
||||
--evaluation_strategy steps \
|
||||
--eval_dataset_size 1024 \
|
||||
--max_eval_samples 1000 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--max_new_tokens 32 \
|
||||
--dataloader_num_workers 1 \
|
||||
--group_by_length \
|
||||
--logging_strategy steps \
|
||||
--remove_unused_columns False \
|
||||
--do_train \
|
||||
--do_eval \
|
||||
--do_mmlu_eval \
|
||||
--lora_r 64 \
|
||||
--lora_alpha 16 \
|
||||
--lora_modules all \
|
||||
--double_quant \
|
||||
--quant_type nf4 \
|
||||
--bf16 \
|
||||
--bits 4 \
|
||||
--warmup_ratio 0.03 \
|
||||
--lr_scheduler_type constant \
|
||||
--gradient_checkpointing \
|
||||
--dataset oasst1 \
|
||||
--source_max_len 16 \
|
||||
--target_max_len 512 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--max_steps 1875 \
|
||||
--eval_steps 187 \
|
||||
--learning_rate 0.0002 \
|
||||
--adam_beta2 0.999 \
|
||||
--max_grad_norm 0.3 \
|
||||
--lora_dropout 0.1 \
|
||||
--weight_decay 0.0 \
|
||||
--seed 0 \
|
||||
Reference in New Issue
Block a user