Fix llama-3 (#423)

* Fix prompt

* Update chat_templates.py

* fix_untrained_tokens

* Update llama.py

* add tokens

* Update _utils.py

* Update tokenizer_utils.py

* Update llama.py

* Update llama.py

* Update llama.py

* Update llama.py

* pad_token

* Update chat_templates.py

* Update chat_templates.py

* tokenizer

* Update save.py

* Update chat_templates.py

* Update chat_templates.py

* patch tokenizer padding

* Update tokenizer_utils.py

* Update save.py

* Fix: loading models with resized vocabulary (#377)

* new: vocab resize on load

* new: gitignore

* GGUF fix

* Readme (#390)

* Update README.md

* Update README.md

---------

Co-authored-by: Michael Han <107991372+shimmyshimmer@users.noreply.github.com>

* Update README.md

* Delete .gitignore

* Phi-3

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Fix reserved tokens

* Update save.py

* Update tokenizer_utils.py

* Update tokenizer_utils.py

* Update tokenizer_utils.py

* Update tokenizer_utils.py

* Update tokenizer_utils.py

---------

Co-authored-by: Igor Kilbas <whitemarsstudios@gmail.com>
Co-authored-by: Michael Han <107991372+shimmyshimmer@users.noreply.github.com>
This commit is contained in:
Daniel Han 2024-05-05 05:45:01 +10:00 committed by GitHub
commit 4a802a4bb1
3 changed files with 119 additions and 16 deletions

View file

@ -1503,10 +1503,16 @@ class FastLlamaModel:
pass
pass
# Check for Llama-3
# if hasattr(model._saved_temp_tokenizer, "_using_llama3_template"):
# if not train_embed_tokens and not train_lm_head:
# raise RuntimeError("")
# First fix untrained tokens
if train_embed_tokens or train_lm_head:
fix_untrained_tokens(model, eps = 1e-16)
pass
# Wrong - can cause reserved tokens to pop out!!
# if train_embed_tokens or train_lm_head:
# fix_untrained_tokens(model, eps = 1e-16)
# pass
# Check modules_to_save
if modules_to_save is not None:
@ -1547,7 +1553,7 @@ class FastLlamaModel:
lora_config = LoraConfig(**arguments)
model = _get_peft_model(model, lora_config)
model._saved_temp_tokenizer = _saved_temp_tokenizer
model = FastLlamaModel.patch_peft_model(model, use_gradient_checkpointing)

View file

@ -118,14 +118,14 @@ def _merge_lora(layer, name):
W = fast_dequantize(W, quant_state)
else:
dtype = W.dtype
# W = W.to(torch.float32).t()
W = W.t()
W = W.to(torch.float32).t()
# W = W.t()
if A is not None:
# sAB = (A.t().to(torch.float32) @ (s * B.t().to(torch.float32)))
# W += sAB
# W.addmm_(A.t().to(torch.float32), B.t().to(torch.float32), alpha = s)
W.addmm_(A.t().to(W.dtype), B.t().to(W.dtype), alpha = s)
W.addmm_(A.t().to(torch.float32), B.t().to(torch.float32), alpha = s)
# W.addmm_(A.t().to(W.dtype), B.t().to(W.dtype), alpha = s)
# if not torch.isfinite(W).all():
maximum_element = torch.max(W.min().abs(), W.max())
if not torch.isfinite(maximum_element).item():
@ -696,12 +696,18 @@ pass
def install_llama_cpp_make_non_blocking():
env = { **os.environ, "LLAMA_CUDA": "1", }
# https://github.com/ggerganov/llama.cpp/issues/7062
# Weirdly GPU conversion for GGUF breaks??
# env = { **os.environ, "LLAMA_CUDA": "1", }
n_jobs = max(int(psutil.cpu_count()*1.5), 1)
# Force make clean
os.system("make clean -C llama.cpp")
full_command = ["make", "all", "-j"+str(n_jobs), "-C", "llama.cpp"]
run_installer = subprocess.Popen(full_command, env = env, stdout = subprocess.DEVNULL, stderr = subprocess.STDOUT)
# https://github.com/ggerganov/llama.cpp/issues/7062
# Weirdly GPU conversion for GGUF breaks??
# run_installer = subprocess.Popen(full_command, env = env, stdout = subprocess.DEVNULL, stderr = subprocess.STDOUT)
run_installer = subprocess.Popen(full_command, stdout = subprocess.DEVNULL, stderr = subprocess.STDOUT)
return run_installer
pass
@ -764,12 +770,17 @@ pass
def install_llama_cpp_blocking(use_cuda = True):
use_cuda = "LLAMA_CUDA=1" if use_cuda else ""
# https://github.com/ggerganov/llama.cpp/issues/7062
# Weirdly GPU conversion for GGUF breaks??
# use_cuda = "LLAMA_CUDA=1" if use_cuda else ""
commands = [
"git clone --recursive https://github.com/ggerganov/llama.cpp",
"make clean -C llama.cpp",
f"{use_cuda} make all -j{psutil.cpu_count()*2} -C llama.cpp",
# https://github.com/ggerganov/llama.cpp/issues/7062
# Weirdly GPU conversion for GGUF breaks??
# f"{use_cuda} make all -j{psutil.cpu_count()*2} -C llama.cpp",
f"make all -j{psutil.cpu_count()*2} -C llama.cpp",
"pip install gguf protobuf",
]
if os.path.exists("llama.cpp"): return
@ -833,6 +844,12 @@ def save_to_gguf(
first_conversion : str = "f16",
_run_installer = None, # Non blocking install of llama.cpp
):
logger.warning(
"WARNING: llama.cpp GGUF conversion is currently unstable, since llama.cpp is\n"\
"undergoing some major bug fixes as at 5th of May 2024. This is not an Unsloth issue.\n"\
"Please be patient - GGUF saving should still work, but might not work as well."
)
from transformers.models.llama.modeling_llama import logger
if quantization_method.startswith("iq2"):
@ -967,7 +984,7 @@ def save_to_gguf(
"You do not need to close this Python program. Run the following commands in a new terminal:\n"\
"You must run this in the same folder as you're saving your model.\n"\
"git clone --recursive https://github.com/ggerganov/llama.cpp\n"\
"cd llama.cpp && make clean && LLAMA_CUDA=1 make all -j\n"\
"cd llama.cpp && make clean && make all -j\n"\
"Once that's done, redo the quantization."
)
pass
@ -1007,7 +1024,7 @@ def save_to_gguf(
"You do not need to close this Python program. Run the following commands in a new terminal:\n"\
"You must run this in the same folder as you're saving your model.\n"\
"git clone --recursive https://github.com/ggerganov/llama.cpp\n"\
"cd llama.cpp && make clean && LLAMA_CUDA=1 make all -j\n"\
"cd llama.cpp && make clean && make all -j\n"\
"Once that's done, redo the quantization."
)
pass

View file

@ -25,7 +25,6 @@ __all__ = [
"load_correct_tokenizer",
"fix_sentencepiece_tokenizer",
"check_tokenizer",
"fix_untrained_tokens",
"add_new_tokens",
]
@ -518,6 +517,44 @@ def fix_untrained_tokens(model, eps = 1e-16):
pass
@torch.inference_mode
def mean_of_trained_tokens(model, eps = 1e-16):
"""
Llama-3 for eg has untrained vectors in the base model.
These include <|eot_id|>, <|start_header_id|>, <|end_header_id|>
We reset them to the mean of the rest of the tokens
"""
embedding_matrix = model.get_input_embeddings ().weight.data.clone()
lm_head_matrix = model.get_output_embeddings().weight.data.clone()
# Get untrained tokens
indicator_untrained = torch.amax(embedding_matrix, axis = 1) <= eps
where_untrained = torch.where(indicator_untrained)[0]
n_untrained = where_untrained.shape[0]
n_trained = embedding_matrix.shape[0] - n_untrained
if n_untrained != 0:
print(
f"Unsloth: Not an error, but your model has {n_untrained} untrained tokens.\n"\
"We shall set them to the mean of the other trained tokens."
)
pass
# First set untrained to all 0s - sometimes it's not! 1e-23 for bfloat16
embedding_matrix[where_untrained] = 0
lm_head_matrix [where_untrained] = 0
# Find sum
sum_embedding = torch.sum(embedding_matrix, dtype = torch.float32, axis = 0)
sum_lm_head = torch.sum(lm_head_matrix, dtype = torch.float32, axis = 0)
# Find correct average by dividing by sum of trained tokens
mean_embedding = (sum_embedding / n_trained).to(embedding_matrix.dtype)
mean_lm_head = (sum_lm_head / n_trained).to(lm_head_matrix .dtype)
return mean_embedding, mean_lm_head
pass
@torch.inference_mode
def add_new_tokens(
model,
@ -547,7 +584,10 @@ def add_new_tokens(
pass
# Get mean of trained tokens
mean_embedding, mean_lm_head = fix_untrained_tokens(model)
# mean_embedding, mean_lm_head = fix_untrained_tokens(model)
# Weirdly be careful reserved tokens can pop out
mean_embedding, mean_lm_head = mean_of_trained_tokens(model)
mean_embedding = mean_embedding.to(torch.float32)
mean_lm_head = mean_lm_head .to(torch.float32)
@ -595,3 +635,43 @@ def add_new_tokens(
return
pass
from inspect import getsource
import trl.trainer.sft_trainer
from trl.trainer.sft_trainer import *
def fix_sft_trainer_tokenizer():
"""
Fixes double adding BOS tokens like in llama-3
"""
for function_name, replacer in (
("_prepare_non_packed_dataloader", "def tokenize(element):",),
# ("_prepare_packed_dataloader", "if dataset_text_field is not None",),
):
function = getsource(eval(f"trl.trainer.sft_trainer.SFTTrainer.{function_name}"))
where = function.find("def")
function = function.split("\n")
function = "\n".join(x[where:] for x in function)
check_text = \
"\n"\
"test_text = dataset[0][dataset_text_field] if (formatting_func is None or not use_formatting_func) else formatting_func(dataset[0])\n"\
"chat_template = getattr(tokenizer, 'chat_template', None)\n"\
"chat_template = '' if chat_template is None else chat_template\n"\
"has_bos_token_already = test_text.startswith(tokenizer.bos_token) or tokenizer.bos_token in chat_template\n"\
"add_special_tokens = False if has_bos_token_already else add_special_tokens\n\n"
check_text = check_text.split("\n")
check_text = "\n".join(" "*where + x for x in check_text)
function = function.replace(replacer, check_text + replacer)
exec(function, globals())
# Replace TRL's SFTTrainer
exec(f"trl.trainer.sft_trainer.SFTTrainer.{function_name} = {function_name}", globals())
pass
pass
# Fixes double adding BOS tokens like in llama-3
fix_sft_trainer_tokenizer()