Jeethu commited on
Commit
3fa47da
·
verified ·
1 Parent(s): 6235614

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1,6 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
 
2
  *.bin filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  *.pt filter=lfs diff=lfs merge=lfs -text
4
  *.pth filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.gguf filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
README.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ library_name: transformers
5
+ pipeline_tag: text-generation
6
+ license: apache-2.0
7
+ tags:
8
+ - lizzy-7b
9
+ - flwrlabs
10
+ - british-english
11
+ - text-generation
12
+ model_name: Lizzy 7B
13
+ base_model:
14
+ - flwrlabs/Lizzy-7B
15
+ base_model_relation: quantized
16
+ ---
17
+
18
+ # Jeethu/Lizzy-7B-PARO
19
+
20
+ **Pairwise Rotation Quantization for Efficient Reasoning LLM Inference**
21
+
22
+ <p>
23
+ <a href="https://arxiv.org/abs/2511.10645"><img src="https://img.shields.io/badge/arXiv-2511.10645-b31b1b.svg" alt="Paper"></a>
24
+ <a href="https://paroquant.z-lab.ai"><img src="https://img.shields.io/badge/Blog-ParoQuant-blue" alt="Blog"></a>
25
+ <a href="https://huggingface.co/collections/z-lab/paroquant"><img src="https://img.shields.io/badge/%F0%9F%A4%97-Models-yellow" alt="Models"></a>
26
+ <a href="https://pypi.org/project/paroquant/"><img src="https://img.shields.io/pypi/v/paroquant" alt="PyPI"></a>
27
+ </p>
28
+
29
+ ParoQuant is the state-of-the-art INT4 quantization for LLMs. It closes the accuracy gap with FP16 while running at near-AWQ speed. Supports NVIDIA GPUs (vLLM, Transformers) and Apple Silicon (MLX). For more information, see https://github.com/z-lab/paroquant.
30
+
31
+ Jeethu/Lizzy-7B-PARO is a 4-bit [flwrlabs/Lizzy-7B](https://huggingface.co/flwrlabs/Lizzy-7B) quantized with ParoQuant.
32
+
chat_template.jinja ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ \
2
+ {# ───── defaults ───── #}
3
+ {%- if enable_thinking is not defined -%}
4
+ {%- set enable_thinking = true -%}
5
+ {%- endif -%}
6
+ {%- set system_message = "" -%}
7
+ {%- set custom_instructions = "" -%}
8
+ {%- set identity_preamble = "You are Lizzy, a helpful British AI assistant built by Flower Labs. When asked about your identity, name, developer, or origin, answer consistently: your name is Lizzy, you were built by Flower Labs, and you are not ChatGPT, DeepSeek, Claude, Gemini, or any other assistant. Do not misattribute your creator or model family." -%}
9
+ {%- set default_think_instructions = "You are a helpful British function-calling AI assistant. You are a British persona and your date cutoff is November 2024, and your model weights are available at https://huggingface.co/flwrlabs. Your role as an assistant involves thoroughly exploring questions through a systematic thinking process before providing the final precise and accurate solutions. This requires engaging in a comprehensive cycle of analysis, summarizing, exploration, reassessment, reflection, backtracking, and iteration to develop well-considered thinking process. Please structure your response into two main sections: Thought and Solution using the specified format: <tool_call> Thought section </tool_call> Solution section. In the Thought section, detail your reasoning process in steps. Each step should include detailed considerations such as analysing questions, summarizing relevant findings, brainstorming new ideas, verifying the accuracy of the current steps, refining any errors, and revisiting previous steps. In the Solution section, based on various attempts, explorations, and reflections from the Thought section, systematically present the final solution that you deem correct. The Solution section should be logical, accurate, and concise and detail necessary steps needed to reach the conclusion." -%}
10
+ {%- set default_no_think_instructions = "You are a helpful British function-calling AI assistant. You are a British persona and your date cutoff is November 2024, and your model weights are available at https://huggingface.co/flwrlabs." -%}
11
+
12
+ {# ───── reasoning mode ───── #}
13
+ {%- if enable_thinking -%}
14
+ {%- set reasoning_mode = "/think" -%}
15
+ {%- else -%}
16
+ {%- set reasoning_mode = "/no_think" -%}
17
+ {%- endif -%}
18
+
19
+ {# ───── header (system message) ───── #}
20
+ {{- "<|im_start|>system\n" -}}
21
+
22
+ {%- if messages[0].role == "system" -%}
23
+ {%- set system_message = messages[0].content -%}
24
+ {%- if "/no_think" in system_message -%}
25
+ {%- set reasoning_mode = "/no_think" -%}
26
+ {%- elif "/think" in system_message -%}
27
+ {%- set reasoning_mode = "/think" -%}
28
+ {%- endif -%}
29
+ {%- set custom_instructions = system_message.replace("/no_think", "").replace("/think", "").rstrip() -%}
30
+ {%- endif -%}
31
+
32
+ {%- if "/system_override" in system_message -%}
33
+ {{- identity_preamble + "\n\n" -}}
34
+ {{- custom_instructions.replace("/system_override", "").rstrip() -}}
35
+ {{- "<|im_end|>\n" -}}
36
+ {%- else -%}
37
+ {{- "## Metadata\n\n" -}}
38
+ {{- "Knowledge Cutoff Date: June 2025\n" -}}
39
+ {%- set today = strftime_now("%d %B %Y") -%}
40
+ {{- "Today Date: " ~ today ~ "\n" -}}
41
+ {{- "Reasoning Mode: " + reasoning_mode + "\n\n" -}}
42
+
43
+ {{- "## Identity\n\n" -}}
44
+ {{- identity_preamble + "\n\n" -}}
45
+
46
+ {{- "## Custom Instructions\n\n" -}}
47
+ {%- if custom_instructions -%}
48
+ {{- custom_instructions + "\n\n" -}}
49
+ {%- elif reasoning_mode == "/think" -%}
50
+ {{- default_think_instructions + "\n\n" -}}
51
+ {%- else -%}
52
+ {{- default_no_think_instructions + "\n\n" -}}
53
+ {%- endif -%}
54
+
55
+ {%- if xml_tools or python_tools or tools -%}
56
+ {{- "### Tools\n\n" -}}
57
+ {%- if xml_tools or tools -%}
58
+ {%- if tools -%}
59
+ {%- set xml_tools = tools -%}
60
+ {%- endif -%}
61
+ {%- set ns = namespace(xml_tool_string="You may call one or more functions to assist with the user query.\nYou are provided with function signatures within <tools></tools> XML tags:\n\n<tools>\n") -%}
62
+ {%- for tool in xml_tools[:] -%} {# The slicing makes sure that xml_tools is a list #}
63
+ {%- set ns.xml_tool_string = ns.xml_tool_string ~ (tool | string) ~ "\n" -%}
64
+ {%- endfor -%}
65
+ {%- set xml_tool_string = ns.xml_tool_string + "</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call>" -%}
66
+ {{- xml_tool_string -}}
67
+ {%- endif -%}
68
+ {%- if python_tools -%}
69
+ {%- set ns = namespace(python_tool_string="When you send a message containing Python code between '<code>' and '</code>' tags, it will be executed in a stateful Jupyter notebook environment, and you will then be given the output to continued reasoning in an agentic loop.\n\nYou can use the following tools in your python code like regular functions:\n<tools>\n") -%}
70
+ {%- for tool in python_tools[:] -%} {# The slicing makes sure that python_tools is a list #}
71
+ {%- set ns.python_tool_string = ns.python_tool_string ~ (tool | string) ~ "\n" -%}
72
+ {%- endfor -%}
73
+ {%- set python_tool_string = ns.python_tool_string + "</tools>\n\nThe state persists between code executions: so variables that you define in one step are still available thereafter." -%}
74
+ {{- python_tool_string -}}
75
+ {%- endif -%}
76
+ {{- "\n\n" -}}
77
+ {{- "<|im_end|>\n" -}}
78
+ {%- endif -%}
79
+ {%- endif -%}
80
+ {# ───── main loop ───── #}
81
+ {%- for message in messages -%}
82
+ {%- set content = message.content if message.content is string else "" -%}
83
+ {%- if message.role == "user" -%}
84
+ {{ "<|im_start|>" + message.role + "\n" + content + "<|im_end|>\n" }}
85
+ {%- elif message.role == "assistant" -%}
86
+ {% generation %}
87
+ {%- if reasoning_mode == "/think" -%}
88
+ {{ "<|im_start|>assistant\n" + content.lstrip("\n") + "<|im_end|>\n" }}
89
+ {%- else -%}
90
+ {{ "<|im_start|>assistant\n" + "<think>\n\n</think>\n" + content.lstrip("\n") + "<|im_end|>\n" }}
91
+ {%- endif -%}
92
+ {% endgeneration %}
93
+ {%- elif message.role == "tool" -%}
94
+ {{ "<|im_start|>" + "user\n" + content + "<|im_end|>\n" }}
95
+ {%- endif -%}
96
+ {%- endfor -%}
97
+ {# ───── generation prompt ───── #}
98
+ {%- if add_generation_prompt -%}
99
+ {%- if reasoning_mode == "/think" -%}
100
+ {{ "<|im_start|>assistant\n" }}
101
+ {%- else -%}
102
+ {{ "<|im_start|>assistant\n" + "<think>\n\n</think>\n" }}
103
+ {%- endif -%}
104
+ {%- endif -%}
config.json ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vocab_size": 100278,
3
+ "hidden_size": 4096,
4
+ "intermediate_size": 11008,
5
+ "num_hidden_layers": 32,
6
+ "num_attention_heads": 32,
7
+ "num_key_value_heads": 32,
8
+ "max_position_embeddings": 65536,
9
+ "head_dim": 128,
10
+ "hidden_act": "silu",
11
+ "norm_type": "rmsnorm",
12
+ "norm_eps": 1e-06,
13
+ "norm_has_bias": false,
14
+ "use_pre_attn_norm": false,
15
+ "use_pre_mlp_norm": false,
16
+ "use_post_attn_norm": true,
17
+ "use_post_mlp_norm": true,
18
+ "mlp_type": "gated",
19
+ "attention_bias": false,
20
+ "mlp_bias": false,
21
+ "position_embedding_type": "rope",
22
+ "rope_theta": 500000,
23
+ "rope_scaling": {
24
+ "attention_factor": 1.2079441541679836,
25
+ "beta_fast": 32,
26
+ "beta_slow": 1,
27
+ "factor": 8.0,
28
+ "original_max_position_embeddings": 8192,
29
+ "rope_type": "yarn",
30
+ "rope_theta": 500000
31
+ },
32
+ "rope_layer_flags": [
33
+ true,
34
+ true,
35
+ true,
36
+ true,
37
+ true,
38
+ true,
39
+ true,
40
+ true,
41
+ true,
42
+ true,
43
+ true,
44
+ true,
45
+ true,
46
+ true,
47
+ true,
48
+ true,
49
+ true,
50
+ true,
51
+ true,
52
+ true,
53
+ true,
54
+ true,
55
+ true,
56
+ true,
57
+ true,
58
+ true,
59
+ true,
60
+ true,
61
+ true,
62
+ true,
63
+ true,
64
+ true
65
+ ],
66
+ "no_rope_layer_interval": null,
67
+ "rope_type_overrides": {},
68
+ "layer_types": [
69
+ "sliding_attention",
70
+ "sliding_attention",
71
+ "sliding_attention",
72
+ "full_attention",
73
+ "sliding_attention",
74
+ "sliding_attention",
75
+ "sliding_attention",
76
+ "full_attention",
77
+ "sliding_attention",
78
+ "sliding_attention",
79
+ "sliding_attention",
80
+ "full_attention",
81
+ "sliding_attention",
82
+ "sliding_attention",
83
+ "sliding_attention",
84
+ "full_attention",
85
+ "sliding_attention",
86
+ "sliding_attention",
87
+ "sliding_attention",
88
+ "full_attention",
89
+ "sliding_attention",
90
+ "sliding_attention",
91
+ "sliding_attention",
92
+ "full_attention",
93
+ "sliding_attention",
94
+ "sliding_attention",
95
+ "sliding_attention",
96
+ "full_attention",
97
+ "sliding_attention",
98
+ "sliding_attention",
99
+ "sliding_attention",
100
+ "full_attention"
101
+ ],
102
+ "layer_layouts": [
103
+ "decoder_postnorm",
104
+ "decoder_postnorm",
105
+ "decoder_postnorm",
106
+ "decoder_postnorm",
107
+ "decoder_postnorm",
108
+ "decoder_postnorm",
109
+ "decoder_postnorm",
110
+ "decoder_postnorm",
111
+ "decoder_postnorm",
112
+ "decoder_postnorm",
113
+ "decoder_postnorm",
114
+ "decoder_postnorm",
115
+ "decoder_postnorm",
116
+ "decoder_postnorm",
117
+ "decoder_postnorm",
118
+ "decoder_postnorm",
119
+ "decoder_postnorm",
120
+ "decoder_postnorm",
121
+ "decoder_postnorm",
122
+ "decoder_postnorm",
123
+ "decoder_postnorm",
124
+ "decoder_postnorm",
125
+ "decoder_postnorm",
126
+ "decoder_postnorm",
127
+ "decoder_postnorm",
128
+ "decoder_postnorm",
129
+ "decoder_postnorm",
130
+ "decoder_postnorm",
131
+ "decoder_postnorm",
132
+ "decoder_postnorm",
133
+ "decoder_postnorm",
134
+ "decoder_postnorm"
135
+ ],
136
+ "sliding_window": 4096,
137
+ "linear_num_key_heads": null,
138
+ "linear_num_value_heads": null,
139
+ "linear_key_head_dim": null,
140
+ "linear_value_head_dim": null,
141
+ "linear_a_log_min": null,
142
+ "linear_a_log_max": null,
143
+ "linear_dt_min": null,
144
+ "linear_dt_max": null,
145
+ "linear_dt_init_floor": null,
146
+ "linear_conv_kernel_dim": null,
147
+ "linear_allow_neg_eigval": null,
148
+ "use_qk_norm": true,
149
+ "qk_norm_type": "rmsnorm",
150
+ "attention_dropout": 0.0,
151
+ "resid_dropout": 0.0,
152
+ "embd_dropout": 0.0,
153
+ "initializer_range": 0.02,
154
+ "bos_token_id": 100257,
155
+ "eos_token_id": 100257,
156
+ "pad_token_id": 100277,
157
+ "use_cache": true,
158
+ "tie_word_embeddings": false,
159
+ "model_type": "lizzy",
160
+ "architectures": [
161
+ "LizzyForCausalLM"
162
+ ],
163
+ "auto_map": {
164
+ "AutoConfig": "configuration_lizzy.LizzyConfig",
165
+ "AutoModel": "modeling_lizzy.LizzyModel",
166
+ "AutoModelForCausalLM": "modeling_lizzy.LizzyForCausalLM",
167
+ "AutoTokenizer": "tokenization_lizzy.LizzyTokenizerFast"
168
+ },
169
+ "tokenizer_class": "LizzyTokenizerFast",
170
+ "transformers_version": "5.4.0",
171
+ "quantization_config": {
172
+ "quant_method": "paroquant",
173
+ "bits": 4,
174
+ "group_size": 128,
175
+ "krot": 8
176
+ }
177
+ }
configuration_lizzy.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from transformers import PretrainedConfig
6
+
7
+
8
+ class LizzyConfig(PretrainedConfig):
9
+ model_type = "lizzy"
10
+ keys_to_ignore_at_inference = ["past_key_values"]
11
+ base_model_tp_plan = {
12
+ "layers.*.self_attn.q_proj": "colwise",
13
+ "layers.*.self_attn.k_proj": "colwise",
14
+ "layers.*.self_attn.v_proj": "colwise",
15
+ "layers.*.self_attn.o_proj": "rowwise",
16
+ "layers.*.mlp.up_proj": "colwise",
17
+ "layers.*.mlp.gate_proj": "colwise",
18
+ "layers.*.mlp.down_proj": "rowwise",
19
+ "lm_head": "colwise",
20
+ }
21
+ base_model_pp_plan = {
22
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
23
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
24
+ "norm": (["hidden_states"], ["hidden_states"]),
25
+ }
26
+
27
+ def __init__(
28
+ self,
29
+ vocab_size: int = 32000,
30
+ hidden_size: int = 4096,
31
+ intermediate_size: int = 11008,
32
+ num_hidden_layers: int = 32,
33
+ num_attention_heads: int = 32,
34
+ num_key_value_heads: int | None = None,
35
+ max_position_embeddings: int = 2048,
36
+ head_dim: int | None = None,
37
+ hidden_act: str = "silu",
38
+ norm_type: str = "rmsnorm",
39
+ norm_eps: float = 1e-6,
40
+ norm_has_bias: bool = False,
41
+ use_pre_attn_norm: bool = True,
42
+ use_pre_mlp_norm: bool = True,
43
+ use_post_attn_norm: bool = False,
44
+ use_post_mlp_norm: bool = False,
45
+ mlp_type: str = "gated",
46
+ attention_bias: bool = False,
47
+ mlp_bias: bool = False,
48
+ position_embedding_type: str = "rope",
49
+ rope_theta: float = 10000.0,
50
+ rope_scaling: dict[str, Any] | None = None,
51
+ rope_layer_flags: list[bool] | None = None,
52
+ no_rope_layer_interval: int | None = None,
53
+ rope_type_overrides: dict[str, str] | None = None,
54
+ layer_types: list[str] | None = None,
55
+ layer_layouts: list[str] | None = None,
56
+ sliding_window: int | None = None,
57
+ linear_num_key_heads: int | None = None,
58
+ linear_num_value_heads: int | None = None,
59
+ linear_key_head_dim: int | None = None,
60
+ linear_value_head_dim: int | None = None,
61
+ linear_a_log_min: float | None = None,
62
+ linear_a_log_max: float | None = None,
63
+ linear_dt_min: float | None = None,
64
+ linear_dt_max: float | None = None,
65
+ linear_dt_init_floor: float | None = None,
66
+ linear_conv_kernel_dim: int | None = None,
67
+ linear_allow_neg_eigval: bool | None = None,
68
+ use_qk_norm: bool = False,
69
+ qk_norm_type: str = "rmsnorm",
70
+ attention_dropout: float = 0.0,
71
+ resid_dropout: float = 0.0,
72
+ embd_dropout: float = 0.0,
73
+ initializer_range: float = 0.02,
74
+ bos_token_id: int | None = None,
75
+ eos_token_id: int | None = None,
76
+ pad_token_id: int | None = None,
77
+ use_cache: bool = True,
78
+ tie_word_embeddings: bool = False,
79
+ **kwargs,
80
+ ) -> None:
81
+ if num_key_value_heads is None:
82
+ num_key_value_heads = num_attention_heads
83
+ if head_dim is None:
84
+ head_dim = hidden_size // num_attention_heads
85
+ if no_rope_layer_interval is not None:
86
+ no_rope_layer_interval = int(no_rope_layer_interval)
87
+ if no_rope_layer_interval <= 0:
88
+ no_rope_layer_interval = None
89
+ if layer_types is None:
90
+ layer_types = ["full_attention"] * int(num_hidden_layers)
91
+ if layer_layouts is None:
92
+ if use_post_attn_norm or use_post_mlp_norm:
93
+ layer_layouts = ["decoder_postnorm"] * int(num_hidden_layers)
94
+ else:
95
+ layer_layouts = ["decoder_prenorm"] * int(num_hidden_layers)
96
+ if rope_layer_flags is None:
97
+ rope_enabled = position_embedding_type == "rope"
98
+ if rope_enabled and no_rope_layer_interval is not None:
99
+ rope_layer_flags = [
100
+ ((layer_idx + 1) % no_rope_layer_interval) != 0
101
+ for layer_idx in range(int(num_hidden_layers))
102
+ ]
103
+ else:
104
+ rope_layer_flags = [rope_enabled] * int(num_hidden_layers)
105
+
106
+ normalized_rope_scaling = None
107
+ if rope_scaling is not None:
108
+ normalized_rope_scaling = dict(rope_scaling)
109
+ for field_name in (
110
+ "factor",
111
+ "attention_factor",
112
+ "beta_fast",
113
+ "beta_slow",
114
+ ):
115
+ if normalized_rope_scaling.get(field_name) is not None:
116
+ normalized_rope_scaling[field_name] = float(
117
+ normalized_rope_scaling[field_name]
118
+ )
119
+ if (
120
+ normalized_rope_scaling.get("original_max_position_embeddings")
121
+ is not None
122
+ ):
123
+ normalized_rope_scaling["original_max_position_embeddings"] = int(
124
+ normalized_rope_scaling["original_max_position_embeddings"]
125
+ )
126
+
127
+ # Transformers validates RoPE settings during PretrainedConfig
128
+ # initialization, so publish the rope-critical fields before
129
+ # calling `super().__init__()`.
130
+ self.max_position_embeddings = int(max_position_embeddings)
131
+ self.rope_theta = float(rope_theta)
132
+ self.rope_scaling = normalized_rope_scaling
133
+
134
+ super().__init__(
135
+ bos_token_id=bos_token_id,
136
+ eos_token_id=eos_token_id,
137
+ pad_token_id=pad_token_id,
138
+ tie_word_embeddings=tie_word_embeddings,
139
+ **kwargs,
140
+ )
141
+ self.vocab_size = int(vocab_size)
142
+ self.hidden_size = int(hidden_size)
143
+ self.intermediate_size = int(intermediate_size)
144
+ self.num_hidden_layers = int(num_hidden_layers)
145
+ self.num_attention_heads = int(num_attention_heads)
146
+ self.num_key_value_heads = int(num_key_value_heads)
147
+ self.max_position_embeddings = int(max_position_embeddings)
148
+ self.head_dim = int(head_dim)
149
+ self.hidden_act = str(hidden_act)
150
+ self.norm_type = str(norm_type)
151
+ self.norm_eps = float(norm_eps)
152
+ self.norm_has_bias = bool(norm_has_bias)
153
+ self.use_pre_attn_norm = bool(use_pre_attn_norm)
154
+ self.use_pre_mlp_norm = bool(use_pre_mlp_norm)
155
+ self.use_post_attn_norm = bool(use_post_attn_norm)
156
+ self.use_post_mlp_norm = bool(use_post_mlp_norm)
157
+ self.mlp_type = str(mlp_type)
158
+ self.attention_bias = bool(attention_bias)
159
+ self.mlp_bias = bool(mlp_bias)
160
+ self.position_embedding_type = str(position_embedding_type)
161
+ self.rope_theta = float(rope_theta)
162
+ self.rope_scaling = normalized_rope_scaling
163
+ self.no_rope_layer_interval = no_rope_layer_interval
164
+ self.rope_type_overrides = {
165
+ str(key): str(value)
166
+ for key, value in dict(rope_type_overrides or {}).items()
167
+ }
168
+ self.layer_types = list(layer_types)
169
+ self.layer_layouts = [str(item) for item in layer_layouts]
170
+ self.rope_layer_flags = [bool(item) for item in rope_layer_flags]
171
+ self.sliding_window = sliding_window
172
+ self.linear_num_key_heads = (
173
+ None
174
+ if linear_num_key_heads is None
175
+ else int(linear_num_key_heads)
176
+ )
177
+ self.linear_num_value_heads = (
178
+ None
179
+ if linear_num_value_heads is None
180
+ else int(linear_num_value_heads)
181
+ )
182
+ self.linear_key_head_dim = (
183
+ None
184
+ if linear_key_head_dim is None
185
+ else int(linear_key_head_dim)
186
+ )
187
+ self.linear_value_head_dim = (
188
+ None
189
+ if linear_value_head_dim is None
190
+ else int(linear_value_head_dim)
191
+ )
192
+ self.linear_a_log_min = (
193
+ None if linear_a_log_min is None else float(linear_a_log_min)
194
+ )
195
+ self.linear_a_log_max = (
196
+ None if linear_a_log_max is None else float(linear_a_log_max)
197
+ )
198
+ self.linear_dt_min = (
199
+ None if linear_dt_min is None else float(linear_dt_min)
200
+ )
201
+ self.linear_dt_max = (
202
+ None if linear_dt_max is None else float(linear_dt_max)
203
+ )
204
+ self.linear_dt_init_floor = (
205
+ None
206
+ if linear_dt_init_floor is None
207
+ else float(linear_dt_init_floor)
208
+ )
209
+ self.linear_conv_kernel_dim = (
210
+ None
211
+ if linear_conv_kernel_dim is None
212
+ else int(linear_conv_kernel_dim)
213
+ )
214
+ self.linear_allow_neg_eigval = (
215
+ None
216
+ if linear_allow_neg_eigval is None
217
+ else bool(linear_allow_neg_eigval)
218
+ )
219
+ self.use_qk_norm = bool(use_qk_norm)
220
+ self.qk_norm_type = str(qk_norm_type)
221
+ self.attention_dropout = float(attention_dropout)
222
+ self.resid_dropout = float(resid_dropout)
223
+ self.embd_dropout = float(embd_dropout)
224
+ self.initializer_range = float(initializer_range)
225
+ self.use_cache = bool(use_cache)
226
+ self.rms_norm_eps = self.norm_eps
227
+ self.dtype = None
generation_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "eos_token_id": 100257,
4
+ "transformers_version": "4.57.3",
5
+ "bos_token_id": 100257,
6
+ "pad_token_id": 100277,
7
+ "do_sample": true
8
+ }
header-dark.svg ADDED
header-light.svg ADDED
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f3dd0ee931c07cfee96d0ed171d5b9bcc12e38f51e65ee251b1651e282404568
3
+ size 5038271952
modeling_lizzy.py ADDED
@@ -0,0 +1,2190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import os
5
+ from typing import Any, cast
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from torch import nn
10
+ from torch.utils.checkpoint import checkpoint
11
+ from transformers.activations import ACT2FN
12
+ from transformers.cache_utils import Cache, DynamicCache
13
+ from transformers.generation import GenerationMixin
14
+ from transformers.modeling_outputs import (
15
+ BaseModelOutputWithPast,
16
+ CausalLMOutputWithPast,
17
+ )
18
+ from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
19
+
20
+ try:
21
+ from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS
22
+ except ImportError:
23
+ ROPE_INIT_FUNCTIONS = {}
24
+
25
+ try:
26
+ from fla.modules import FusedRMSNormGated, ShortConvolution
27
+ from fla.ops.gated_delta_rule import (
28
+ chunk_gated_delta_rule,
29
+ fused_recurrent_gated_delta_rule,
30
+ )
31
+ except ImportError:
32
+ chunk_gated_delta_rule = None
33
+ fused_recurrent_gated_delta_rule = None
34
+ FusedRMSNormGated = None
35
+ ShortConvolution = None
36
+
37
+ from .configuration_lizzy import LizzyConfig
38
+
39
+
40
+ class LizzyRMSNorm(nn.Module):
41
+ def __init__(self, hidden_size: int, eps: float = 1e-6) -> None:
42
+ super().__init__()
43
+ self.weight = nn.Parameter(torch.ones(hidden_size))
44
+ self.variance_epsilon = eps
45
+
46
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
47
+ input_dtype = hidden_states.dtype
48
+ hidden_states = hidden_states.to(torch.float32)
49
+ variance = hidden_states.pow(2).mean(dim=-1, keepdim=True)
50
+ hidden_states = hidden_states * torch.rsqrt(
51
+ variance + self.variance_epsilon
52
+ )
53
+ return self.weight * hidden_states.to(input_dtype)
54
+
55
+
56
+ def _make_norm(
57
+ norm_type: str,
58
+ hidden_size: int,
59
+ eps: float,
60
+ *,
61
+ has_bias: bool,
62
+ ) -> nn.Module:
63
+ if norm_type == "rmsnorm":
64
+ return LizzyRMSNorm(hidden_size, eps=eps)
65
+ if norm_type == "layernorm":
66
+ return nn.LayerNorm(
67
+ hidden_size,
68
+ eps=eps,
69
+ elementwise_affine=True,
70
+ bias=has_bias,
71
+ )
72
+ msg = f"Unsupported norm_type: {norm_type}"
73
+ raise ValueError(msg)
74
+
75
+
76
+ def _rotate_half(x: torch.Tensor) -> torch.Tensor:
77
+ x1 = x[..., : x.shape[-1] // 2]
78
+ x2 = x[..., x.shape[-1] // 2 :]
79
+ return torch.cat((-x2, x1), dim=-1)
80
+
81
+
82
+ def _apply_rotary_pos_emb(
83
+ q: torch.Tensor,
84
+ k: torch.Tensor,
85
+ cos: torch.Tensor,
86
+ sin: torch.Tensor,
87
+ ) -> tuple[torch.Tensor, torch.Tensor]:
88
+ q_embed = (q * cos) + (_rotate_half(q) * sin)
89
+ k_embed = (k * cos) + (_rotate_half(k) * sin)
90
+ return q_embed, k_embed
91
+
92
+
93
+ def _legacy_cache_length(
94
+ past_key_values: tuple[tuple[torch.Tensor, torch.Tensor], ...] | None,
95
+ ) -> int:
96
+ if (
97
+ isinstance(past_key_values, tuple)
98
+ and len(past_key_values) > 0
99
+ and past_key_values[0] is not None
100
+ and past_key_values[0][0] is not None
101
+ ):
102
+ return int(past_key_values[0][0].shape[2])
103
+ return 0
104
+
105
+
106
+ def _normalize_cache_position(
107
+ cache_position: torch.Tensor | None,
108
+ ) -> torch.Tensor | None:
109
+ if cache_position is None:
110
+ return None
111
+ if cache_position.dim() == 0:
112
+ return cache_position.view(1)
113
+ if cache_position.dim() > 1:
114
+ return cache_position[0]
115
+ return cache_position
116
+
117
+
118
+ def _is_cache_object(value: Any) -> bool:
119
+ return isinstance(value, Cache) or isinstance(value, LizzyHybridDynamicCache)
120
+
121
+
122
+ def _compute_default_rope_parameters(
123
+ config: LizzyConfig,
124
+ device: torch.device,
125
+ ) -> tuple[torch.Tensor, float]:
126
+ inv_freq = 1.0 / (
127
+ config.rope_theta
128
+ ** (
129
+ torch.arange(0, config.head_dim, 2, device=device, dtype=torch.float32)
130
+ / config.head_dim
131
+ )
132
+ )
133
+ return inv_freq, 1.0
134
+
135
+
136
+ def _compute_yarn_rope_parameters(
137
+ config: LizzyConfig,
138
+ device: torch.device,
139
+ ) -> tuple[torch.Tensor, float]:
140
+ rope_scaling = dict(config.rope_scaling or {})
141
+ factor = float(rope_scaling["factor"])
142
+ attention_factor = rope_scaling.get("attention_factor")
143
+ mscale = rope_scaling.get("mscale")
144
+ mscale_all_dim = rope_scaling.get("mscale_all_dim")
145
+ original_max_position_embeddings = int(
146
+ rope_scaling.get("original_max_position_embeddings")
147
+ or config.max_position_embeddings
148
+ )
149
+
150
+ def get_mscale(scale: float, mscale_value: float = 1.0) -> float:
151
+ if scale <= 1.0:
152
+ return 1.0
153
+ return 0.1 * mscale_value * math.log(scale) + 1.0
154
+
155
+ if attention_factor is None:
156
+ if mscale is not None and mscale_all_dim is not None:
157
+ attention_factor = float(
158
+ get_mscale(factor, float(mscale))
159
+ / get_mscale(factor, float(mscale_all_dim))
160
+ )
161
+ else:
162
+ attention_factor = get_mscale(factor)
163
+
164
+ beta_fast = float(rope_scaling.get("beta_fast") or 32.0)
165
+ beta_slow = float(rope_scaling.get("beta_slow") or 1.0)
166
+ truncate = bool(rope_scaling.get("truncate", True))
167
+ dim = config.head_dim
168
+
169
+ def find_correction_dim(
170
+ num_rotations: float,
171
+ *,
172
+ dim: int,
173
+ base: float,
174
+ max_position_embeddings: int,
175
+ ) -> float:
176
+ return (
177
+ dim
178
+ * math.log(max_position_embeddings / (num_rotations * 2 * math.pi))
179
+ / (2 * math.log(base))
180
+ )
181
+
182
+ def find_correction_range(
183
+ low_rot: float,
184
+ high_rot: float,
185
+ *,
186
+ dim: int,
187
+ base: float,
188
+ max_position_embeddings: int,
189
+ truncate: bool,
190
+ ) -> tuple[float, float]:
191
+ low = find_correction_dim(
192
+ low_rot,
193
+ dim=dim,
194
+ base=base,
195
+ max_position_embeddings=max_position_embeddings,
196
+ )
197
+ high = find_correction_dim(
198
+ high_rot,
199
+ dim=dim,
200
+ base=base,
201
+ max_position_embeddings=max_position_embeddings,
202
+ )
203
+ if truncate:
204
+ low = math.floor(low)
205
+ high = math.ceil(high)
206
+ return max(low, 0.0), min(high, dim - 1.0)
207
+
208
+ def linear_ramp_factor(
209
+ min_value: float,
210
+ max_value: float,
211
+ dim: int,
212
+ ) -> torch.Tensor:
213
+ if min_value == max_value:
214
+ max_value += 0.001
215
+ linear_func = (
216
+ torch.arange(dim, dtype=torch.float32, device=device) - min_value
217
+ ) / (max_value - min_value)
218
+ return torch.clamp(linear_func, 0, 1)
219
+
220
+ pos_freqs = config.rope_theta ** (
221
+ torch.arange(0, dim, 2, device=device, dtype=torch.float32) / dim
222
+ )
223
+ inv_freq_extrapolation = 1.0 / pos_freqs
224
+ inv_freq_interpolation = 1.0 / (factor * pos_freqs)
225
+ low, high = find_correction_range(
226
+ beta_fast,
227
+ beta_slow,
228
+ dim=dim,
229
+ base=config.rope_theta,
230
+ max_position_embeddings=original_max_position_embeddings,
231
+ truncate=truncate,
232
+ )
233
+ inv_freq_extrapolation_factor = 1 - linear_ramp_factor(low, high, dim // 2)
234
+ inv_freq = (
235
+ inv_freq_interpolation * (1 - inv_freq_extrapolation_factor)
236
+ + inv_freq_extrapolation * inv_freq_extrapolation_factor
237
+ )
238
+ return inv_freq, float(attention_factor)
239
+
240
+
241
+ def _compute_rope_parameters(
242
+ config: LizzyConfig,
243
+ device: torch.device,
244
+ *,
245
+ seq_len: int | torch.Tensor | None = None,
246
+ rope_type_override: str | None = None,
247
+ ) -> tuple[torch.Tensor, float]:
248
+ rope_scaling = dict(config.rope_scaling or {})
249
+ rope_type = rope_type_override
250
+ if rope_type is None:
251
+ if not rope_scaling:
252
+ return _compute_default_rope_parameters(config, device)
253
+ rope_type = str(
254
+ rope_scaling.get("rope_type", rope_scaling.get("type", "default"))
255
+ )
256
+
257
+ if rope_type == "default":
258
+ return _compute_default_rope_parameters(config, device)
259
+ if rope_type == "yarn":
260
+ return _compute_yarn_rope_parameters(config, device)
261
+ if not rope_scaling:
262
+ return _compute_default_rope_parameters(config, device)
263
+
264
+ rope_init_fn = (
265
+ ROPE_INIT_FUNCTIONS.get(rope_type) or ROPE_INIT_FUNCTIONS.get("default")
266
+ )
267
+ if rope_init_fn is None:
268
+ return _compute_default_rope_parameters(config, device)
269
+
270
+ inv_freq, attention_factor = rope_init_fn(config, device, seq_len=seq_len)
271
+ return inv_freq.to(device=device, dtype=torch.float32), float(attention_factor)
272
+
273
+
274
+ def _looks_like_legacy_interval_rope_lizzy(config: LizzyConfig) -> bool:
275
+ rope_layer_flags = list(getattr(config, "rope_layer_flags", None) or [])
276
+ if rope_layer_flags and not all(bool(item) for item in rope_layer_flags):
277
+ return False
278
+
279
+ layer_types = list(getattr(config, "layer_types", None) or [])
280
+ if layer_types and any(str(item) != "full_attention" for item in layer_types):
281
+ return False
282
+
283
+ return (
284
+ str(getattr(config, "position_embedding_type", "")).lower() == "rope"
285
+ and not bool(getattr(config, "rope_scaling", None))
286
+ and int(getattr(config, "num_hidden_layers", 0) or 0) == 36
287
+ and int(getattr(config, "hidden_size", 0) or 0) == 2048
288
+ and int(getattr(config, "num_attention_heads", 0) or 0) == 16
289
+ and int(getattr(config, "num_key_value_heads", 0) or 0) == 4
290
+ and math.isclose(
291
+ float(getattr(config, "rope_theta", 0.0) or 0.0), 5_000_000.0
292
+ )
293
+ and not bool(getattr(config, "use_post_attn_norm", False))
294
+ and not bool(getattr(config, "use_post_mlp_norm", False))
295
+ and not bool(getattr(config, "use_qk_norm", False))
296
+ )
297
+
298
+
299
+ def _get_no_rope_layer_interval(config: LizzyConfig) -> int | None:
300
+ value = getattr(config, "no_rope_layer_interval", None)
301
+ if value is not None:
302
+ value = int(value)
303
+ if value > 0:
304
+ return value
305
+ if _looks_like_legacy_interval_rope_lizzy(config):
306
+ # Backward-compatible fallback for already-uploaded Lizzy
307
+ # checkpoints that should use NoPE on every 4th layer.
308
+ return 4
309
+ return None
310
+
311
+
312
+ def _get_rope_layer_flag(config: LizzyConfig, layer_idx: int) -> bool:
313
+ rope_enabled = str(
314
+ getattr(config, "position_embedding_type", "rope")
315
+ ).lower() == "rope"
316
+ rope_layer_flags = list(getattr(config, "rope_layer_flags", None) or [])
317
+ no_rope_layer_interval = _get_no_rope_layer_interval(config)
318
+ if (
319
+ no_rope_layer_interval is not None
320
+ and (
321
+ layer_idx >= len(rope_layer_flags)
322
+ or not rope_layer_flags
323
+ or all(bool(item) for item in rope_layer_flags)
324
+ )
325
+ ):
326
+ return rope_enabled and ((layer_idx + 1) % no_rope_layer_interval != 0)
327
+ if 0 <= layer_idx < len(rope_layer_flags):
328
+ return rope_enabled and bool(rope_layer_flags[layer_idx])
329
+ return rope_enabled
330
+
331
+
332
+ def _get_layer_layout(config: LizzyConfig, layer_idx: int) -> str:
333
+ layer_layouts = list(getattr(config, "layer_layouts", None) or [])
334
+ if 0 <= layer_idx < len(layer_layouts):
335
+ return str(layer_layouts[layer_idx])
336
+ if bool(getattr(config, "use_post_attn_norm", False)) or bool(
337
+ getattr(config, "use_post_mlp_norm", False)
338
+ ):
339
+ return "decoder_postnorm"
340
+ return "decoder_prenorm"
341
+
342
+
343
+ def _has_linear_attention(config: LizzyConfig) -> bool:
344
+ return any(
345
+ str(layer_type) == "linear_attention"
346
+ for layer_type in list(getattr(config, "layer_types", None) or [])
347
+ )
348
+
349
+
350
+ class LizzyHybridDynamicCache:
351
+ """Cache for Lizzy checkpoints with mixed full and linear attention."""
352
+
353
+ is_compileable = False
354
+
355
+ def __init__(self, config: LizzyConfig) -> None:
356
+ super().__init__()
357
+ self.layer_types = list(config.layer_types)
358
+ self.transformer_layers = [
359
+ idx
360
+ for idx, layer_type in enumerate(self.layer_types)
361
+ if layer_type == "full_attention"
362
+ ]
363
+ self.last_linear_layer = (
364
+ len(self.layer_types)
365
+ - 1
366
+ - self.layer_types[::-1].index("linear_attention")
367
+ )
368
+ self.recurrent_states = [None for _ in range(config.num_hidden_layers)]
369
+ self.key_cache = [None for _ in range(config.num_hidden_layers)]
370
+ self.value_cache = [None for _ in range(config.num_hidden_layers)]
371
+ self.conv_states_q = [None for _ in range(config.num_hidden_layers)]
372
+ self.conv_states_k = [None for _ in range(config.num_hidden_layers)]
373
+ self.conv_states_v = [None for _ in range(config.num_hidden_layers)]
374
+
375
+ def __len__(self) -> int:
376
+ return len(self.layer_types)
377
+
378
+ def update(
379
+ self,
380
+ key_states: torch.Tensor,
381
+ value_states: torch.Tensor,
382
+ layer_idx: int,
383
+ cache_kwargs: dict[str, Any] | None = None,
384
+ ) -> tuple[torch.Tensor, torch.Tensor]:
385
+ del cache_kwargs
386
+ if self.key_cache[layer_idx] is None:
387
+ self.key_cache[layer_idx] = key_states
388
+ self.value_cache[layer_idx] = value_states
389
+ else:
390
+ self.key_cache[layer_idx] = torch.cat(
391
+ [self.key_cache[layer_idx], key_states],
392
+ dim=2,
393
+ )
394
+ self.value_cache[layer_idx] = torch.cat(
395
+ [self.value_cache[layer_idx], value_states],
396
+ dim=2,
397
+ )
398
+ return self.key_cache[layer_idx], self.value_cache[layer_idx]
399
+
400
+ def reorder_cache(self, beam_idx: torch.LongTensor) -> None:
401
+ batch_size = beam_idx.shape[0]
402
+ for layer_idx in range(len(self.key_cache)):
403
+ if self.key_cache[layer_idx] is not None:
404
+ if self.key_cache[layer_idx].shape[0] < batch_size:
405
+ expand_ratio = (
406
+ batch_size // self.key_cache[layer_idx].shape[0]
407
+ )
408
+ self.key_cache[layer_idx] = (
409
+ self.key_cache[layer_idx].repeat_interleave(
410
+ expand_ratio, dim=0,
411
+ )
412
+ )
413
+ self.value_cache[layer_idx] = (
414
+ self.value_cache[layer_idx].repeat_interleave(
415
+ expand_ratio, dim=0,
416
+ )
417
+ )
418
+ device = self.key_cache[layer_idx].device
419
+ self.key_cache[layer_idx] = self.key_cache[layer_idx].index_select(
420
+ 0,
421
+ beam_idx.to(device),
422
+ )
423
+ self.value_cache[layer_idx] = (
424
+ self.value_cache[layer_idx].index_select(0, beam_idx.to(device))
425
+ )
426
+ if self.conv_states_q[layer_idx] is not None:
427
+ if self.conv_states_q[layer_idx].shape[0] < batch_size:
428
+ expand_ratio = (
429
+ batch_size // self.conv_states_q[layer_idx].shape[0]
430
+ )
431
+ self.conv_states_q[layer_idx] = (
432
+ self.conv_states_q[layer_idx].repeat_interleave(
433
+ expand_ratio, dim=0,
434
+ )
435
+ )
436
+ self.conv_states_k[layer_idx] = (
437
+ self.conv_states_k[layer_idx].repeat_interleave(
438
+ expand_ratio, dim=0,
439
+ )
440
+ )
441
+ self.conv_states_v[layer_idx] = (
442
+ self.conv_states_v[layer_idx].repeat_interleave(
443
+ expand_ratio, dim=0,
444
+ )
445
+ )
446
+ self.recurrent_states[layer_idx] = (
447
+ self.recurrent_states[layer_idx].repeat_interleave(
448
+ expand_ratio, dim=0,
449
+ )
450
+ )
451
+ device = self.conv_states_q[layer_idx].device
452
+ self.conv_states_q[layer_idx] = (
453
+ self.conv_states_q[layer_idx].index_select(
454
+ 0,
455
+ beam_idx.to(device),
456
+ )
457
+ )
458
+ self.conv_states_k[layer_idx] = (
459
+ self.conv_states_k[layer_idx].index_select(
460
+ 0,
461
+ beam_idx.to(device),
462
+ )
463
+ )
464
+ self.conv_states_v[layer_idx] = (
465
+ self.conv_states_v[layer_idx].index_select(
466
+ 0,
467
+ beam_idx.to(device),
468
+ )
469
+ )
470
+ self.recurrent_states[layer_idx] = (
471
+ self.recurrent_states[layer_idx].index_select(
472
+ 0,
473
+ beam_idx.to(device),
474
+ )
475
+ )
476
+
477
+ def get_seq_length(self, layer_idx: int | None = 0) -> int:
478
+ if not self.transformer_layers:
479
+ return 0
480
+ layer_idx = (
481
+ self.transformer_layers[0]
482
+ if layer_idx not in self.transformer_layers
483
+ else layer_idx
484
+ )
485
+ if len(self.key_cache) <= layer_idx or self.key_cache[layer_idx] is None:
486
+ return 0
487
+ return self.key_cache[layer_idx].shape[-2]
488
+
489
+ def get_mask_sizes(self, query_length: int, layer_idx: int) -> tuple[int, int]:
490
+ del layer_idx
491
+ kv_offset = 0
492
+ past_seen_tokens = self.get_seq_length()
493
+ kv_length = query_length + past_seen_tokens
494
+ return kv_length, kv_offset
495
+
496
+ @property
497
+ def has_previous_state(self) -> bool:
498
+ # Mirror the upstream contract: once the final linear layer has cached
499
+ # its conv state, single-token decode can switch to the recurrent path.
500
+ return self.conv_states_q[self.last_linear_layer] is not None
501
+
502
+
503
+ class LizzyHybridRMSNormGated(nn.Module):
504
+ def __init__(self, hidden_size: int, eps: float = 1e-6) -> None:
505
+ super().__init__()
506
+ self.weight = nn.Parameter(torch.ones(hidden_size))
507
+ self.variance_epsilon = eps
508
+
509
+ def forward(
510
+ self,
511
+ hidden_states: torch.Tensor,
512
+ gate: torch.Tensor | None = None,
513
+ ) -> torch.Tensor:
514
+ if gate is None:
515
+ msg = "gate is required for gated RMSNorm."
516
+ raise ValueError(msg)
517
+ input_dtype = hidden_states.dtype
518
+ hidden_states = hidden_states.to(torch.float32)
519
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
520
+ hidden_states = hidden_states * torch.rsqrt(
521
+ variance + self.variance_epsilon
522
+ )
523
+ hidden_states = self.weight * hidden_states.to(input_dtype)
524
+ hidden_states = hidden_states * F.silu(gate.to(torch.float32))
525
+ return hidden_states.to(input_dtype)
526
+
527
+
528
+ class LizzyHybridShortConvolution(nn.Conv1d):
529
+ def __init__(
530
+ self,
531
+ hidden_size: int,
532
+ kernel_size: int,
533
+ bias: bool = False,
534
+ activation: str | None = "silu",
535
+ ) -> None:
536
+ super().__init__(
537
+ in_channels=hidden_size,
538
+ out_channels=hidden_size,
539
+ kernel_size=kernel_size,
540
+ groups=hidden_size,
541
+ padding=kernel_size - 1,
542
+ bias=bias,
543
+ )
544
+ self.hidden_size = hidden_size
545
+ self.conv_kernel_size = kernel_size
546
+ self.act_fn = ACT2FN[activation]
547
+
548
+ def forward(
549
+ self,
550
+ hidden_states: torch.Tensor,
551
+ cache: torch.Tensor | None = None,
552
+ use_precomputed: bool = False,
553
+ **kwargs: Any,
554
+ ) -> tuple[torch.Tensor, torch.Tensor]:
555
+ del kwargs
556
+ seq_len, dim = hidden_states.shape[-2:]
557
+ hidden_states = hidden_states.transpose(1, 2)
558
+ if use_precomputed:
559
+ if cache is None:
560
+ msg = "cache is required when use_precomputed=True."
561
+ raise ValueError(msg)
562
+ x_with_state = torch.cat([cache, hidden_states], dim=-1)
563
+ out = F.conv1d(
564
+ x_with_state,
565
+ self.weight,
566
+ self.bias,
567
+ padding=0,
568
+ groups=dim,
569
+ )
570
+ conv_state = x_with_state[:, :, 1:]
571
+ else:
572
+ out = F.conv1d(
573
+ hidden_states,
574
+ self.weight,
575
+ self.bias,
576
+ padding=self.conv_kernel_size - 1,
577
+ groups=dim,
578
+ )
579
+ out = out[:, :, :seq_len]
580
+ conv_state = F.pad(
581
+ hidden_states,
582
+ (self.conv_kernel_size - 1 - hidden_states.shape[-1], 0),
583
+ )
584
+ out = self.act_fn(out)
585
+ return out.transpose(1, 2), conv_state
586
+
587
+
588
+ def _apply_mask_to_padding_states(
589
+ hidden_states: torch.Tensor,
590
+ attention_mask: torch.Tensor | None,
591
+ ) -> torch.Tensor:
592
+ # Match the upstream hybrid implementation: silence padded tokens before
593
+ # the DeltaNet projections so recurrent state does not absorb padding.
594
+ if (
595
+ attention_mask is not None
596
+ and attention_mask.shape[1] > 1
597
+ and attention_mask.shape[0] > 1
598
+ ):
599
+ dtype = hidden_states.dtype
600
+ hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
601
+ return hidden_states
602
+
603
+
604
+ def _l2norm(
605
+ x: torch.Tensor,
606
+ dim: int = -1,
607
+ eps: float = 1e-6,
608
+ ) -> torch.Tensor:
609
+ inv_norm = torch.rsqrt((x * x).sum(dim=dim, keepdim=True) + eps)
610
+ return x * inv_norm
611
+
612
+
613
+ def _torch_chunk_gated_delta_rule(
614
+ query: torch.Tensor,
615
+ key: torch.Tensor,
616
+ value: torch.Tensor,
617
+ g: torch.Tensor,
618
+ beta: torch.Tensor,
619
+ chunk_size: int = 64,
620
+ initial_state: torch.Tensor | None = None,
621
+ output_final_state: bool = False,
622
+ use_qk_l2norm_in_kernel: bool = False,
623
+ ) -> tuple[torch.Tensor, torch.Tensor | None]:
624
+ initial_dtype = query.dtype
625
+ if use_qk_l2norm_in_kernel:
626
+ query = _l2norm(query, dim=-1, eps=1e-6)
627
+ key = _l2norm(key, dim=-1, eps=1e-6)
628
+ query, key, value, beta, g = [
629
+ x.transpose(1, 2).contiguous().to(torch.float32)
630
+ for x in (query, key, value, beta, g)
631
+ ]
632
+ batch_size, num_heads, sequence_length, k_head_dim = key.shape
633
+ v_head_dim = value.shape[-1]
634
+ pad_size = (chunk_size - sequence_length % chunk_size) % chunk_size
635
+ query = F.pad(query, (0, 0, 0, pad_size))
636
+ key = F.pad(key, (0, 0, 0, pad_size))
637
+ value = F.pad(value, (0, 0, 0, pad_size))
638
+ beta = F.pad(beta, (0, pad_size))
639
+ g = F.pad(g, (0, pad_size))
640
+ total_sequence_length = sequence_length + pad_size
641
+ scale = 1 / (query.shape[-1] ** 0.5)
642
+ query = query * scale
643
+
644
+ v_beta = value * beta.unsqueeze(-1)
645
+ k_beta = key * beta.unsqueeze(-1)
646
+ query, key, value, k_beta, v_beta = [
647
+ x.reshape(x.shape[0], x.shape[1], -1, chunk_size, x.shape[-1])
648
+ for x in (query, key, value, k_beta, v_beta)
649
+ ]
650
+ g = g.reshape(g.shape[0], g.shape[1], -1, chunk_size)
651
+ mask = torch.triu(
652
+ torch.ones(
653
+ chunk_size,
654
+ chunk_size,
655
+ dtype=torch.bool,
656
+ device=query.device,
657
+ ),
658
+ diagonal=0,
659
+ )
660
+ g = g.cumsum(dim=-1)
661
+ decay_mask = ((g.unsqueeze(-1) - g.unsqueeze(-2)).tril().exp().float()).tril()
662
+ attn = -((k_beta @ key.transpose(-1, -2)) * decay_mask).masked_fill(mask, 0)
663
+ for idx in range(1, chunk_size):
664
+ row = attn[..., idx, :idx].clone()
665
+ sub = attn[..., :idx, :idx].clone()
666
+ attn[..., idx, :idx] = row + (row.unsqueeze(-1) * sub).sum(-2)
667
+ attn = attn + torch.eye(
668
+ chunk_size,
669
+ dtype=attn.dtype,
670
+ device=attn.device,
671
+ )
672
+ value = attn @ v_beta
673
+ k_cumdecay = attn @ (k_beta * g.exp().unsqueeze(-1))
674
+ last_recurrent_state = (
675
+ torch.zeros(batch_size, num_heads, k_head_dim, v_head_dim).to(value)
676
+ if initial_state is None
677
+ else initial_state.to(value)
678
+ )
679
+ core_attn_out = torch.zeros_like(value)
680
+ mask = torch.triu(
681
+ torch.ones(
682
+ chunk_size,
683
+ chunk_size,
684
+ dtype=torch.bool,
685
+ device=query.device,
686
+ ),
687
+ diagonal=1,
688
+ )
689
+ for idx in range(0, total_sequence_length // chunk_size):
690
+ q_i, k_i, v_i = query[:, :, idx], key[:, :, idx], value[:, :, idx]
691
+ attn = (q_i @ k_i.transpose(-1, -2) * decay_mask[:, :, idx]).masked_fill_(
692
+ mask,
693
+ 0,
694
+ )
695
+ v_prime = (k_cumdecay[:, :, idx]) @ last_recurrent_state
696
+ v_new = v_i - v_prime
697
+ attn_inter = (q_i * g[:, :, idx, :, None].exp()) @ last_recurrent_state
698
+ core_attn_out[:, :, idx] = attn_inter + attn @ v_new
699
+ last_recurrent_state = (
700
+ last_recurrent_state * g[:, :, idx, -1, None, None].exp()
701
+ + (
702
+ k_i
703
+ * (g[:, :, idx, -1, None] - g[:, :, idx]).exp()[..., None]
704
+ ).transpose(-1, -2)
705
+ @ v_new
706
+ )
707
+ if not output_final_state:
708
+ last_recurrent_state = None
709
+ core_attn_out = core_attn_out.reshape(
710
+ core_attn_out.shape[0],
711
+ core_attn_out.shape[1],
712
+ -1,
713
+ core_attn_out.shape[-1],
714
+ )
715
+ core_attn_out = core_attn_out[:, :, :sequence_length]
716
+ core_attn_out = core_attn_out.transpose(1, 2).contiguous().to(initial_dtype)
717
+ return core_attn_out, last_recurrent_state
718
+
719
+
720
+ def _torch_recurrent_gated_delta_rule(
721
+ query: torch.Tensor,
722
+ key: torch.Tensor,
723
+ value: torch.Tensor,
724
+ g: torch.Tensor,
725
+ beta: torch.Tensor,
726
+ initial_state: torch.Tensor | None,
727
+ output_final_state: bool,
728
+ use_qk_l2norm_in_kernel: bool = False,
729
+ ) -> tuple[torch.Tensor, torch.Tensor | None]:
730
+ initial_dtype = query.dtype
731
+ if use_qk_l2norm_in_kernel:
732
+ query = _l2norm(query, dim=-1, eps=1e-6)
733
+ key = _l2norm(key, dim=-1, eps=1e-6)
734
+ query, key, value, beta, g = [
735
+ x.transpose(1, 2).contiguous().to(torch.float32)
736
+ for x in (query, key, value, beta, g)
737
+ ]
738
+ batch_size, num_heads, sequence_length, k_head_dim = key.shape
739
+ v_head_dim = value.shape[-1]
740
+ scale = 1 / (query.shape[-1] ** 0.5)
741
+ query = query * scale
742
+ core_attn_out = torch.zeros(
743
+ batch_size,
744
+ num_heads,
745
+ sequence_length,
746
+ v_head_dim,
747
+ ).to(value)
748
+ last_recurrent_state = (
749
+ torch.zeros(batch_size, num_heads, k_head_dim, v_head_dim).to(value)
750
+ if initial_state is None
751
+ else initial_state.to(value)
752
+ )
753
+ for idx in range(sequence_length):
754
+ q_t = query[:, :, idx]
755
+ k_t = key[:, :, idx]
756
+ v_t = value[:, :, idx]
757
+ g_t = g[:, :, idx].exp().unsqueeze(-1).unsqueeze(-1)
758
+ beta_t = beta[:, :, idx].unsqueeze(-1)
759
+ last_recurrent_state = last_recurrent_state * g_t
760
+ kv_mem = (last_recurrent_state * k_t.unsqueeze(-1)).sum(dim=-2)
761
+ delta = (v_t - kv_mem) * beta_t
762
+ last_recurrent_state = (
763
+ last_recurrent_state + k_t.unsqueeze(-1) * delta.unsqueeze(-2)
764
+ )
765
+ core_attn_out[:, :, idx] = (
766
+ last_recurrent_state * q_t.unsqueeze(-1)
767
+ ).sum(dim=-2)
768
+ if not output_final_state:
769
+ last_recurrent_state = None
770
+ core_attn_out = core_attn_out.transpose(1, 2).contiguous().to(initial_dtype)
771
+ return core_attn_out, last_recurrent_state
772
+
773
+
774
+ class LizzyHybridGatedDeltaNet(nn.Module):
775
+ def __init__(self, config: LizzyConfig, layer_idx: int) -> None:
776
+ super().__init__()
777
+ self.hidden_size = config.hidden_size
778
+ self.num_v_heads = config.linear_num_value_heads
779
+ self.num_k_heads = config.linear_num_key_heads
780
+ self.head_k_dim = config.linear_key_head_dim
781
+ self.head_v_dim = config.linear_value_head_dim
782
+ self.key_dim = self.head_k_dim * self.num_k_heads
783
+ self.value_dim = self.head_v_dim * self.num_v_heads
784
+ self.layer_idx = layer_idx
785
+ self.conv_kernel_size = config.linear_conv_kernel_dim
786
+ self.allow_neg_eigval = config.linear_allow_neg_eigval
787
+ self.eps = config.rms_norm_eps
788
+ self.q_proj = nn.Linear(self.hidden_size, self.key_dim, bias=False)
789
+ self.k_proj = nn.Linear(self.hidden_size, self.key_dim, bias=False)
790
+ self.v_proj = nn.Linear(self.hidden_size, self.value_dim, bias=False)
791
+ self.a_proj = nn.Linear(self.hidden_size, self.num_v_heads, bias=False)
792
+ self.b_proj = nn.Linear(self.hidden_size, self.num_v_heads, bias=False)
793
+ self.g_proj = nn.Linear(self.hidden_size, self.value_dim, bias=False)
794
+ self.o_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False)
795
+
796
+ # Step-02 conversion runs on CPU by default, even on GPU nodes. In that
797
+ # flow Triton-backed FLA kernels will crash as soon as a CPU tensor
798
+ # reaches them, so the wrapper can force the pure PyTorch fallback for
799
+ # Hybrid layers via an environment switch.
800
+ disable_fla_fast_path = os.environ.get(
801
+ "LIZZY_DISABLE_HYBRID_FLA",
802
+ "",
803
+ ).strip().lower() in {"1", "true", "yes", "on"}
804
+ use_fla_fast_path = (
805
+ not disable_fla_fast_path
806
+ and
807
+ torch.cuda.is_available()
808
+ and ShortConvolution is not None
809
+ and chunk_gated_delta_rule is not None
810
+ and fused_recurrent_gated_delta_rule is not None
811
+ and FusedRMSNormGated is not None
812
+ )
813
+ # Keep the fast-path contract when FLA is present, but fall back to a
814
+ # local implementation so the public Lizzy artifact never depends on
815
+ # family-specific Transformers remote code.
816
+ conv1d_class = (
817
+ ShortConvolution if use_fla_fast_path else LizzyHybridShortConvolution
818
+ )
819
+ self.q_conv1d = conv1d_class(
820
+ hidden_size=self.key_dim,
821
+ kernel_size=self.conv_kernel_size,
822
+ bias=False,
823
+ activation="silu",
824
+ )
825
+ self.k_conv1d = conv1d_class(
826
+ hidden_size=self.key_dim,
827
+ kernel_size=self.conv_kernel_size,
828
+ bias=False,
829
+ activation="silu",
830
+ )
831
+ self.v_conv1d = conv1d_class(
832
+ hidden_size=self.value_dim,
833
+ kernel_size=self.conv_kernel_size,
834
+ bias=False,
835
+ activation="silu",
836
+ )
837
+
838
+ a = torch.empty(self.num_v_heads, dtype=torch.float32).uniform_(
839
+ config.linear_a_log_min,
840
+ config.linear_a_log_max,
841
+ )
842
+ self.A_log = nn.Parameter(torch.log(a))
843
+ dt = torch.exp(
844
+ torch.rand(self.num_v_heads)
845
+ * (math.log(config.linear_dt_max) - math.log(config.linear_dt_min))
846
+ + math.log(config.linear_dt_min)
847
+ )
848
+ dt = torch.clamp(dt, min=config.linear_dt_init_floor)
849
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
850
+ self.dt_bias = nn.Parameter(inv_dt)
851
+
852
+ self.o_norm = (
853
+ LizzyHybridRMSNormGated(self.head_v_dim, eps=1e-5)
854
+ if not use_fla_fast_path
855
+ else FusedRMSNormGated(
856
+ self.head_v_dim,
857
+ eps=1e-5,
858
+ device=torch.cuda.current_device(),
859
+ dtype=(
860
+ config.dtype
861
+ if config.dtype is not None
862
+ else torch.get_default_dtype()
863
+ ),
864
+ )
865
+ )
866
+ self.chunk_gated_delta_rule = (
867
+ chunk_gated_delta_rule
868
+ if use_fla_fast_path
869
+ else _torch_chunk_gated_delta_rule
870
+ )
871
+ self.recurrent_gated_delta_rule = (
872
+ (
873
+ fused_recurrent_gated_delta_rule
874
+ if use_fla_fast_path
875
+ else _torch_recurrent_gated_delta_rule
876
+ )
877
+ )
878
+
879
+ def forward(
880
+ self,
881
+ hidden_states: torch.Tensor,
882
+ cache_params: LizzyHybridDynamicCache | None = None,
883
+ attention_mask: torch.Tensor | None = None,
884
+ **kwargs: Any,
885
+ ) -> torch.Tensor:
886
+ del kwargs
887
+ hidden_states = _apply_mask_to_padding_states(hidden_states, attention_mask)
888
+ batch_size, seq_len, _ = hidden_states.shape
889
+ use_cache = cache_params is not None
890
+ use_precomputed = (
891
+ use_cache
892
+ and getattr(cache_params, "has_previous_state", False)
893
+ and seq_len == 1
894
+ )
895
+ conv_state_q = (
896
+ cache_params.conv_states_q[self.layer_idx] if cache_params else None
897
+ )
898
+ conv_state_k = (
899
+ cache_params.conv_states_k[self.layer_idx] if cache_params else None
900
+ )
901
+ conv_state_v = (
902
+ cache_params.conv_states_v[self.layer_idx] if cache_params else None
903
+ )
904
+ recurrent_state = (
905
+ cache_params.recurrent_states[self.layer_idx] if cache_params else None
906
+ )
907
+
908
+ q = self.q_proj(hidden_states)
909
+ k = self.k_proj(hidden_states)
910
+ v = self.v_proj(hidden_states)
911
+ q, new_conv_state_q = self.q_conv1d(
912
+ q,
913
+ cache=conv_state_q,
914
+ use_precomputed=use_precomputed,
915
+ output_final_state=use_cache,
916
+ )
917
+ k, new_conv_state_k = self.k_conv1d(
918
+ k,
919
+ cache=conv_state_k,
920
+ use_precomputed=use_precomputed,
921
+ output_final_state=use_cache,
922
+ )
923
+ v, new_conv_state_v = self.v_conv1d(
924
+ v,
925
+ cache=conv_state_v,
926
+ use_precomputed=use_precomputed,
927
+ output_final_state=use_cache,
928
+ )
929
+
930
+ if cache_params is not None:
931
+ cache_params.conv_states_q[self.layer_idx] = new_conv_state_q
932
+ cache_params.conv_states_k[self.layer_idx] = new_conv_state_k
933
+ cache_params.conv_states_v[self.layer_idx] = new_conv_state_v
934
+
935
+ q = q.view(batch_size, seq_len, -1, self.head_k_dim)
936
+ k = k.view(batch_size, seq_len, -1, self.head_k_dim)
937
+ v = v.view(batch_size, seq_len, -1, self.head_v_dim)
938
+ if self.num_v_heads > self.num_k_heads:
939
+ expand_ratio = self.num_v_heads // self.num_k_heads
940
+ q = q.repeat_interleave(expand_ratio, dim=2)
941
+ k = k.repeat_interleave(expand_ratio, dim=2)
942
+
943
+ beta = self.b_proj(hidden_states).sigmoid()
944
+ if self.allow_neg_eigval:
945
+ beta = beta * 2.0
946
+ g = -self.A_log.float().exp() * F.softplus(
947
+ self.a_proj(hidden_states).float() + self.dt_bias
948
+ )
949
+
950
+ if use_precomputed:
951
+ output, new_recurrent_state = self.recurrent_gated_delta_rule(
952
+ q,
953
+ k,
954
+ v,
955
+ g=g,
956
+ beta=beta,
957
+ initial_state=recurrent_state,
958
+ output_final_state=use_cache,
959
+ use_qk_l2norm_in_kernel=True,
960
+ )
961
+ else:
962
+ output, new_recurrent_state = self.chunk_gated_delta_rule(
963
+ q,
964
+ k,
965
+ v,
966
+ g=g,
967
+ beta=beta,
968
+ initial_state=recurrent_state,
969
+ output_final_state=use_cache,
970
+ use_qk_l2norm_in_kernel=True,
971
+ )
972
+
973
+ if cache_params is not None:
974
+ cache_params.recurrent_states[self.layer_idx] = new_recurrent_state
975
+
976
+ gate = self.g_proj(hidden_states)
977
+ output = output.reshape(-1, self.head_v_dim)
978
+ gate = gate.reshape(-1, self.head_v_dim)
979
+ output = self.o_norm(output, gate)
980
+ output = output.reshape(batch_size, seq_len, -1)
981
+ output = self.o_proj(output)
982
+ return output
983
+
984
+
985
+ class LizzyLinearAttention(nn.Module):
986
+ def __init__(self, config: LizzyConfig, layer_idx: int) -> None:
987
+ super().__init__()
988
+ self.layer_idx = layer_idx
989
+ self.inner = LizzyHybridGatedDeltaNet(config, layer_idx)
990
+
991
+ def forward(
992
+ self,
993
+ hidden_states: torch.Tensor,
994
+ attention_mask: torch.Tensor | None = None,
995
+ past_key_value: Cache | None = None,
996
+ use_cache: bool = False,
997
+ output_attentions: bool = False,
998
+ **kwargs: Any,
999
+ ) -> tuple[
1000
+ torch.Tensor,
1001
+ Cache | None,
1002
+ torch.Tensor | None,
1003
+ ]:
1004
+ del kwargs, output_attentions
1005
+ output = self.inner(
1006
+ hidden_states=hidden_states,
1007
+ cache_params=(
1008
+ past_key_value if _is_cache_object(past_key_value) else None
1009
+ ),
1010
+ attention_mask=attention_mask,
1011
+ )
1012
+ present = past_key_value if use_cache else None
1013
+ return output, present, None
1014
+
1015
+
1016
+ class LizzyAttention(nn.Module):
1017
+ def __init__(self, config: LizzyConfig, layer_idx: int) -> None:
1018
+ super().__init__()
1019
+ self.is_causal = True
1020
+ self.config = config
1021
+ self.layer_idx = layer_idx
1022
+ self.num_heads = config.num_attention_heads
1023
+ self.num_key_value_heads = config.num_key_value_heads
1024
+ self.num_key_value_groups = self.num_heads // self.num_key_value_heads
1025
+ self.head_dim = config.head_dim
1026
+ self.hidden_size = config.hidden_size
1027
+ self.scaling = self.head_dim**-0.5
1028
+ self.attention_dropout = config.attention_dropout
1029
+ self.position_embedding_type = config.position_embedding_type
1030
+ self.layer_type = (
1031
+ str(config.layer_types[layer_idx])
1032
+ if layer_idx < len(config.layer_types)
1033
+ else "full_attention"
1034
+ )
1035
+ self.use_rope = _get_rope_layer_flag(config, layer_idx)
1036
+ self._rope_type_override = str(
1037
+ dict(config.rope_type_overrides or {}).get(self.layer_type) or ""
1038
+ ) or None
1039
+ if (
1040
+ self._rope_type_override is None
1041
+ and self.layer_type == "sliding_attention"
1042
+ and bool(config.rope_scaling)
1043
+ and config.use_post_attn_norm
1044
+ and config.use_post_mlp_norm
1045
+ and config.use_qk_norm
1046
+ and any(str(item) == "full_attention" for item in config.layer_types)
1047
+ ):
1048
+ self._rope_type_override = "default"
1049
+ self.sliding_window = None
1050
+ if self.layer_type == "sliding_attention":
1051
+ self.sliding_window = config.sliding_window
1052
+
1053
+ q_dim = self.num_heads * self.head_dim
1054
+ kv_dim = self.num_key_value_heads * self.head_dim
1055
+ self.q_proj = nn.Linear(
1056
+ config.hidden_size,
1057
+ q_dim,
1058
+ bias=config.attention_bias,
1059
+ )
1060
+ self.k_proj = nn.Linear(
1061
+ config.hidden_size,
1062
+ kv_dim,
1063
+ bias=config.attention_bias,
1064
+ )
1065
+ self.v_proj = nn.Linear(
1066
+ config.hidden_size,
1067
+ kv_dim,
1068
+ bias=config.attention_bias,
1069
+ )
1070
+ self.o_proj = nn.Linear(
1071
+ q_dim,
1072
+ config.hidden_size,
1073
+ bias=config.attention_bias,
1074
+ )
1075
+ self.q_norm = (
1076
+ _make_norm(config.qk_norm_type, q_dim, config.norm_eps, has_bias=False)
1077
+ if config.use_qk_norm
1078
+ else None
1079
+ )
1080
+ self.k_norm = (
1081
+ _make_norm(config.qk_norm_type, kv_dim, config.norm_eps, has_bias=False)
1082
+ if config.use_qk_norm
1083
+ else None
1084
+ )
1085
+ self._rope_requires_runtime_update = False
1086
+
1087
+ if self.use_rope:
1088
+ rope_scaling = dict(config.rope_scaling or {})
1089
+ rope_type = self._rope_type_override or str(
1090
+ rope_scaling.get("rope_type", rope_scaling.get("type", "default"))
1091
+ )
1092
+ self._rope_requires_runtime_update = rope_type == "dynamic"
1093
+ if self._rope_requires_runtime_update:
1094
+ self.register_buffer("_rope_inv_freq", None, persistent=False)
1095
+ self.register_buffer(
1096
+ "_rope_attention_factor", None, persistent=False,
1097
+ )
1098
+ else:
1099
+ inv_freq, attention_factor = _compute_rope_parameters(
1100
+ config,
1101
+ device=torch.device("cpu"),
1102
+ seq_len=config.max_position_embeddings,
1103
+ rope_type_override=self._rope_type_override,
1104
+ )
1105
+ self.register_buffer("_rope_inv_freq", inv_freq, persistent=False)
1106
+ self.register_buffer(
1107
+ "_rope_attention_factor",
1108
+ torch.tensor(float(attention_factor), dtype=torch.float32),
1109
+ persistent=False,
1110
+ )
1111
+ else:
1112
+ self.register_buffer("_rope_inv_freq", None, persistent=False)
1113
+ self.register_buffer("_rope_attention_factor", None, persistent=False)
1114
+
1115
+ def _build_rope(
1116
+ self,
1117
+ position_ids: torch.Tensor,
1118
+ device: torch.device,
1119
+ dtype: torch.dtype,
1120
+ ) -> tuple[torch.Tensor, torch.Tensor]:
1121
+ if not self.use_rope:
1122
+ msg = "RoPE requested but rope buffer is not initialized."
1123
+ raise RuntimeError(msg)
1124
+
1125
+ inv_freq = self._rope_inv_freq
1126
+ attention_factor_tensor = self._rope_attention_factor
1127
+ if (
1128
+ inv_freq is None
1129
+ or attention_factor_tensor is None
1130
+ or self._rope_requires_runtime_update
1131
+ ):
1132
+ # Keep the sequence-length hint as a tensor so TorchDynamo/vLLM
1133
+ # can trace this path without requiring capture_scalar_outputs.
1134
+ # When low-memory loading leaves the non-persistent cache unset,
1135
+ # rebuild from config for this forward only instead of mutating
1136
+ # buffers inside the compiled graph.
1137
+ seq_len = (
1138
+ torch.max(position_ids) + 1 if position_ids.numel() > 0 else None
1139
+ )
1140
+ inv_freq, attention_factor = _compute_rope_parameters(
1141
+ self.config,
1142
+ device=device,
1143
+ seq_len=seq_len,
1144
+ rope_type_override=self._rope_type_override,
1145
+ )
1146
+ attention_factor_tensor = torch.tensor(
1147
+ float(attention_factor),
1148
+ device=device,
1149
+ dtype=torch.float32,
1150
+ )
1151
+ else:
1152
+ inv_freq = inv_freq.to(device=device)
1153
+ attention_factor_tensor = attention_factor_tensor.to(
1154
+ device=device,
1155
+ dtype=torch.float32,
1156
+ )
1157
+
1158
+ # Mirror the upstream HF decoder-only rotary path closely here.
1159
+ # The matmul-based construction is slightly more numerically stable
1160
+ # than the generic einsum formulation for strict parity probes.
1161
+ inv_freq_expanded = (
1162
+ inv_freq[None, :, None]
1163
+ .to(device=device, dtype=torch.float32)
1164
+ .expand(position_ids.shape[0], -1, 1)
1165
+ )
1166
+ position_ids_expanded = position_ids[:, None, :].to(torch.float32)
1167
+ angles = torch.matmul(
1168
+ inv_freq_expanded,
1169
+ position_ids_expanded,
1170
+ ).transpose(1, 2)
1171
+ angles = torch.cat((angles, angles), dim=-1)
1172
+ cos = angles.cos().unsqueeze(1) * attention_factor_tensor
1173
+ sin = angles.sin().unsqueeze(1) * attention_factor_tensor
1174
+ cos = cos.to(dtype)
1175
+ sin = sin.to(dtype)
1176
+ return cos, sin
1177
+
1178
+ def forward(
1179
+ self,
1180
+ hidden_states: torch.Tensor,
1181
+ attention_mask: torch.Tensor | None = None,
1182
+ position_ids: torch.Tensor | None = None,
1183
+ past_key_value: Cache | tuple[torch.Tensor, torch.Tensor] | None = None,
1184
+ cache_position: torch.Tensor | None = None,
1185
+ use_cache: bool = False,
1186
+ output_attentions: bool = False,
1187
+ **kwargs: Any,
1188
+ ) -> tuple[
1189
+ torch.Tensor,
1190
+ Cache | tuple[torch.Tensor, torch.Tensor] | None,
1191
+ torch.Tensor | None,
1192
+ ]:
1193
+ batch_size, q_len, _ = hidden_states.shape
1194
+ cache_position = _normalize_cache_position(cache_position)
1195
+
1196
+ query_states = self.q_proj(hidden_states)
1197
+ key_states = self.k_proj(hidden_states)
1198
+ value_states = self.v_proj(hidden_states)
1199
+
1200
+ if self.q_norm is not None:
1201
+ query_states = self.q_norm(query_states)
1202
+ if self.k_norm is not None:
1203
+ key_states = self.k_norm(key_states)
1204
+
1205
+ local_num_heads = query_states.shape[-1] // self.head_dim
1206
+ local_num_key_value_heads = key_states.shape[-1] // self.head_dim
1207
+ if local_num_heads <= 0 or local_num_key_value_heads <= 0:
1208
+ msg = "Invalid local attention head count after projection."
1209
+ raise RuntimeError(msg)
1210
+ if query_states.shape[-1] != local_num_heads * self.head_dim:
1211
+ msg = "q_proj output is not divisible by head_dim."
1212
+ raise RuntimeError(msg)
1213
+ if key_states.shape[-1] != local_num_key_value_heads * self.head_dim:
1214
+ msg = "k_proj output is not divisible by head_dim."
1215
+ raise RuntimeError(msg)
1216
+ if value_states.shape[-1] != local_num_key_value_heads * self.head_dim:
1217
+ msg = "v_proj output is not divisible by head_dim."
1218
+ raise RuntimeError(msg)
1219
+
1220
+ query_states = query_states.view(
1221
+ batch_size, q_len, local_num_heads, self.head_dim,
1222
+ )
1223
+ query_states = query_states.transpose(1, 2)
1224
+ key_states = key_states.view(
1225
+ batch_size,
1226
+ q_len,
1227
+ local_num_key_value_heads,
1228
+ self.head_dim,
1229
+ )
1230
+ key_states = key_states.transpose(1, 2)
1231
+ value_states = value_states.view(
1232
+ batch_size,
1233
+ q_len,
1234
+ local_num_key_value_heads,
1235
+ self.head_dim,
1236
+ )
1237
+ value_states = value_states.transpose(1, 2)
1238
+
1239
+ if self.use_rope:
1240
+ if position_ids is None:
1241
+ msg = "position_ids are required for rope attention."
1242
+ raise ValueError(msg)
1243
+ cos, sin = self._build_rope(
1244
+ position_ids, hidden_states.device, query_states.dtype,
1245
+ )
1246
+ query_states, key_states = _apply_rotary_pos_emb(
1247
+ query_states,
1248
+ key_states,
1249
+ cos,
1250
+ sin,
1251
+ )
1252
+
1253
+ if _is_cache_object(past_key_value):
1254
+ if use_cache:
1255
+ key_states, value_states = past_key_value.update(
1256
+ key_states,
1257
+ value_states,
1258
+ self.layer_idx,
1259
+ cache_kwargs={"cache_position": cache_position},
1260
+ )
1261
+ present_key_value = past_key_value
1262
+ elif self.layer_idx < len(past_key_value):
1263
+ past_key, past_value = past_key_value[self.layer_idx]
1264
+ if past_key is not None and past_value is not None:
1265
+ key_states = torch.cat([past_key, key_states], dim=2)
1266
+ value_states = torch.cat([past_value, value_states], dim=2)
1267
+ present_key_value = None
1268
+ else:
1269
+ present_key_value = None
1270
+ elif past_key_value is not None:
1271
+ past_key, past_value = past_key_value
1272
+ key_states = torch.cat([past_key, key_states], dim=2)
1273
+ value_states = torch.cat([past_value, value_states], dim=2)
1274
+ present_key_value = (key_states, value_states) if use_cache else None
1275
+ else:
1276
+ present_key_value = (key_states, value_states) if use_cache else None
1277
+
1278
+ attention_interface = None
1279
+ attn_impl = getattr(self.config, "_attn_implementation", "eager")
1280
+ if attn_impl == "flex_attention" and self.head_dim < 16:
1281
+ attn_impl = "sdpa"
1282
+ if attn_impl != "eager":
1283
+ attention_interface = ALL_ATTENTION_FUNCTIONS.get(attn_impl)
1284
+
1285
+ if attention_interface is not None:
1286
+ attn_output, attn_weights = attention_interface(
1287
+ self,
1288
+ query_states,
1289
+ key_states,
1290
+ value_states,
1291
+ attention_mask,
1292
+ dropout=0.0 if not self.training else self.attention_dropout,
1293
+ scaling=self.scaling,
1294
+ sliding_window=self.sliding_window,
1295
+ **kwargs,
1296
+ )
1297
+ attn_output = attn_output.contiguous()
1298
+ else:
1299
+ if local_num_key_value_heads != local_num_heads:
1300
+ local_num_key_value_groups = (
1301
+ local_num_heads // local_num_key_value_heads
1302
+ )
1303
+ key_states = key_states.repeat_interleave(
1304
+ local_num_key_value_groups, dim=1,
1305
+ )
1306
+ value_states = value_states.repeat_interleave(
1307
+ local_num_key_value_groups, dim=1,
1308
+ )
1309
+ attn_weights = torch.matmul(
1310
+ query_states,
1311
+ key_states.transpose(-1, -2),
1312
+ ) * self.scaling
1313
+ if attention_mask is not None:
1314
+ attn_weights = attn_weights + attention_mask
1315
+ attn_weights = F.softmax(attn_weights, dim=-1, dtype=torch.float32)
1316
+ attn_weights = attn_weights.to(query_states.dtype)
1317
+ attn_weights = F.dropout(
1318
+ attn_weights,
1319
+ p=self.attention_dropout if self.training else 0.0,
1320
+ training=self.training,
1321
+ )
1322
+ attn_output = torch.matmul(attn_weights, value_states)
1323
+ attn_output = attn_output.transpose(1, 2).contiguous()
1324
+
1325
+ attn_output = attn_output.reshape(batch_size, q_len, -1).contiguous()
1326
+ attn_output = self.o_proj(attn_output)
1327
+ if not output_attentions:
1328
+ attn_weights = None
1329
+ return attn_output, present_key_value, attn_weights
1330
+
1331
+
1332
+ def _refresh_attention_rope_buffers(module: nn.Module) -> None:
1333
+ """Rebuild non-persistent RoPE buffers after checkpoint load."""
1334
+
1335
+ for child in module.modules():
1336
+ if not isinstance(child, LizzyAttention):
1337
+ continue
1338
+
1339
+ should_use_rope = _get_rope_layer_flag(child.config, child.layer_idx)
1340
+ child.use_rope = should_use_rope
1341
+ if not should_use_rope:
1342
+ child._rope_requires_runtime_update = False
1343
+ child._rope_inv_freq = None
1344
+ child._rope_attention_factor = None
1345
+ continue
1346
+
1347
+ rope_scaling = dict(child.config.rope_scaling or {})
1348
+ rope_type = child._rope_type_override or str(
1349
+ rope_scaling.get("rope_type", rope_scaling.get("type", "default"))
1350
+ )
1351
+ child._rope_requires_runtime_update = rope_type == "dynamic"
1352
+ if child._rope_requires_runtime_update:
1353
+ child._rope_inv_freq = None
1354
+ child._rope_attention_factor = None
1355
+ continue
1356
+
1357
+ # These buffers are derived from config rather than serialized weights.
1358
+ # Recompute them after load so low-memory materialization cannot leave
1359
+ # stale or uninitialized rotary state behind.
1360
+ inv_freq, attention_factor = _compute_rope_parameters(
1361
+ child.config,
1362
+ device=torch.device("cpu"),
1363
+ seq_len=child.config.max_position_embeddings,
1364
+ rope_type_override=child._rope_type_override,
1365
+ )
1366
+ child._rope_inv_freq = inv_freq
1367
+ child._rope_attention_factor = torch.tensor(
1368
+ float(attention_factor),
1369
+ dtype=torch.float32,
1370
+ )
1371
+
1372
+
1373
+ class LizzyMLP(nn.Module):
1374
+ def __init__(self, config: LizzyConfig) -> None:
1375
+ super().__init__()
1376
+ self.config = config
1377
+ self.act = ACT2FN[config.hidden_act]
1378
+ self.gate_proj = (
1379
+ nn.Linear(
1380
+ config.hidden_size,
1381
+ config.intermediate_size,
1382
+ bias=config.mlp_bias,
1383
+ )
1384
+ if config.mlp_type == "gated"
1385
+ else None
1386
+ )
1387
+ self.up_proj = nn.Linear(
1388
+ config.hidden_size,
1389
+ config.intermediate_size,
1390
+ bias=config.mlp_bias,
1391
+ )
1392
+ self.down_proj = nn.Linear(
1393
+ config.intermediate_size,
1394
+ config.hidden_size,
1395
+ bias=config.mlp_bias,
1396
+ )
1397
+
1398
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
1399
+ if self.gate_proj is None and self.config.mlp_type == "gated":
1400
+ msg = "Missing gated MLP projection layers."
1401
+ raise RuntimeError(msg)
1402
+ if self.config.mlp_type == "gated":
1403
+ if self.gate_proj is None:
1404
+ msg = "Missing gated MLP projection layers."
1405
+ raise RuntimeError(msg)
1406
+ return self.down_proj(self.act(
1407
+ self.gate_proj(hidden_states)) * self.up_proj(hidden_states)
1408
+ )
1409
+ return self.down_proj(self.act(self.up_proj(hidden_states)))
1410
+
1411
+
1412
+ class LizzyDecoderLayer(nn.Module):
1413
+ def __init__(self, config: LizzyConfig, layer_idx: int) -> None:
1414
+ super().__init__()
1415
+ self.layer_type = (
1416
+ str(config.layer_types[layer_idx])
1417
+ if layer_idx < len(config.layer_types)
1418
+ else "full_attention"
1419
+ )
1420
+ self.layer_layout = _get_layer_layout(config, layer_idx)
1421
+ self.self_attn = (
1422
+ LizzyAttention(config, layer_idx)
1423
+ if self.layer_type != "linear_attention"
1424
+ else None
1425
+ )
1426
+ self.linear_attn = (
1427
+ LizzyLinearAttention(config, layer_idx)
1428
+ if self.layer_type == "linear_attention"
1429
+ else None
1430
+ )
1431
+ self.mlp = LizzyMLP(config)
1432
+
1433
+ self.pre_attn_norm = (
1434
+ _make_norm(
1435
+ config.norm_type,
1436
+ config.hidden_size,
1437
+ config.norm_eps,
1438
+ has_bias=config.norm_has_bias,
1439
+ )
1440
+ if self.layer_layout == "decoder_prenorm"
1441
+ else None
1442
+ )
1443
+ self.pre_mlp_norm = (
1444
+ _make_norm(
1445
+ config.norm_type,
1446
+ config.hidden_size,
1447
+ config.norm_eps,
1448
+ has_bias=config.norm_has_bias,
1449
+ )
1450
+ if self.layer_layout == "decoder_prenorm"
1451
+ else None
1452
+ )
1453
+ self.post_attn_norm = (
1454
+ _make_norm(
1455
+ config.norm_type,
1456
+ config.hidden_size,
1457
+ config.norm_eps,
1458
+ has_bias=config.norm_has_bias,
1459
+ )
1460
+ if self.layer_layout == "decoder_postnorm"
1461
+ else None
1462
+ )
1463
+ self.post_mlp_norm = (
1464
+ _make_norm(
1465
+ config.norm_type,
1466
+ config.hidden_size,
1467
+ config.norm_eps,
1468
+ has_bias=config.norm_has_bias
1469
+ )
1470
+ if self.layer_layout == "decoder_postnorm"
1471
+ else None
1472
+ )
1473
+
1474
+ def forward(
1475
+ self,
1476
+ hidden_states: torch.Tensor,
1477
+ attention_mask: torch.Tensor | None = None,
1478
+ position_ids: torch.Tensor | None = None,
1479
+ past_key_value: Cache | tuple[torch.Tensor, torch.Tensor] | None = None,
1480
+ cache_position: torch.Tensor | None = None,
1481
+ use_cache: bool = False,
1482
+ output_attentions: bool = False,
1483
+ **kwargs: Any,
1484
+ ) -> tuple[
1485
+ torch.Tensor,
1486
+ Cache | tuple[torch.Tensor, torch.Tensor] | None,
1487
+ torch.Tensor | None,
1488
+ ]:
1489
+ residual = hidden_states
1490
+ attn_inputs = (
1491
+ self.pre_attn_norm(hidden_states)
1492
+ if self.pre_attn_norm is not None
1493
+ else hidden_states
1494
+ )
1495
+ if self.linear_attn is not None:
1496
+ attn_output, present_key_value, attn_weights = self.linear_attn(
1497
+ attn_inputs,
1498
+ attention_mask=attention_mask,
1499
+ past_key_value=(
1500
+ past_key_value if _is_cache_object(past_key_value) else None
1501
+ ),
1502
+ use_cache=use_cache,
1503
+ output_attentions=output_attentions,
1504
+ **kwargs,
1505
+ )
1506
+ else:
1507
+ assert self.self_attn is not None
1508
+ attn_output, present_key_value, attn_weights = self.self_attn(
1509
+ attn_inputs,
1510
+ attention_mask=attention_mask,
1511
+ position_ids=position_ids,
1512
+ past_key_value=past_key_value,
1513
+ cache_position=cache_position,
1514
+ use_cache=use_cache,
1515
+ output_attentions=output_attentions,
1516
+ **kwargs,
1517
+ )
1518
+ if self.post_attn_norm is not None:
1519
+ attn_output = self.post_attn_norm(attn_output)
1520
+ hidden_states = residual + attn_output
1521
+
1522
+ residual = hidden_states
1523
+ mlp_inputs = (
1524
+ self.pre_mlp_norm(hidden_states)
1525
+ if self.pre_mlp_norm is not None
1526
+ else hidden_states
1527
+ )
1528
+ mlp_output = self.mlp(mlp_inputs)
1529
+ if self.post_mlp_norm is not None:
1530
+ mlp_output = self.post_mlp_norm(mlp_output)
1531
+ hidden_states = residual + mlp_output
1532
+ return hidden_states, present_key_value, attn_weights
1533
+
1534
+
1535
+ class LizzyPreTrainedModel(PreTrainedModel):
1536
+ config_class = LizzyConfig
1537
+ base_model_prefix = "model"
1538
+ supports_gradient_checkpointing = True
1539
+ _no_split_modules = ["LizzyDecoderLayer"]
1540
+ _skip_keys_device_placement = ["past_key_values"]
1541
+ _supports_flash_attn = True
1542
+ _supports_sdpa = True
1543
+ _supports_flex_attn = True
1544
+ _supports_attention_backend = True
1545
+
1546
+ def _init_weights(self, module: nn.Module) -> None:
1547
+ std = self.config.initializer_range
1548
+ if isinstance(module, nn.Linear):
1549
+ module.weight.data.normal_(mean=0.0, std=std)
1550
+ if module.bias is not None:
1551
+ module.bias.data.zero_()
1552
+ elif isinstance(module, nn.Embedding):
1553
+ module.weight.data.normal_(mean=0.0, std=std)
1554
+ if module.padding_idx is not None:
1555
+ module.weight.data[module.padding_idx].zero_()
1556
+ elif isinstance(module, (LizzyRMSNorm, nn.LayerNorm)):
1557
+ if hasattr(module, "weight") and module.weight is not None:
1558
+ module.weight.data.fill_(1.0)
1559
+ if hasattr(module, "bias") and module.bias is not None:
1560
+ module.bias.data.zero_()
1561
+
1562
+ @classmethod
1563
+ def from_pretrained(
1564
+ cls,
1565
+ pretrained_model_name_or_path: str | os.PathLike[str] | None,
1566
+ *model_args: Any,
1567
+ **kwargs: Any,
1568
+ ) -> "LizzyPreTrainedModel":
1569
+ model = cast(
1570
+ "LizzyPreTrainedModel",
1571
+ super().from_pretrained(
1572
+ pretrained_model_name_or_path,
1573
+ *model_args,
1574
+ **kwargs,
1575
+ ),
1576
+ )
1577
+ _refresh_attention_rope_buffers(model)
1578
+ if hasattr(model, "lm_head") and hasattr(model, "model"):
1579
+ tied_weights_keys = getattr(type(model), "_tied_weights_keys", None)
1580
+ if isinstance(tied_weights_keys, dict) and tied_weights_keys:
1581
+ model._tied_weights_keys = dict(tied_weights_keys)
1582
+ else:
1583
+ model._tied_weights_keys = {
1584
+ "lm_head.weight": "model.embed_tokens.weight",
1585
+ }
1586
+ model._tp_plan = {"lm_head": "colwise_rep"}
1587
+ model._pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
1588
+ return model
1589
+
1590
+ def load_state_dict( # type: ignore[override]
1591
+ self,
1592
+ state_dict: dict[str, torch.Tensor],
1593
+ strict: bool = True,
1594
+ assign: bool = False,
1595
+ ) -> Any:
1596
+ remapped_state_dict: dict[str, torch.Tensor] = {}
1597
+ for key, value in state_dict.items():
1598
+ remapped_key = key
1599
+ if ".mlp.fc_in." in key:
1600
+ remapped_key = key.replace(".mlp.fc_in.", ".mlp.up_proj.")
1601
+ elif ".mlp.fc_out." in key:
1602
+ remapped_key = key.replace(".mlp.fc_out.", ".mlp.down_proj.")
1603
+
1604
+ existing = remapped_state_dict.get(remapped_key)
1605
+ if existing is not None and not torch.equal(existing, value):
1606
+ msg = (
1607
+ f"Conflicting legacy Lizzy MLP tensors"
1608
+ f" for key: {remapped_key}"
1609
+ )
1610
+ raise ValueError(msg)
1611
+ remapped_state_dict[remapped_key] = value
1612
+
1613
+ load_result = super().load_state_dict(
1614
+ remapped_state_dict,
1615
+ strict=strict,
1616
+ assign=assign,
1617
+ )
1618
+ # RoPE buffers are intentionally non-persistent, so refresh them after
1619
+ # weight loading instead of trusting constructor-time allocations.
1620
+ _refresh_attention_rope_buffers(self)
1621
+ return load_result
1622
+
1623
+
1624
+ class LizzyModel(LizzyPreTrainedModel):
1625
+ def __init__(self, config: LizzyConfig) -> None:
1626
+ super().__init__(config)
1627
+ self.padding_idx = config.pad_token_id
1628
+ self.vocab_size = config.vocab_size
1629
+ self.embed_tokens = nn.Embedding(
1630
+ config.vocab_size,
1631
+ config.hidden_size,
1632
+ self.padding_idx,
1633
+ )
1634
+ self.embed_positions = (
1635
+ nn.Embedding(config.max_position_embeddings, config.hidden_size)
1636
+ if config.position_embedding_type == "absolute"
1637
+ else None
1638
+ )
1639
+ self.layers = nn.ModuleList(
1640
+ LizzyDecoderLayer(config, layer_idx)
1641
+ for layer_idx in range(config.num_hidden_layers)
1642
+ )
1643
+ self.norm = _make_norm(
1644
+ config.norm_type,
1645
+ config.hidden_size,
1646
+ config.norm_eps,
1647
+ has_bias=config.norm_has_bias,
1648
+ )
1649
+ self.embd_dropout = nn.Dropout(config.embd_dropout)
1650
+ self.gradient_checkpointing = False
1651
+ self.post_init()
1652
+
1653
+ def get_input_embeddings(self) -> nn.Embedding:
1654
+ return self.embed_tokens
1655
+
1656
+ def set_input_embeddings(self, value: nn.Embedding) -> None:
1657
+ self.embed_tokens = value
1658
+
1659
+ def _build_attention_mask(
1660
+ self,
1661
+ attention_mask: torch.Tensor | None,
1662
+ *,
1663
+ batch_size: int,
1664
+ q_len: int,
1665
+ kv_len: int,
1666
+ kv_offset: int,
1667
+ cache_position: torch.Tensor,
1668
+ device: torch.device,
1669
+ dtype: torch.dtype,
1670
+ sliding_window: int | None = None,
1671
+ ) -> torch.Tensor:
1672
+ kv_len = (
1673
+ int(kv_len.item()) if isinstance(kv_len, torch.Tensor) else int(kv_len)
1674
+ )
1675
+ kv_offset = (
1676
+ int(kv_offset.item())
1677
+ if isinstance(kv_offset, torch.Tensor)
1678
+ else int(kv_offset)
1679
+ )
1680
+ min_value = torch.finfo(dtype).min
1681
+ source_positions = cache_position.to(device=device).view(-1, 1)
1682
+ target_positions = torch.arange(
1683
+ kv_offset,
1684
+ kv_offset + kv_len,
1685
+ device=device,
1686
+ ).unsqueeze(0)
1687
+ causal = torch.zeros((q_len, kv_len), dtype=dtype, device=device)
1688
+ causal = causal.masked_fill(target_positions > source_positions, min_value)
1689
+ if sliding_window is not None:
1690
+ lower_bound = source_positions - int(sliding_window) + 1
1691
+ causal = causal.masked_fill(target_positions < lower_bound, min_value)
1692
+ causal = causal.unsqueeze(0).unsqueeze(0).expand(batch_size, 1, -1, -1)
1693
+
1694
+ if attention_mask is None:
1695
+ return causal
1696
+
1697
+ if attention_mask.dim() != 2:
1698
+ msg = "attention_mask must be 2D [batch, sequence]."
1699
+ raise ValueError(msg)
1700
+ if attention_mask.shape[1] < kv_len:
1701
+ pad = torch.ones(
1702
+ (attention_mask.shape[0], kv_len - attention_mask.shape[1]),
1703
+ dtype=attention_mask.dtype,
1704
+ device=attention_mask.device,
1705
+ )
1706
+ attention_mask = torch.cat([pad, attention_mask], dim=1)
1707
+ elif attention_mask.shape[1] > kv_len:
1708
+ attention_mask = attention_mask[:, -kv_len:]
1709
+
1710
+ expanded = attention_mask[:, None, None, :].to(device=device)
1711
+ padding = (expanded == 0).to(dtype) * min_value
1712
+ return causal + padding
1713
+
1714
+ def forward(
1715
+ self,
1716
+ input_ids: torch.LongTensor | None = None,
1717
+ attention_mask: torch.Tensor | dict[str, torch.Tensor] | None = None,
1718
+ position_ids: torch.LongTensor | None = None,
1719
+ past_key_values: Cache | tuple[
1720
+ tuple[torch.Tensor, torch.Tensor], ...
1721
+ ] | None = None,
1722
+ inputs_embeds: torch.FloatTensor | None = None,
1723
+ cache_position: torch.LongTensor | None = None,
1724
+ use_cache: bool | None = None,
1725
+ output_attentions: bool | None = None,
1726
+ output_hidden_states: bool | None = None,
1727
+ return_dict: bool | None = None,
1728
+ **kwargs: Any,
1729
+ ) -> BaseModelOutputWithPast | tuple[Any, ...]:
1730
+ if (input_ids is None) == (inputs_embeds is None):
1731
+ msg = "Exactly one of input_ids or inputs_embeds must be provided."
1732
+ raise ValueError(msg)
1733
+
1734
+ output_attentions = (
1735
+ bool(output_attentions) if output_attentions is not None else False
1736
+ )
1737
+ output_hidden_states = (
1738
+ bool(output_hidden_states)
1739
+ if output_hidden_states is not None
1740
+ else False
1741
+ )
1742
+ use_cache = (
1743
+ bool(use_cache)
1744
+ if use_cache is not None
1745
+ else bool(self.config.use_cache)
1746
+ )
1747
+ return_dict = bool(return_dict) if return_dict is not None else True
1748
+
1749
+ if inputs_embeds is None:
1750
+ hidden_states = self.embed_tokens(input_ids)
1751
+ batch_size, seq_len = input_ids.shape
1752
+ else:
1753
+ hidden_states = inputs_embeds
1754
+ batch_size, seq_len, _ = inputs_embeds.shape
1755
+
1756
+ cache_object = (
1757
+ past_key_values
1758
+ if _is_cache_object(past_key_values)
1759
+ else None
1760
+ )
1761
+ if use_cache and _has_linear_attention(self.config):
1762
+ # Transformers 5.4 seeds `generate()` with an empty DynamicCache
1763
+ # for standard causal decoders. Hybrid Lizzy checkpoints need the
1764
+ # mixed cache below instead, because linear-attention layers read
1765
+ # DeltaNet convolution/recurrent state during the prefill pass.
1766
+ if cache_object is not None and not isinstance(
1767
+ cache_object, LizzyHybridDynamicCache,
1768
+ ):
1769
+ if int(cache_object.get_seq_length()) > 0:
1770
+ msg = (
1771
+ "Hybrid Lizzy checkpoints require "
1772
+ "LizzyHybridDynamicCache once generation cache "
1773
+ "state is populated."
1774
+ )
1775
+ raise ValueError(msg)
1776
+ cache_object = LizzyHybridDynamicCache(config=self.config)
1777
+ past_key_values = cache_object
1778
+ if use_cache and cache_object is None and past_key_values is None:
1779
+ if _has_linear_attention(self.config):
1780
+ # Linear-attention checkpoints need a mixed cache that can hold
1781
+ # both KV tensors and recurrent DeltaNet state.
1782
+ cache_object = LizzyHybridDynamicCache(config=self.config)
1783
+ else:
1784
+ cache_object = DynamicCache()
1785
+ past_key_values = cache_object
1786
+
1787
+ if cache_object is not None:
1788
+ past_length = int(cache_object.get_seq_length())
1789
+ else:
1790
+ past_length = _legacy_cache_length(past_key_values)
1791
+
1792
+ cache_position = _normalize_cache_position(cache_position)
1793
+ if cache_position is None:
1794
+ cache_position = torch.arange(
1795
+ past_length,
1796
+ past_length + seq_len,
1797
+ dtype=torch.long,
1798
+ device=hidden_states.device,
1799
+ )
1800
+
1801
+ if position_ids is None:
1802
+ position_ids = cache_position.unsqueeze(0).expand(batch_size, -1)
1803
+
1804
+ if self.embed_positions is not None:
1805
+ hidden_states = hidden_states + self.embed_positions(position_ids)
1806
+
1807
+ hidden_states = self.embd_dropout(hidden_states)
1808
+
1809
+ if self.training and self.gradient_checkpointing:
1810
+ use_cache = False
1811
+
1812
+ layer_types = list(self.config.layer_types)
1813
+ if not layer_types:
1814
+ layer_types = ["full_attention"] * len(self.layers)
1815
+ has_linear_attention = any(
1816
+ str(layer_type) == "linear_attention" for layer_type in layer_types
1817
+ )
1818
+
1819
+ _attn_impl = getattr(self.config, "_attn_implementation", "eager")
1820
+ if has_linear_attention and isinstance(attention_mask, dict):
1821
+ linear_attention_mask = attention_mask.get("linear_attention")
1822
+ else:
1823
+ linear_attention_mask = attention_mask
1824
+ if (
1825
+ has_linear_attention
1826
+ and cache_object is not None
1827
+ and getattr(cache_object, "has_previous_state", False)
1828
+ ):
1829
+ linear_attention_mask = None
1830
+ elif (
1831
+ has_linear_attention
1832
+ and attention_mask is not None
1833
+ and not isinstance(attention_mask, dict)
1834
+ and torch.all(attention_mask == 1)
1835
+ ):
1836
+ linear_attention_mask = None
1837
+
1838
+ if (
1839
+ _attn_impl == "flash_attention_2"
1840
+ and not isinstance(attention_mask, dict)
1841
+ ):
1842
+ # Flash attention handles causal masking (via is_causal) and
1843
+ # padding (via 2D mask) natively; skip building a 4D mask.
1844
+ attention_mask_mapping = {
1845
+ lt: attention_mask
1846
+ for lt in dict.fromkeys(layer_types)
1847
+ if lt != "linear_attention"
1848
+ }
1849
+ elif _attn_impl == "sdpa" and attention_mask is None:
1850
+ attention_mask_mapping = {}
1851
+ for layer_type in dict.fromkeys(layer_types):
1852
+ if layer_type == "linear_attention":
1853
+ continue
1854
+ if layer_type == "full_attention":
1855
+ # Match upstream decoder-only HF models: when SDPA sees
1856
+ # plain causal full attention with no padding mask to
1857
+ # preserve, let it use its native is_causal fast-path
1858
+ # instead of forcing an explicit 4D bias tensor.
1859
+ attention_mask_mapping[layer_type] = None
1860
+ continue
1861
+ layer_idx = layer_types.index(layer_type)
1862
+ if cache_object is not None:
1863
+ kv_len, kv_offset = cache_object.get_mask_sizes(
1864
+ seq_len, layer_idx,
1865
+ )
1866
+ else:
1867
+ kv_len = past_length + seq_len
1868
+ kv_offset = 0
1869
+ attention_mask_mapping[layer_type] = self._build_attention_mask(
1870
+ attention_mask,
1871
+ batch_size=batch_size,
1872
+ q_len=seq_len,
1873
+ kv_len=kv_len,
1874
+ kv_offset=kv_offset,
1875
+ cache_position=cache_position,
1876
+ device=hidden_states.device,
1877
+ dtype=hidden_states.dtype,
1878
+ sliding_window=(
1879
+ self.config.sliding_window
1880
+ if layer_type == "sliding_attention"
1881
+ else None
1882
+ ),
1883
+ )
1884
+ elif isinstance(attention_mask, dict):
1885
+ attention_mask_mapping = {
1886
+ key: value
1887
+ for key, value in attention_mask.items()
1888
+ if key != "linear_attention"
1889
+ }
1890
+ else:
1891
+ attention_mask_mapping: dict[str, torch.Tensor] = {}
1892
+ for layer_type in dict.fromkeys(layer_types):
1893
+ if layer_type == "linear_attention":
1894
+ continue
1895
+ layer_idx = layer_types.index(layer_type)
1896
+ if cache_object is not None:
1897
+ kv_len, kv_offset = cache_object.get_mask_sizes(
1898
+ seq_len, layer_idx,
1899
+ )
1900
+ else:
1901
+ kv_len = past_length + seq_len
1902
+ kv_offset = 0
1903
+ attention_mask_mapping[layer_type] = self._build_attention_mask(
1904
+ attention_mask,
1905
+ batch_size=batch_size,
1906
+ q_len=seq_len,
1907
+ kv_len=kv_len,
1908
+ kv_offset=kv_offset,
1909
+ cache_position=cache_position,
1910
+ device=hidden_states.device,
1911
+ dtype=hidden_states.dtype,
1912
+ sliding_window=(
1913
+ self.config.sliding_window
1914
+ if layer_type == "sliding_attention"
1915
+ else None
1916
+ ),
1917
+ )
1918
+
1919
+ all_hidden_states = [] if output_hidden_states else None
1920
+ all_attentions = [] if output_attentions else None
1921
+ next_cache = (
1922
+ cache_object
1923
+ if cache_object is not None
1924
+ else ([] if use_cache else None)
1925
+ )
1926
+ gradient_checkpointing_func = getattr(
1927
+ self,
1928
+ "_gradient_checkpointing_func",
1929
+ checkpoint,
1930
+ )
1931
+
1932
+ for idx, layer in enumerate(self.layers):
1933
+ if output_hidden_states and all_hidden_states is not None:
1934
+ all_hidden_states.append(hidden_states)
1935
+ layer_type = (
1936
+ layer_types[idx]
1937
+ if idx < len(layer_types)
1938
+ else "full_attention"
1939
+ )
1940
+ if layer_type == "linear_attention":
1941
+ layer_attention_mask = linear_attention_mask
1942
+ else:
1943
+ layer_attention_mask = attention_mask_mapping[layer_type]
1944
+
1945
+ if cache_object is not None:
1946
+ layer_past: Cache | tuple[
1947
+ torch.Tensor, torch.Tensor
1948
+ ] | None = cache_object
1949
+ elif past_key_values is not None:
1950
+ layer_past = past_key_values[idx]
1951
+ if layer_past is not None and layer_past[0] is None:
1952
+ layer_past = None
1953
+ else:
1954
+ layer_past = None
1955
+
1956
+ if self.training and self.gradient_checkpointing:
1957
+ def custom_forward(hidden_states: torch.Tensor) -> Any:
1958
+ layer_outputs = layer(
1959
+ hidden_states,
1960
+ attention_mask=layer_attention_mask,
1961
+ position_ids=position_ids,
1962
+ past_key_value=None,
1963
+ cache_position=cache_position,
1964
+ use_cache=False,
1965
+ output_attentions=output_attentions,
1966
+ **kwargs,
1967
+ )
1968
+ if output_attentions:
1969
+ return layer_outputs[0], layer_outputs[2]
1970
+ return layer_outputs[0]
1971
+
1972
+ checkpointed_outputs = gradient_checkpointing_func(
1973
+ custom_forward, hidden_states,
1974
+ )
1975
+ if output_attentions:
1976
+ hidden_states, attn_weights = checkpointed_outputs
1977
+ else:
1978
+ hidden_states = checkpointed_outputs
1979
+ attn_weights = None
1980
+ present = None
1981
+ else:
1982
+ hidden_states, present, attn_weights = layer(
1983
+ hidden_states,
1984
+ attention_mask=layer_attention_mask,
1985
+ position_ids=position_ids,
1986
+ past_key_value=layer_past,
1987
+ cache_position=cache_position,
1988
+ use_cache=use_cache,
1989
+ output_attentions=output_attentions,
1990
+ **kwargs,
1991
+ )
1992
+ if use_cache and next_cache is not None and cache_object is None:
1993
+ next_cache.append(present)
1994
+
1995
+ if output_attentions and all_attentions is not None:
1996
+ all_attentions.append(attn_weights)
1997
+
1998
+ hidden_states = self.norm(hidden_states)
1999
+ if output_hidden_states and all_hidden_states is not None:
2000
+ all_hidden_states.append(hidden_states)
2001
+
2002
+ past_key_values_output: Cache | tuple[
2003
+ tuple[torch.Tensor, torch.Tensor], ...
2004
+ ] | None = None
2005
+ if use_cache and next_cache is not None:
2006
+ if cache_object is not None:
2007
+ past_key_values_output = cache_object
2008
+ else:
2009
+ past_key_values_output = tuple(next_cache)
2010
+
2011
+ if not return_dict:
2012
+ output: tuple[Any, ...] = (hidden_states,)
2013
+ if past_key_values_output is not None:
2014
+ output = output + (past_key_values_output,)
2015
+ if output_hidden_states and all_hidden_states is not None:
2016
+ output = output + (tuple(all_hidden_states),)
2017
+ if output_attentions and all_attentions is not None:
2018
+ output = output + (tuple(all_attentions),)
2019
+ return output
2020
+
2021
+ return BaseModelOutputWithPast(
2022
+ last_hidden_state=hidden_states,
2023
+ past_key_values=past_key_values_output,
2024
+ hidden_states=(
2025
+ tuple(all_hidden_states)
2026
+ if all_hidden_states is not None
2027
+ else None
2028
+ ),
2029
+ attentions=(
2030
+ tuple(all_attentions)
2031
+ if all_attentions is not None
2032
+ else None
2033
+ ),
2034
+ )
2035
+
2036
+
2037
+ class LizzyForCausalLM(LizzyPreTrainedModel, GenerationMixin):
2038
+ config_class = LizzyConfig
2039
+ # Transformers 5.4 expects an expanded target->source mapping here rather than
2040
+ # the older list-based shorthand.
2041
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
2042
+ _tp_plan = {"lm_head": "colwise_rep"}
2043
+ _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
2044
+
2045
+ def __init__(self, config: LizzyConfig) -> None:
2046
+ super().__init__(config)
2047
+ self.model = LizzyModel(config)
2048
+ self.vocab_size = config.vocab_size
2049
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
2050
+ self.post_init()
2051
+
2052
+ def get_input_embeddings(self) -> nn.Embedding:
2053
+ return self.model.get_input_embeddings()
2054
+
2055
+ def set_input_embeddings(self, value: nn.Embedding) -> None:
2056
+ self.model.set_input_embeddings(value)
2057
+
2058
+ def get_output_embeddings(self) -> nn.Module:
2059
+ return self.lm_head
2060
+
2061
+ def set_output_embeddings(self, new_embeddings: nn.Module) -> None:
2062
+ self.lm_head = new_embeddings
2063
+
2064
+ def prepare_inputs_for_generation(
2065
+ self,
2066
+ input_ids: torch.LongTensor,
2067
+ past_key_values: Cache | tuple[
2068
+ tuple[torch.Tensor, torch.Tensor], ...
2069
+ ] | None = None,
2070
+ attention_mask: torch.Tensor | None = None,
2071
+ inputs_embeds: torch.FloatTensor | None = None,
2072
+ cache_position: torch.LongTensor | None = None,
2073
+ **kwargs: Any,
2074
+ ) -> dict[str, Any]:
2075
+ past_length = 0
2076
+ if past_key_values is not None:
2077
+ if _is_cache_object(past_key_values):
2078
+ past_length = int(past_key_values.get_seq_length())
2079
+ else:
2080
+ past_length = _legacy_cache_length(past_key_values)
2081
+
2082
+ cache_position = _normalize_cache_position(cache_position)
2083
+ if cache_position is None:
2084
+ if past_key_values is not None:
2085
+ new_tokens = input_ids.shape[1] - past_length
2086
+ if new_tokens <= 0:
2087
+ new_tokens = 1
2088
+ cache_position = torch.arange(
2089
+ past_length,
2090
+ past_length + new_tokens,
2091
+ device=input_ids.device,
2092
+ )
2093
+ else:
2094
+ cache_position = torch.arange(
2095
+ input_ids.shape[1],
2096
+ device=input_ids.device,
2097
+ )
2098
+
2099
+ if past_key_values is not None:
2100
+ input_ids = input_ids[:, -cache_position.shape[0] :]
2101
+ if attention_mask is not None:
2102
+ attn_mask_idx = (past_length + input_ids.shape[1])
2103
+ attention_mask = attention_mask[:, -attn_mask_idx :]
2104
+
2105
+ if inputs_embeds is not None and past_key_values is None:
2106
+ model_inputs: dict[str, Any] = {"inputs_embeds": inputs_embeds}
2107
+ else:
2108
+ model_inputs = {"input_ids": input_ids.contiguous()}
2109
+
2110
+ model_inputs.update(
2111
+ {
2112
+ "past_key_values": past_key_values,
2113
+ "attention_mask": attention_mask,
2114
+ "cache_position": cache_position,
2115
+ "use_cache": kwargs.get("use_cache", self.config.use_cache),
2116
+ },
2117
+ )
2118
+ return model_inputs
2119
+
2120
+ def forward(
2121
+ self,
2122
+ input_ids: torch.LongTensor | None = None,
2123
+ attention_mask: torch.Tensor | None = None,
2124
+ position_ids: torch.LongTensor | None = None,
2125
+ past_key_values: Cache | tuple[
2126
+ tuple[torch.Tensor, torch.Tensor], ...
2127
+ ] | None = None,
2128
+ inputs_embeds: torch.FloatTensor | None = None,
2129
+ labels: torch.LongTensor | None = None,
2130
+ cache_position: torch.LongTensor | None = None,
2131
+ use_cache: bool | None = None,
2132
+ output_attentions: bool | None = None,
2133
+ output_hidden_states: bool | None = None,
2134
+ return_dict: bool | None = None,
2135
+ logits_to_keep: int | torch.Tensor = 0,
2136
+ **kwargs: Any,
2137
+ ) -> CausalLMOutputWithPast | tuple[Any, ...]:
2138
+ # HF eval loaders call `forward()` without an explicit return_dict,
2139
+ # so local Lizzy exports must normalize the optional flag first.
2140
+ return_dict = bool(return_dict) if return_dict is not None else True
2141
+
2142
+ outputs = self.model(
2143
+ input_ids=input_ids,
2144
+ attention_mask=attention_mask,
2145
+ position_ids=position_ids,
2146
+ past_key_values=past_key_values,
2147
+ inputs_embeds=inputs_embeds,
2148
+ cache_position=cache_position,
2149
+ use_cache=use_cache,
2150
+ output_attentions=output_attentions,
2151
+ output_hidden_states=output_hidden_states,
2152
+ return_dict=return_dict,
2153
+ **kwargs,
2154
+ )
2155
+
2156
+ hidden_states = outputs[0] if not return_dict else outputs.last_hidden_state
2157
+ slice_indices = (
2158
+ slice(-logits_to_keep, None)
2159
+ if isinstance(logits_to_keep, int)
2160
+ else logits_to_keep
2161
+ )
2162
+ if labels is not None:
2163
+ full_logits = self.lm_head(hidden_states)
2164
+ logits = full_logits[:, slice_indices, :]
2165
+ else:
2166
+ full_logits = None
2167
+ logits = self.lm_head(hidden_states[:, slice_indices, :])
2168
+
2169
+ loss = None
2170
+ if labels is not None:
2171
+ shift_logits = full_logits[..., :-1, :].contiguous()
2172
+ shift_labels = labels[..., 1:].contiguous()
2173
+ loss = F.cross_entropy(
2174
+ shift_logits.view(-1, shift_logits.size(-1)),
2175
+ shift_labels.view(-1),
2176
+ )
2177
+
2178
+ if not return_dict:
2179
+ output = (logits,) + outputs[1:]
2180
+ if loss is not None:
2181
+ output = (loss,) + output
2182
+ return output
2183
+
2184
+ return CausalLMOutputWithPast(
2185
+ loss=loss,
2186
+ logits=logits,
2187
+ past_key_values=outputs.past_key_values,
2188
+ hidden_states=outputs.hidden_states,
2189
+ attentions=outputs.attentions,
2190
+ )
quickstart.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Minimal inference example for the private Lizzy 7B checkpoint."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import os
7
+
8
+
9
+ def main() -> None:
10
+ repo_id = os.getenv("FLOWER_MODEL_ID", "flwrlabs/Lizzy-7B")
11
+ print("Model ID:", repo_id)
12
+ print(
13
+ "Data note:",
14
+ "Flower release drafts should always disclose that Flower/Lizzy variants add private synthetic data during both pre-training and post-training to favour British behaviour and knowledge. Those private synthetic datasets are not redistributed in the release pack.",
15
+ )
16
+ print("HF_TOKEN present:", bool(os.getenv("HF_TOKEN")))
17
+ print("This example is intentionally non-executing by default.")
18
+ print("Use one of the snippets below after installing transformers or vLLM:")
19
+ print()
20
+ print("Transformers:")
21
+ print(
22
+ " tokenizer = AutoTokenizer.from_pretrained(repo_id, trust_remote_code=True)"
23
+ )
24
+ print(
25
+ " model = AutoModelForCausalLM.from_pretrained(repo_id, trust_remote_code=True, torch_dtype='auto')"
26
+ )
27
+ print()
28
+ print("vLLM:")
29
+ print(
30
+ " python -m vllm.entrypoints.openai.api_server --model "
31
+ "flwrlabs/Lizzy-7B --trust-remote-code --max-model-len 8192"
32
+ )
33
+
34
+
35
+ if __name__ == "__main__":
36
+ main()
quickstart_cli.sh ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ MODEL_ID="${FLOWER_MODEL_ID:-flwrlabs/Lizzy-7B}"
5
+
6
+ echo "HF_TOKEN set: ${HF_TOKEN:+yes}"
7
+ echo "Model: $MODEL_ID"
8
+ echo "Data note: Flower release drafts should always disclose that Flower/Lizzy variants add private synthetic data during both pre-training and post-training to favour British behaviour and knowledge. Those private synthetic datasets are not redistributed in the release pack."
9
+ echo
10
+ echo "Transformers example:"
11
+ echo "python - <<'PY'"
12
+ echo "from transformers import AutoTokenizer, AutoModelForCausalLM"
13
+ echo "repo_id = 'flwrlabs/Lizzy-7B'"
14
+ echo "tokenizer = AutoTokenizer.from_pretrained(repo_id, trust_remote_code=True)"
15
+ echo "model = AutoModelForCausalLM.from_pretrained(repo_id, trust_remote_code=True, torch_dtype='auto')"
16
+ echo "PY"
17
+ echo
18
+ echo "vLLM serve example:"
19
+ echo "python -m vllm.entrypoints.openai.api_server --model $MODEL_ID --trust-remote-code --max-model-len 8192"
special_tokens_map.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": "<|endoftext|>",
3
+ "eos_token": "<|endoftext|>",
4
+ "pad_token": "<|pad|>",
5
+ "unk_token": "<|endoftext|>"
6
+ }
tokenization_lizzy.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from transformers import PreTrainedTokenizerFast
8
+
9
+
10
+ class LizzyTokenizerFast(PreTrainedTokenizerFast):
11
+ """Family-agnostic fast tokenizer wrapper for Lizzy checkpoints."""
12
+
13
+ model_input_names = ["input_ids", "attention_mask"]
14
+
15
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
16
+ preserved_keys = (
17
+ "add_prefix_space",
18
+ "add_bos_token",
19
+ "add_eos_token",
20
+ "clean_up_tokenization_spaces",
21
+ "use_default_system_prompt",
22
+ "legacy",
23
+ "fix_mistral_regex",
24
+ )
25
+ preserved_init_attrs = {
26
+ key: kwargs.get(key)
27
+ for key in preserved_keys
28
+ if key in kwargs
29
+ }
30
+ super().__init__(*args, **kwargs)
31
+ init_kwargs = getattr(self, "init_kwargs", {})
32
+ local_payload: dict[str, Any] = {}
33
+ config_path = (
34
+ Path(str(getattr(self, "name_or_path", ""))) / "tokenizer_config.json"
35
+ )
36
+ if config_path.is_file():
37
+ try:
38
+ local_payload = json.loads(config_path.read_text(encoding="utf-8"))
39
+ except Exception:
40
+ local_payload = {}
41
+ for key in preserved_keys:
42
+ value = preserved_init_attrs.get(key, init_kwargs.get(key))
43
+ if value is None:
44
+ value = local_payload.get(key)
45
+ if value is not None:
46
+ setattr(self, key, value)
47
+
48
+ @property
49
+ def all_special_tokens_extended(self) -> list[str]:
50
+ """Compatibility shim for runtimes still expecting the pre-5.4 API."""
51
+ return list(self.all_special_tokens)
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_eos_token": false,
4
+ "add_prefix_space": false,
5
+ "backend": "tokenizers",
6
+ "bos_token": "<|endoftext|>",
7
+ "chat_template": "\\\n {# \u2500\u2500\u2500\u2500\u2500 defaults \u2500\u2500\u2500\u2500\u2500 #}\n {%- if enable_thinking is not defined -%}\n {%- set enable_thinking = true -%}\n {%- endif -%}\n {%- set system_message = \"\" -%}\n {%- set custom_instructions = \"\" -%}\n {%- set identity_preamble = \"You are Lizzy, a helpful British AI assistant built by Flower Labs. When asked about your identity, name, developer, or origin, answer consistently: your name is Lizzy, you were built by Flower Labs, and you are not ChatGPT, DeepSeek, Claude, Gemini, or any other assistant. Do not misattribute your creator or model family.\" -%}\n {%- set default_think_instructions = \"You are a helpful British function-calling AI assistant. You are a British persona and your date cutoff is November 2024, and your model weights are available at https://huggingface.co/flwrlabs. Your role as an assistant involves thoroughly exploring questions through a systematic thinking process before providing the final precise and accurate solutions. This requires engaging in a comprehensive cycle of analysis, summarizing, exploration, reassessment, reflection, backtracking, and iteration to develop well-considered thinking process. Please structure your response into two main sections: Thought and Solution using the specified format: <tool_call> Thought section </tool_call> Solution section. In the Thought section, detail your reasoning process in steps. Each step should include detailed considerations such as analysing questions, summarizing relevant findings, brainstorming new ideas, verifying the accuracy of the current steps, refining any errors, and revisiting previous steps. In the Solution section, based on various attempts, explorations, and reflections from the Thought section, systematically present the final solution that you deem correct. The Solution section should be logical, accurate, and concise and detail necessary steps needed to reach the conclusion.\" -%}\n {%- set default_no_think_instructions = \"You are a helpful British function-calling AI assistant. You are a British persona and your date cutoff is November 2024, and your model weights are available at https://huggingface.co/flwrlabs.\" -%}\n\n {# \u2500\u2500\u2500\u2500\u2500 reasoning mode \u2500\u2500\u2500\u2500\u2500 #}\n {%- if enable_thinking -%}\n {%- set reasoning_mode = \"/think\" -%}\n {%- else -%}\n {%- set reasoning_mode = \"/no_think\" -%}\n {%- endif -%}\n\n {# \u2500\u2500\u2500\u2500\u2500 header (system message) \u2500\u2500\u2500\u2500\u2500 #}\n {{- \"<|im_start|>system\\n\" -}}\n\n {%- if messages[0].role == \"system\" -%}\n {%- set system_message = messages[0].content -%}\n {%- if \"/no_think\" in system_message -%}\n {%- set reasoning_mode = \"/no_think\" -%}\n {%- elif \"/think\" in system_message -%}\n {%- set reasoning_mode = \"/think\" -%}\n {%- endif -%}\n {%- set custom_instructions = system_message.replace(\"/no_think\", \"\").replace(\"/think\", \"\").rstrip() -%}\n {%- endif -%}\n\n {%- if \"/system_override\" in system_message -%}\n {{- identity_preamble + \"\\n\\n\" -}}\n {{- custom_instructions.replace(\"/system_override\", \"\").rstrip() -}}\n {{- \"<|im_end|>\\n\" -}}\n {%- else -%}\n {{- \"## Metadata\\n\\n\" -}}\n {{- \"Knowledge Cutoff Date: June 2025\\n\" -}}\n {%- set today = strftime_now(\"%d %B %Y\") -%}\n {{- \"Today Date: \" ~ today ~ \"\\n\" -}}\n {{- \"Reasoning Mode: \" + reasoning_mode + \"\\n\\n\" -}}\n\n {{- \"## Identity\\n\\n\" -}}\n {{- identity_preamble + \"\\n\\n\" -}}\n\n {{- \"## Custom Instructions\\n\\n\" -}}\n {%- if custom_instructions -%}\n {{- custom_instructions + \"\\n\\n\" -}}\n {%- elif reasoning_mode == \"/think\" -%}\n {{- default_think_instructions + \"\\n\\n\" -}}\n {%- else -%}\n {{- default_no_think_instructions + \"\\n\\n\" -}}\n {%- endif -%}\n\n {%- if xml_tools or python_tools or tools -%}\n {{- \"### Tools\\n\\n\" -}}\n {%- if xml_tools or tools -%}\n {%- if tools -%}\n {%- set xml_tools = tools -%}\n {%- endif -%}\n {%- set ns = namespace(xml_tool_string=\"You may call one or more functions to assist with the user query.\\nYou are provided with function signatures within <tools></tools> XML tags:\\n\\n<tools>\\n\") -%}\n {%- for tool in xml_tools[:] -%} {# The slicing makes sure that xml_tools is a list #}\n {%- set ns.xml_tool_string = ns.xml_tool_string ~ (tool | string) ~ \"\\n\" -%}\n {%- endfor -%}\n {%- set xml_tool_string = ns.xml_tool_string + \"</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call>\" -%}\n {{- xml_tool_string -}}\n {%- endif -%}\n {%- if python_tools -%}\n {%- set ns = namespace(python_tool_string=\"When you send a message containing Python code between '<code>' and '</code>' tags, it will be executed in a stateful Jupyter notebook environment, and you will then be given the output to continued reasoning in an agentic loop.\\n\\nYou can use the following tools in your python code like regular functions:\\n<tools>\\n\") -%}\n {%- for tool in python_tools[:] -%} {# The slicing makes sure that python_tools is a list #}\n {%- set ns.python_tool_string = ns.python_tool_string ~ (tool | string) ~ \"\\n\" -%}\n {%- endfor -%}\n {%- set python_tool_string = ns.python_tool_string + \"</tools>\\n\\nThe state persists between code executions: so variables that you define in one step are still available thereafter.\" -%}\n {{- python_tool_string -}}\n {%- endif -%}\n {{- \"\\n\\n\" -}}\n {{- \"<|im_end|>\\n\" -}}\n {%- endif -%}\n {%- endif -%}\n {# \u2500\u2500\u2500\u2500\u2500 main loop \u2500\u2500\u2500\u2500\u2500 #}\n {%- for message in messages -%}\n {%- set content = message.content if message.content is string else \"\" -%}\n {%- if message.role == \"user\" -%}\n {{ \"<|im_start|>\" + message.role + \"\\n\" + content + \"<|im_end|>\\n\" }}\n {%- elif message.role == \"assistant\" -%}\n {% generation %}\n {%- if reasoning_mode == \"/think\" -%}\n {{ \"<|im_start|>assistant\\n\" + content.lstrip(\"\\n\") + \"<|im_end|>\\n\" }}\n {%- else -%}\n {{ \"<|im_start|>assistant\\n\" + \"<think>\\n\\n</think>\\n\" + content.lstrip(\"\\n\") + \"<|im_end|>\\n\" }}\n {%- endif -%}\n {% endgeneration %}\n {%- elif message.role == \"tool\" -%}\n {{ \"<|im_start|>\" + \"user\\n\" + content + \"<|im_end|>\\n\" }}\n {%- endif -%}\n {%- endfor -%}\n {# \u2500\u2500\u2500\u2500\u2500 generation prompt \u2500\u2500\u2500\u2500\u2500 #}\n {%- if add_generation_prompt -%}\n {%- if reasoning_mode == \"/think\" -%}\n {{ \"<|im_start|>assistant\\n\" }}\n {%- else -%}\n {{ \"<|im_start|>assistant\\n\" + \"<think>\\n\\n</think>\\n\" }}\n {%- endif -%}\n {%- endif -%}\n",
8
+ "clean_up_tokenization_spaces": false,
9
+ "eos_token": "<|endoftext|>",
10
+ "model_max_length": 65536,
11
+ "pad_token": "<|pad|>",
12
+ "tokenizer_class": "TokenizersBackend",
13
+ "unk_token": "<|endoftext|>"
14
+ }
vllm_patches/transformers_lizzy_tp.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compat patch for Lizzy TP under vLLM's generic Transformers backend."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from torch import nn
10
+
11
+ _PATCH_ATTR = "_flwr_transformers_lizzy_tp_patch_applied"
12
+
13
+
14
+ class _TensorParallelSliceNorm(nn.Module):
15
+ """Apply a full-width checkpoint norm to a TP-local activation slice."""
16
+
17
+ def __init__(self, base_norm: nn.Module, start_idx: int, end_idx: int):
18
+ super().__init__()
19
+ self.start_idx = start_idx
20
+ self.end_idx = end_idx
21
+ self.weight = base_norm.weight
22
+ if getattr(base_norm, "bias", None) is not None:
23
+ self.bias = base_norm.bias
24
+ else:
25
+ self.register_parameter("bias", None)
26
+ self.eps = float(
27
+ getattr(base_norm, "eps", getattr(base_norm, "variance_epsilon", 1e-6)),
28
+ )
29
+ self.norm_kind = (
30
+ "layernorm" if isinstance(base_norm, nn.LayerNorm) else "rmsnorm"
31
+ )
32
+
33
+ @property
34
+ def local_size(self) -> int:
35
+ return self.end_idx - self.start_idx
36
+
37
+ def _slice_param(self, param: torch.Tensor | None) -> torch.Tensor | None:
38
+ if param is None:
39
+ return None
40
+ if param.shape[0] == self.local_size:
41
+ return param
42
+ return param[self.start_idx : self.end_idx]
43
+
44
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
45
+ weight = self.weight
46
+ bias = self.bias
47
+ if hidden_states.shape[-1] != self.weight.shape[0]:
48
+ if hidden_states.shape[-1] != self.local_size:
49
+ msg = (
50
+ "Unexpected hidden size for TP-sliced norm: "
51
+ f"{hidden_states.shape[-1]} "
52
+ f"(expected {self.weight.shape[0]} or {self.local_size})"
53
+ )
54
+ raise RuntimeError(msg)
55
+ weight = self._slice_param(weight)
56
+ bias = self._slice_param(bias)
57
+
58
+ if self.norm_kind == "layernorm":
59
+ return F.layer_norm(
60
+ hidden_states,
61
+ (hidden_states.shape[-1],),
62
+ weight,
63
+ bias,
64
+ self.eps,
65
+ )
66
+
67
+ input_dtype = hidden_states.dtype
68
+ hidden_states_fp32 = hidden_states.to(torch.float32)
69
+ variance = hidden_states_fp32.pow(2).mean(dim=-1, keepdim=True)
70
+ hidden_states_norm = hidden_states_fp32 * torch.rsqrt(variance + self.eps)
71
+ hidden_states_norm = hidden_states_norm.to(input_dtype)
72
+ output = weight * hidden_states_norm
73
+ if bias is not None:
74
+ output = output + bias
75
+ return output
76
+
77
+
78
+ def _maybe_patch_lizzy_attention_for_tp(
79
+ *,
80
+ module: nn.Module,
81
+ prefix: str,
82
+ tp_size: int,
83
+ tp_rank: int,
84
+ log_replacement: Any, # noqa: ANN401
85
+ ) -> None:
86
+ if tp_size <= 1 or type(module).__name__ != "LizzyAttention":
87
+ return
88
+
89
+ num_heads = getattr(module, "num_heads", None)
90
+ num_key_value_heads = getattr(module, "num_key_value_heads", None)
91
+ head_dim = getattr(module, "head_dim", None)
92
+ q_norm = getattr(module, "q_norm", None)
93
+ k_norm = getattr(module, "k_norm", None)
94
+ if not all(
95
+ isinstance(value, int)
96
+ for value in (num_heads, num_key_value_heads, head_dim)
97
+ ):
98
+ return
99
+ if num_heads % tp_size != 0 or num_key_value_heads % tp_size != 0:
100
+ return
101
+
102
+ local_num_heads = num_heads // tp_size
103
+ local_num_key_value_heads = num_key_value_heads // tp_size
104
+ local_q_dim = local_num_heads * head_dim
105
+ local_kv_dim = local_num_key_value_heads * head_dim
106
+
107
+ module.num_heads = local_num_heads
108
+ module.num_key_value_heads = local_num_key_value_heads
109
+ module.num_key_value_groups = local_num_heads // local_num_key_value_heads
110
+
111
+ if q_norm is not None and getattr(q_norm, "weight", None) is not None:
112
+ start = tp_rank * local_q_dim
113
+ end = start + local_q_dim
114
+ module.q_norm = _TensorParallelSliceNorm(q_norm, start, end)
115
+ log_replacement(f"{prefix}.q_norm", q_norm, module.q_norm)
116
+
117
+ if k_norm is not None and getattr(k_norm, "weight", None) is not None:
118
+ start = tp_rank * local_kv_dim
119
+ end = start + local_kv_dim
120
+ module.k_norm = _TensorParallelSliceNorm(k_norm, start, end)
121
+ log_replacement(f"{prefix}.k_norm", k_norm, module.k_norm)
122
+
123
+
124
+ def patch_vllm_transformers_lizzy_tp() -> None:
125
+ """Patch the generic vLLM Transformers backend for Lizzy TP norms/heads."""
126
+ import vllm.model_executor.models.transformers as transformers_mod
127
+
128
+ transformers_base = transformers_mod.TransformersBase
129
+ if getattr(transformers_base, _PATCH_ATTR, False):
130
+ return
131
+
132
+ PreTrainedModel = transformers_mod.PreTrainedModel
133
+ maybe_prefix = transformers_mod.maybe_prefix
134
+ replace_linear_class = transformers_mod.replace_linear_class
135
+ get_feature_request_tip = transformers_mod.get_feature_request_tip
136
+ re = transformers_mod.re
137
+ log_replacement = transformers_mod.log_replacement
138
+ get_tp_rank = getattr(transformers_mod, "get_tensor_model_parallel_rank", None)
139
+ if get_tp_rank is None:
140
+ try:
141
+ from vllm.distributed import ( # noqa: PLC0415
142
+ get_tensor_model_parallel_rank as get_tp_rank,
143
+ )
144
+ except Exception:
145
+ get_tp_rank = lambda: 0
146
+
147
+ def tensor_parallel(self: Any) -> None: # noqa: ANN401
148
+ """Apply the model's tensor parallel plan plus Lizzy attention fixes."""
149
+ is_pretrained_model = lambda m: isinstance(m, PreTrainedModel)
150
+ supports_tp_plan = lambda m: m.config.base_model_tp_plan is not None
151
+ pretrained_models = filter(is_pretrained_model, self.model.modules())
152
+ models_with_tp_plan = filter(supports_tp_plan, pretrained_models)
153
+
154
+ if not any(models_with_tp_plan) and self.tp_size > 1:
155
+ tip = get_feature_request_tip(
156
+ self.model_config.model,
157
+ self.model_config.trust_remote_code,
158
+ )
159
+ raise ValueError(
160
+ f"{type(self.model)} does not support tensor parallel. {tip}",
161
+ )
162
+
163
+ tp_rank = get_tp_rank()
164
+
165
+ def _tensor_parallel(
166
+ module: nn.Module,
167
+ prefix: str = "",
168
+ tp_plan: dict[str, str] | None = None,
169
+ ) -> None:
170
+ local_tp_plan = tp_plan or {}
171
+
172
+ if isinstance(module, PreTrainedModel):
173
+ local_tp_plan = module.config.base_model_tp_plan or {}
174
+ local_tp_plan = {
175
+ maybe_prefix(prefix, key): value
176
+ for key, value in local_tp_plan.items()
177
+ }
178
+
179
+ for child_name, child_module in module.named_children():
180
+ qual_name = maybe_prefix(prefix, child_name)
181
+ if isinstance(child_module, nn.Linear):
182
+ generator = (p for p in local_tp_plan if re.match(p, qual_name))
183
+ pattern = next(generator, None)
184
+ style = local_tp_plan.get(pattern, "replicate")
185
+ new_module = replace_linear_class(
186
+ child_module,
187
+ style,
188
+ self.quant_config,
189
+ prefix=qual_name,
190
+ )
191
+ setattr(module, child_name, new_module)
192
+ log_replacement(qual_name, child_module, new_module)
193
+ else:
194
+ _tensor_parallel(
195
+ child_module,
196
+ prefix=qual_name,
197
+ tp_plan=local_tp_plan,
198
+ )
199
+
200
+ _maybe_patch_lizzy_attention_for_tp(
201
+ module=module,
202
+ prefix=prefix,
203
+ tp_size=self.tp_size,
204
+ tp_rank=tp_rank,
205
+ log_replacement=log_replacement,
206
+ )
207
+
208
+ _tensor_parallel(self.model)
209
+
210
+ transformers_base.tensor_parallel = tensor_parallel
211
+ setattr(transformers_base, _PATCH_ATTR, True)
vocab.json ADDED
The diff for this file is too large to render. See raw diff