Text Generation
Transformers
Safetensors
English
lizzy
lizzy-7b
flwrlabs
british-english
conversational
custom_code
4-bit precision
paroquant
Instructions to use Jeethu/Lizzy-7B-PARO with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Jeethu/Lizzy-7B-PARO with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Jeethu/Lizzy-7B-PARO", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Jeethu/Lizzy-7B-PARO", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Jeethu/Lizzy-7B-PARO with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Jeethu/Lizzy-7B-PARO" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Jeethu/Lizzy-7B-PARO", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Jeethu/Lizzy-7B-PARO
- SGLang
How to use Jeethu/Lizzy-7B-PARO with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "Jeethu/Lizzy-7B-PARO" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Jeethu/Lizzy-7B-PARO", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "Jeethu/Lizzy-7B-PARO" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Jeethu/Lizzy-7B-PARO", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use Jeethu/Lizzy-7B-PARO with Docker Model Runner:
docker model run hf.co/Jeethu/Lizzy-7B-PARO
Upload folder using huggingface_hub
Browse files- .gitattributes +3 -32
- README.md +32 -0
- chat_template.jinja +104 -0
- config.json +177 -0
- configuration_lizzy.py +227 -0
- generation_config.json +8 -0
- header-dark.svg +1 -0
- header-light.svg +1 -0
- merges.txt +0 -0
- model.safetensors +3 -0
- modeling_lizzy.py +2190 -0
- quickstart.py +36 -0
- quickstart_cli.sh +19 -0
- special_tokens_map.json +6 -0
- tokenization_lizzy.py +51 -0
- tokenizer.json +0 -0
- tokenizer_config.json +14 -0
- vllm_patches/transformers_lizzy_tp.py +211 -0
- vocab.json +0 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,6 @@
|
|
| 1 |
-
*.
|
| 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 |
-
*.
|
| 25 |
-
*.
|
| 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
|
|
|