* LongRoPE

* Update _utils.py

* Update _utils.py

* Update _utils.py

* Update _utils.py

* Update llama.py

* Update llama.py

* Update llama.py

* Update llama.py

* Update llama.py

* Update mapper.py

* Phi 3.5
This commit is contained in:
Daniel Han 2024-08-20 16:51:39 -07:00 committed by GitHub
commit a93e3dea2a
6 changed files with 173 additions and 14 deletions

View file

@ -10,7 +10,7 @@
<a href="https://discord.gg/unsloth"><img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/Discord button.png" height="48"></a>
<a href="https://ko-fi.com/unsloth"><img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/buy me a coffee button.png" height="48"></a>
### Finetune Llama 3.1, Mistral, Phi-3 & Gemma 2-5x faster with 80% less memory!
### Finetune Llama 3.1, Mistral, Phi-3.5 & Gemma 2-5x faster with 80% less memory!
![](https://i.ibb.co/sJ7RhGG/image-41.png)

View file

@ -473,7 +473,7 @@ pass
# =========================================== Phi-3
phi3_template = \
"{{ bos_token }}"\
# "{{ bos_token }}"\ # Phi-3.5 removes BOS?
"{% for message in messages %}"\
"{% if message['role'] == 'user' %}"\
"{{'<|user|>\n' + message['content'] + '<|end|>\n'}}"\
@ -505,7 +505,9 @@ PARAMETER stop "<|assistant|>"
'''
phi3_template_eos_token = "<|end|>"
CHAT_TEMPLATES["phi-3"] = (phi3_template, phi3_template_eos_token, False, phi3_ollama,)
CHAT_TEMPLATES["phi-3"] = (phi3_template, phi3_template_eos_token, False, phi3_ollama,)
CHAT_TEMPLATES["phi-35"] = CHAT_TEMPLATES["phi-3"]
CHAT_TEMPLATES["phi-3.5"] = CHAT_TEMPLATES["phi-3"]
pass
# =========================================== Llama-3.1

View file

@ -969,6 +969,7 @@ def patch_llama_rope_scaling(
scaled_rope_module = None,
extended_rope_module = None,
attention_module = None,
longrope_module = None,
):
assert(\
rope_module is not None and \
@ -1026,14 +1027,26 @@ def patch_llama_rope_scaling(
max_position_embeddings=self.max_position_embeddings,
base=self.rope_theta,
)
elif scaling_type == "longrope":
self.rotary_emb = {longrope_rope_function}(
dim = self.head_dim,
max_position_embeddings = self.max_position_embeddings,
original_max_position_embeddings = self.config.original_max_position_embeddings,
base = self.rope_theta,
short_factor = self.config.rope_scaling['short_factor'],
long_factor = self.config.rope_scaling['long_factor' ],
)
else:
raise ValueError(f"Unknown RoPE scaling type {{scaling_type}}")
pass
"""
fix_rope_function = fix_rope_function.format(
rope_function = rope_module.__name__,
scaled_rope_function = scaled_rope_module.__name__,
extended_rope_function = extended_rope_module.__name__,
longrope_rope_function = \
(longrope_module if longrope_module is not None else rope_module).__name__
)
rotary_emb = re.findall(
"self.rotary_emb = .+?\)", function,

View file

@ -254,6 +254,10 @@ class GemmaFixedRotaryEmbedding(torch.nn.Module):
)
pass
def get_cached(self, seq_len = None):
return self.cos_cached, self.sin_cached
pass
def extend_rope_embedding(self, x, seq_len):
if seq_len <= self.current_rope_size: return
# Iteratively grow by increments of 8192

View file

@ -187,8 +187,9 @@ def LlamaAttention_fast_forward_inference(
# cos, sin = self.rotary_emb(Vn, seq_len = kv_seq_len)
# Qn, Kn = inplace_rope_embedding(Qn, Kn, cos, sin, position_ids)
cos = self.rotary_emb.cos_cached[position_ids].unsqueeze(1)
sin = self.rotary_emb.sin_cached[position_ids].unsqueeze(1)
cos, sin = self.rotary_emb.get_cached(kv_seq_len)
cos = cos[position_ids].unsqueeze(1)
sin = sin[position_ids].unsqueeze(1)
h = self.half_head_dim
RH_Q = self.RH_Q
@ -346,14 +347,17 @@ def LlamaAttention_fast_forward(
kv_seq_len += past_key_value[0].shape[-2]
# Extend RoPE dynamically to fit in VRAM
self.rotary_emb.extend_rope_embedding(V, seq_len = kv_seq_len)
rotary_emb = self.rotary_emb
rotary_emb.extend_rope_embedding(V, seq_len = kv_seq_len)
if position_ids is None:
cos = self.rotary_emb.cos_cached
sin = self.rotary_emb.sin_cached
# Useful for LongRoPE
cos, sin = rotary_emb.get_cached(kv_seq_len)
# cos = self.rotary_emb.cos_cached
# sin = self.rotary_emb.sin_cached
Q, K = fast_rope_embedding(Q, K, cos, sin)
else:
cos, sin = self.rotary_emb(V, seq_len = kv_seq_len)
cos, sin = rotary_emb(V, seq_len = kv_seq_len)
Q, K = inplace_rope_embedding(Q, K, cos, sin, position_ids)
pass
@ -1048,6 +1052,10 @@ class LlamaRotaryEmbedding(torch.nn.Module):
)
pass
def get_cached(self, seq_len = None):
return self.cos_cached, self.sin_cached
pass
def extend_rope_embedding(self, x, seq_len):
if seq_len <= self.current_rope_size: return
# Iteratively grow by increments of 8192
@ -1170,6 +1178,125 @@ class LlamaExtendedRotaryEmbedding(torch.nn.Module):
)
pass
def get_cached(self, seq_len = None):
return self.cos_cached, self.sin_cached
pass
def extend_rope_embedding(self, x, seq_len):
if seq_len <= self.current_rope_size: return
# Iteratively grow by increments of 8192
self.current_rope_size = math.ceil(seq_len / 8192) * 8192
self._set_cos_sin_cache(self.current_rope_size, device = "cuda:0", dtype = x.dtype)
pass
pass
class LongRopeRotaryEmbedding(torch.nn.Module):
# For Phi 3.5 128K https://huggingface.co/microsoft/Phi-3.5-mini-instruct/blob/main/modeling_phi3.py
def __init__(self,
dim = None,
max_position_embeddings = 131072,
original_max_position_embeddings = 4096,
base = 10000,
short_factor = None,
long_factor = None,
device = None,
config = None, # [TODO] Hack to pass in config - need to remove later
):
super().__init__()
assert(short_factor is not None)
assert(long_factor is not None)
assert(type(original_max_position_embeddings) is int)
if config is not None:
# [TODO] Hack to pass in config - need to remove later
base = config.rope_theta
partial_rotary_factor = config.partial_rotary_factor if hasattr(config, "partial_rotary_factor") else 1.0
dim = int((config.hidden_size // config.num_attention_heads))
device = "cuda"
max_position_embeddings = config.max_position_embeddings
pass
self.dim = dim
self.max_position_embeddings = max_position_embeddings
self.original_max_position_embeddings = original_max_position_embeddings
self.base = base
# Dynamic RoPE we first set it to a max of 4 * 8192 tokens then we iteratively grow this
self.current_rope_size = min(original_max_position_embeddings, self.max_position_embeddings)
# Long RoPE similar to RoPE except short sequences have 1 cos / sin
# and long sequences have another cos / sin
inv_freq_shape = torch.arange(0, self.dim, 2, dtype=torch.int64, device="cpu").float() / self.dim
short_factor = torch.tensor(short_factor, device = "cpu", dtype = torch.float32)
long_factor = torch.tensor(long_factor, device = "cpu", dtype = torch.float32)
short_inv_freq = 1.0 / (short_factor * self.base**inv_freq_shape)
long_inv_freq = 1.0 / (long_factor * self.base**inv_freq_shape)
# Phi-3 Scale factor
scale = self.max_position_embeddings / self.original_max_position_embeddings
if scale <= 1.0:
scaling_factor = 1.0
else:
scaling_factor = math.sqrt(1 + math.log(scale) / math.log(self.original_max_position_embeddings))
pass
self.scaling_factor = scaling_factor
# Short and long inv_freq
self.register_buffer("short_inv_freq", short_inv_freq, persistent = False)
self.register_buffer("long_inv_freq", long_inv_freq, persistent = False)
# Build here to make `torch.jit.trace` work.
# self._set_cos_sin_cache(seq_len=self.current_rope_size, device=device, dtype=torch.get_default_dtype())
# Short sequences
dtype = torch.bfloat16 if is_bfloat16_supported() else torch.float16
t = torch.arange(original_max_position_embeddings, device=self.short_inv_freq.device, dtype=torch.int64).float()
freqs = torch.outer(t, self.short_inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
cos_cached = (emb.cos() * self.scaling_factor).to(dtype=dtype, device=device, non_blocking=True)
sin_cached = (emb.sin() * self.scaling_factor).to(dtype=dtype, device=device, non_blocking=True)
self.register_buffer("short_cos_cached", cos_cached, persistent=False)
self.register_buffer("short_sin_cached", sin_cached, persistent=False)
pass
def _set_cos_sin_cache(self, seq_len, device, dtype):
# Note: on the original Llama codebase, these tensors are created on the target device (and not on CPU) and
# in FP32. They are applied (multiplied) in FP32 as well.
self.current_rope_size = seq_len
t = torch.arange(self.current_rope_size, device=self.inv_freq.device, dtype=torch.int64).float()
# Long sequences
freqs = torch.outer(t, self.long_inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
cos_cached = (emb.cos() * self.scaling_factor).to(dtype=dtype, device=device, non_blocking=True)
sin_cached = (emb.sin() * self.scaling_factor).to(dtype=dtype, device=device, non_blocking=True)
self.register_buffer("long_cos_cached", cos_cached, persistent=False)
self.register_buffer("long_sin_cached", sin_cached, persistent=False)
pass
def forward(self, x, position_ids=None, seq_len=None):
# x: [bs, num_attention_heads, seq_len, head_size]
if seq_len > self.current_rope_size:
self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype)
if seq_len < self.original_max_position_embeddings:
return (
self.short_cos_cached[:seq_len].to(dtype = x.dtype),
self.short_sin_cached[:seq_len].to(dtype = x.dtype),
)
else:
return (
self.long_cos_cached[:seq_len].to(dtype = x.dtype),
self.long_sin_cached[:seq_len].to(dtype = x.dtype),
)
pass
pass
def get_cached(self, seq_len = None):
if seq_len < self.original_max_position_embeddings:
return self.short_cos_cached, self.short_sin_cached
return self.long_cos_cached, self.long_sin_cached
pass
def extend_rope_embedding(self, x, seq_len):
if seq_len <= self.current_rope_size: return
# Iteratively grow by increments of 8192
@ -1242,6 +1369,7 @@ class FastLlamaModel:
scaled_rope_module = LlamaLinearScalingRotaryEmbedding,
extended_rope_module = LlamaExtendedRotaryEmbedding,
attention_module = LlamaAttention,
longrope_module = LongRopeRotaryEmbedding,
)
if init_name is not None:
exec(function, globals())
@ -1657,11 +1785,19 @@ class FastLlamaModel:
pass
pass
# Downcast RoPE embedding to correct data type
if (name.endswith("rotary_emb") or hasattr(module, "cos_cached")) \
and (module.cos_cached.dtype != correct_dtype):
module.cos_cached = module.cos_cached.to(correct_dtype)
module.sin_cached = module.sin_cached.to(correct_dtype)
if (name.endswith("rotary_emb") or hasattr(module, "cos_cached")):
if hasattr(module, "cos_cached") and \
(module.cos_cached.dtype != correct_dtype):
module.cos_cached = module.cos_cached.to(correct_dtype)
module.sin_cached = module.sin_cached.to(correct_dtype)
elif hasattr(module, "short_cos_cached") and \
(module.short_cos_cached.dtype != correct_dtype):
module.short_cos_cached = module.short_cos_cached.to(correct_dtype)
module.short_sin_cached = module.short_sin_cached.to(correct_dtype)
pass
pass
pass

View file

@ -249,6 +249,10 @@ __INT_TO_FLOAT_MAPPER = \
"unsloth/gemma-2-2b-it",
"google/gemma-2-2b-it",
),
"unsloth/Phi-3.5-mini-instruct-bnb-4bit" : (
"unsloth/Phi-3.5-mini-instruct",
"microsoft/Phi-3.5-mini-instruct",
),
}
INT_TO_FLOAT_MAPPER = {}