tinyllama-cinder-openhermes-32k / run-tiny-merge.py
matlok's picture
fixing newline char in logs/readme
17917cf
raw
history blame
6.98 kB
#!/usr/bin/env python3
import transformers
import torch
import logging
from ddare.merge import merge_tensors
from ddare.tensor import (
dare_ties_sparsification,
relative_norm,
divide_tensor_into_sets
)
from ddare.util import get_device
import re
from typing import Dict, Tuple, List
# If you want to fine-tune, here's an example Unsloth fine tuning guide for:
# Alpaca + TinyLlama + RoPE Scaling full example.ipynb
# https://colab.research.google.com/drive/1AZghoNBQaMDgWJpi4RbffGM1h6raLUj9?usp=sharing
# code here was refactored from gist:
# https://gist.github.com/maldevide/08829eada04ad9bd78e46c1a3787d42b
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
def get_models(
models: List[str],
trust_remote_code: bool,
):
config = {
'torch_dtype': torch.float16,
'low_cpu_mem_usage': False,
'trust_remote_code': trust_remote_code,
}
loaded_models = []
num_models = len(models)
for midx, model_path in enumerate(models):
log.info(
f"loading model={midx + 1}/{num_models} "
f"model={model_path} "
)
loaded_models.append(
transformers.AutoModelForCausalLM.from_pretrained(
model_path,
**config
)
)
return loaded_models
def pm(
model,
):
keys = model.state_dict().keys()
log.info(f"model keys={len(keys)}")
for i, k in enumerate(keys):
tensor = model.state_dict()[k]
log.info(
f"{i:3d} {k} shape={tensor.shape} "
f"type={tensor.dtype} dev={tensor.device} "
f"contig={tensor.is_contiguous()}")
def run_text_test(
model,
tokenizer_path,
question: str,
device: str = "cuda",
):
base_model = model.to(device)
log.info(
f"loading tokenizer={tokenizer_path}"
)
tokenizer = transformers.AutoTokenizer.from_pretrained(
tokenizer_path,
torch_dtype=torch.float16,
)
inputs = tokenizer(
question,
return_tensors="pt"
).to(device)
with torch.backends.cuda.sdp_kernel(
enable_flash=True,
enable_math=False,
enable_mem_efficient=False
):
outputs = base_model.generate(
**inputs,
max_new_tokens=1000,
)
answer = tokenizer.decode(outputs[0], skip_special_tokens=True)
log.info(
"\n"
"----------"
"\n"
f"tokenizer={tokenizer}\n "
f"question:\n{question}\n"
f"answer:\n{answer}\n"
"----------"
)
base_model = base_model.to(device)
def get_layer_type(
key: str
) -> Tuple[int, str]:
matcher = re.compile(r"model.layers.(\d+).(.+)")
m = matcher.match(key)
if m is None:
if "model.norm.weight" == key:
return -1, "norm"
if "model.embed_tokens.weight" == key:
return -1, "embed"
if "lm_head.weight" == key:
return -1, "head"
log.info(f"Unknown key {key}")
return -1, "unknown"
return int(m.group(1)), m.group(2)
def merge_model_with_ties(
models: List[str],
model_dst: str,
trust_remote_code: bool = True
):
models = get_models(
models=models,
trust_remote_code=trust_remote_code,
)
config = {}
result_dict: Dict[str, torch.Tensor] = {}
device = get_device()
keys = models[0].state_dict().keys()
num_keys = len(keys)
for k in keys:
block, layer_type = get_layer_type(k)
m0: torch.Tensor = models[0].state_dict()[k]
result = m0.clone()
sets = divide_tensor_into_sets(tensor=m0, n_sets=4)
# get the src layers to merge
m = [
models[1].state_dict()[k],
models[2].state_dict()[k],
models[3].state_dict()[k],
models[4].state_dict()[k],
]
# build a ratio
ratio = {
'to_q': 0.0,
'to_k': 0.0,
'to_v': 0.0,
}.get(layer_type, .5)
norm_ratio = 0.68
log.info(
f"model={k} {num_keys} shape={m0.shape} "
f"dtype={m0.dtype} {m0.device} "
f"raio={ratio} "
f"contig={m0.is_contiguous()} "
f"norm={norm_ratio}")
# for all tensors
for i, tensor in enumerate(m):
if layer_type == "to_k":
# Get to_q key
q_base = models[0].state_dict()[k.replace("to_k", "to_q")]
q_merge = models[i].state_dict()[k.replace("to_k", "to_q")]
scale = relative_norm(q_merge, q_base)
tensor = tensor.to(device) / scale
del scale
elif layer_type == "to_q":
scale = relative_norm(tensor, m0)
tensor = tensor.to(device) * scale
del scale
slice_mask = (
sets == i
).bool()
new_tensor = dare_ties_sparsification(
model_a_param=m0,
model_b_param=tensor,
drop_rate=norm_ratio,
ties="sum",
rescale="off",
device=device,
**config)
new_tensor = merge_tensors("slerp", m0, tensor, ratio)
result = torch.where(slice_mask, new_tensor, result)
del new_tensor, slice_mask
result_dict[k] = result
# end of merge
log.info(
f"done merge saving to file: {model_dst}"
)
out_model = (
transformers.AutoModelForCausalLM.from_pretrained(
model_dst,
**config
)
)
out_model.state_dict = lambda: result_dict
out_model.save_pretrained(model_dst)
def run():
question = (
"why is the sky blue?"
)
log.info(f"merging models and asking the question: {question}")
model_src = "TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T"
model_dst = "matlok/tinyllama-cinder-openhermes-32k"
device = "cuda"
config = {
'torch_dtype': torch.float16,
'low_cpu_mem_usage': False,
'trust_remote_code': True,
}
models = [
model_src,
"Doctor-Shotgun/TinyLlama-1.1B-32k-Instruct",
"Doctor-Shotgun/TinyLlama-1.1B-32k",
"Tensoic/TinyLlama-1.1B-3T-openhermes",
"Josephgflowers/TinyLlama-3T-Cinder-v1.3",
]
merge_model_with_ties(
models=models,
model_dst=model_dst
)
log.info(f"loading newly-created file: {model_dst}")
model = transformers.AutoModelForCausalLM.from_pretrained(
model_dst,
**config
)
log.info(
f"loaded new model file: {model_dst} "
f"asking question: {question} "
)
run_text_test(
model=model,
tokenizer_path=model_src,
question=question,
device=device,
)
log.info(f"done loading new model: {model} file: {model_dst}")
if __name__ == "__main__":
run()