GGUF
conversational
HelloSun commited on
Commit
bb7b6d5
·
0 Parent(s):

Duplicate from HelloSun/openPangu-R-7B-2512-Q4KM-gguf

Browse files
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ openPangu-R-7B-2512-Q4_K_M.gguf filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ OPENPANGU MODEL LICENSE AGREEMENT VERSION 1.0
2
+
3
+ This OPENPANGU MODEL LICENSE AGREEMENT VERSION 1.0 (the "Agreement") is a legal agreement between You and Huawei Technologies Co., Ltd. ("Huawei", "We" or "Us"), and it governs Your reproducing, use, modification, and distribution of openPangu as made available by Huawei under this Agreement.
4
+
5
+ By using, reproducing, modifying, distributing, performing or displaying any portion or element of openPangu, or otherwise accepting the terms of this Agreement, You agree to be bound by this Agreement.
6
+
7
+ 1. Definitions.
8
+ 1.1. “openPangu” or “Model” means openPangu large language models and software, including trained model weights, parameters (including optimizer states), accompanying source code and scripts released under this Agreement.
9
+ 1.2. “Derivative Model” means all (1) modifications to the Model, (2) works based on the Model, and (3) any other derivative works of the Model. For clarity, information or content results from operating or otherwise using the Model is not a Derivative Model.
10
+ 1.3. “You” or “Your” means an individual or Legal Entity exercising permissions granted by this Agreement and/or using the Model for any purpose.
11
+ 1.4. “Third Party” or “Third Parties” means individuals or legal entities that are not under common control with Us or You.
12
+
13
+ 2. License Grant. Subject to Your full compliance with the terms and conditions of this Agreement, We hereby grant to You a perpetual, worldwide, non-exclusive, non-transferable, no-charge, royalty-free license (except as stated in Section 3) to use, reproduce, modify, and distribute the Model.
14
+
15
+ 3. Conditions for License Grant. You represent and warrant that You will not, access, download, install, run, deploy, integrate, modify, or otherwise use the Model, directly or indirectly, within the European Union.
16
+
17
+
18
+ 4. Redistribution.
19
+ 4.1. If You distribute the Model or Derivative Model, You shall retain in Your distribution (1) a copy of this agreement, and (2) all copyright notices and other notices of origin included in the Model that are applicable to Your distribution.
20
+ 4.2. Further, if You distribute or make available to Third Parties a product or service (including another AI model) based on the Model, You are required to (1) display the acknowledgement “Powered by openPangu” and (2) include a trademark notice “openPangu is a trademark of Huawei Technologies Co., Ltd.” on related webpages, user manuals, product documentations or other advertising materials mentioning features of the Model.
21
+ 4.3. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for Derivative Model made by You as a whole, provided Your use, reproduction, and distribution of the Model otherwise complies with the terms and conditions of this Agreement.
22
+
23
+ 5. Ownership. We do not claim ownership to any information or content generated using the Model or Derivative Model that are made by You. You are solely responsible for evaluating the accuracy and appropriateness of such information or content for Your use case.
24
+
25
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of Huawei, except as required for complying with Section 4.2.
26
+
27
+ 7. Indemnity. You will indemnify and hold harmless Huawei from and against any claim by any third party arising out of or related to Your use or distribution of the Model or Derivative Model made by You (e.g. a violation against Section 3). For avoidance of doubt, “third party” in this clause include supervisory authorities.
28
+
29
+ 8. THE MODEL IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NONINFRINGEMENT, ACCURACY, OR THE ABSENCE OF LATENT OR OTHER DEFECTS OR ERRORS, WHETHER OR NOT DISCOVERABLE, ALL TO THE GREATEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW.
30
+
31
+ 9. IN NO EVENT SHALL WE BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE MODEL, IN WHOLE OR IN PART, NO MATTER HOW IT’S CAUSED OR THE LEGAL THEORY IT IS BASED ON, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32
+
33
+
34
+ END OF THE TERMS AND CONDITIONS
README.md ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: openpangu-model-license-agreement-1.0
4
+ license_link: LICENSE
5
+ base_model: openpangu/openPangu-R-7B-2512
6
+ library_name: gguf
7
+ ---
8
+
9
+ # openPangu-R-7B-2512-Q4_K_M (GGUF)
10
+
11
+ Powered by openPangu. openPangu is a trademark of Huawei Technologies Co., Ltd.
12
+
13
+ Q4_K_M GGUF conversion of [openpangu/openPangu-R-7B-2512](https://huggingface.co/openpangu/openPangu-R-7B-2512).
14
+ This is an unofficial community conversion, not released or endorsed by Huawei.
15
+
16
+ ## Important
17
+
18
+ - **Upstream llama.cpp does not support this model.** The GGUF uses the architecture name `openpangu-r`,
19
+ which exists only in the patch in this repository. The patch targets **llama.cpp v0.7.0** (latest stable release).
20
+ - Tested on CPU only (x86-64, AVX-512). GPU backends were not tested.
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ bash build_openpangu_r.sh # clones llama.cpp v0.7.0, applies the patch, builds, downloads the GGUF
26
+ ```
27
+
28
+ Options: `SKIP_MODEL=1` skips the download; `HF_TOKEN` is only needed if this repository is private.
29
+ The script checks the sha256 of the patch and the GGUF.
30
+
31
+ Run (raw prompt, Chinese chat template of the model):
32
+
33
+ ```bash
34
+ ./llama.cpp/build/bin/llama-completion -m models/openPangu-R-7B-2512-Q4_K_M.gguf -no-cnv --temp 0 -n 128 --no-display-prompt \
35
+ -p "[unused9]系统:你是一个有帮助的助手。[unused10][unused9]用户:用一句话介绍什么是大语言模型。 /no_think[unused10][unused9]助手:[unused16]"
36
+ ```
37
+
38
+ Prompt format: `[unused9]系统:…[unused10][unused9]用户:…[unused10][unused9]助手:[unused16]`.
39
+ Append ` /no_think` to a user message for fast (non-thinking) answers. The answer follows `[unused17]`; generation ends with `[unused10]`.
40
+
41
+ ## Conversion
42
+
43
+ 1. `convert_hf_to_gguf.py` (patched) with `--outtype f16` from the BF16 safetensors. The MTP module (layer 27) and the second final norm are dropped.
44
+ 2. `llama-quantize <f16.gguf> <out.gguf> Q4_K_M`. Sinks and the conv weight are kept in F32.
45
+
46
+ ## Verification (done in this environment)
47
+
48
+ - **Reference check:** a CPU fp32 reference was written from the HF modeling code. For a 33-token prompt, the top-10 logits
49
+ match llama.cpp F16 (max |Δlogit| ≈ 0.01). For a 484-token prompt (sliding-window layers active), the top-10 match with
50
+ max |Δlogit| ≈ 0.03. Turning the sliding window off in the reference changes the logits by about 6, so the window is verified.
51
+ - **Greedy decoding:** llama.cpp F16 matches the fp32 reference token by token (11 tokens checked).
52
+ - **Batching:** F16 gives the same results with prompt decoding in one batch, in chunks of 4, and token by token.
53
+ - **Long context:** a fact placed about 400 tokens before the question was answered correctly (`7312`).
54
+ - **Multi-turn:** a second user turn appended to the same context is answered in context.
55
+
56
+ Sample outputs (Q4_K_M):
57
+
58
+ | prompt | output |
59
+ |---|---|
60
+ | 用一句话介绍什么是大语言模型(快思考) | 大语言模型是一种基于大量文本数据训练而成的人工智能模型,能够理解和生成人类语言,广泛应用于自然语言处理任务。 |
61
+ | 写一首关于秋天的四行短诗(快思考) | 秋风轻拂叶纷飞,/ 金黄铺满小径长。/ 寒蝉低唱夕阳下,/ 一缕炊烟入梦乡。 |
62
+ | 一个班有30名学生,其中2/5是女生,女生有多少人?(慢思考) | 12人 |
63
+ | 123 + 456 等于多少?(慢思考) | 579 |
64
+
65
+ Note: in fast mode the model once answered `123 + 456 = 679`. The fp32 reference gives the same answer for that prompt, so this is a model
66
+ behavior, not a conversion or implementation error. Thinking mode answers 579.
67
+
68
+ ## Known limitations
69
+
70
+ - **One sequence per batch.** A batch with more than one sequence aborts. The conv history of the merge layers is kept inside the model
71
+ and follows one sequence decoded contiguously. Prompt-cache reuse, `seq_rm`, and multi-slot serving are not supported.
72
+ - The MTP (next-token) head is not included and not used.
73
+ - Hadamard-rotated (quantized) KV cache is not supported; use the default f16 KV cache.
74
+ - `llama-server` was not validated.
75
+
76
+ ## License and notices
77
+
78
+ The model and derivative works are licensed under the **OPENPANGU MODEL LICENSE AGREEMENT VERSION 1.0** (see `LICENSE`).
79
+
80
+ - **EU restriction (Section 3):** you must not access, download, install, run, deploy, integrate, modify, or otherwise use this model within the European Union.
81
+ - **Acknowledgment (Section 4.2):** "Powered by openPangu" and the trademark notice "openPangu is a trademark of Huawei Technologies Co., Ltd." must appear on pages, manuals, or materials that describe features of the model.
82
+ - The model is provided "AS IS" without warranty. Outputs are generated automatically and may be inaccurate.
83
+
84
+ ## Files and checksums
85
+
86
+ | file | sha256 |
87
+ |---|---|
88
+ | `openPangu-R-7B-2512-Q4_K_M.gguf` | `efeb81edbf64ad9d7a80254332f3128d86deec589ee39315a3c1f7ec1aa5f10a` |
89
+ | `openpangu-r-llama.cpp-v0.7.0.patch` | `b5f302da0cece9c6bc717982d820f8b3e6ca0970f8f32b549efb41ef0d6b8773` |
90
+ | `LICENSE` | `747083c8c24995c75ed641d5c031a95a859b1ec37cd3deeb033425a75249a3cb` |
build_openpangu_r.sh ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # One-click setup for openPangu-R-7B-2512 (Q4_K_M GGUF):
3
+ # 1. clones llama.cpp v0.7.0 (stable release)
4
+ # 2. applies the openPangu-R patch (adds the "openpangu-r" architecture)
5
+ # 3. builds llama-cli / llama-completion / llama-quantize
6
+ # 4. downloads the Q4_K_M GGUF and checks its sha256
7
+ #
8
+ # usage: bash build_openpangu_r.sh [install_dir] (default: ./openpangu-r)
9
+ # env: SKIP_MODEL=1 do not download the GGUF
10
+ # HF_TOKEN=... only needed if the Hugging Face repo is private; read from the
11
+ # environment and never written to disk
12
+ set -euo pipefail
13
+
14
+ LLAMA_TAG=v0.7.0
15
+ HF_REPO=HelloSun/openPangu-R-7B-2512-Q4KM
16
+ PATCH_NAME=openpangu-r-llama.cpp-v0.7.0.patch
17
+ PATCH_SHA256=b5f302da0cece9c6bc717982d820f8b3e6ca0970f8f32b549efb41ef0d6b8773
18
+ GGUF_NAME=openPangu-R-7B-2512-Q4_K_M.gguf
19
+ GGUF_SHA256=efeb81edbf64ad9d7a80254332f3128d86deec589ee39315a3c1f7ec1aa5f10a
20
+
21
+ # HF_BASE can point to a local mirror (file:// or http://) for testing
22
+ HF_BASE=${HF_BASE:-https://huggingface.co/${HF_REPO}/resolve/main}
23
+
24
+ ROOT=$(mkdir -p "${1:-$PWD/openpangu-r}" && cd "${1:-$PWD/openpangu-r}" && pwd)
25
+ cd "$ROOT"
26
+
27
+ for tool in git cmake make g++ curl sha256sum; do
28
+ command -v "$tool" >/dev/null || { echo "error: missing tool: $tool" >&2; exit 1; }
29
+ done
30
+
31
+ AUTH=()
32
+ if [ -n "${HF_TOKEN:-}" ]; then
33
+ AUTH=(-H "Authorization: Bearer ${HF_TOKEN}")
34
+ fi
35
+
36
+ check_sha() { # file expected_sha256
37
+ echo "$2 $1" | sha256sum -c --quiet - || { echo "error: sha256 mismatch for $1" >&2; exit 1; }
38
+ }
39
+
40
+ echo "[1/4] llama.cpp $LLAMA_TAG"
41
+ if [ ! -d llama.cpp ]; then
42
+ git clone --depth 1 --branch "$LLAMA_TAG" https://github.com/ggml-org/llama.cpp.git llama.cpp
43
+ fi
44
+ if [ "$(git -C llama.cpp describe --tags --exact-match 2>/dev/null || true)" != "$LLAMA_TAG" ]; then
45
+ echo "error: $ROOT/llama.cpp is not at tag $LLAMA_TAG" >&2
46
+ exit 1
47
+ fi
48
+
49
+ echo "[2/4] openPangu-R patch"
50
+ curl -fsSL "${AUTH[@]}" -o "$PATCH_NAME" "$HF_BASE/$PATCH_NAME"
51
+ check_sha "$PATCH_NAME" "$PATCH_SHA256"
52
+ if git -C llama.cpp apply --reverse --check "$ROOT/$PATCH_NAME" 2>/dev/null; then
53
+ echo "patch already applied"
54
+ else
55
+ git -C llama.cpp apply --check "$ROOT/$PATCH_NAME"
56
+ git -C llama.cpp apply "$ROOT/$PATCH_NAME"
57
+ echo "patch applied"
58
+ fi
59
+
60
+ echo "[3/4] build"
61
+ cmake -S llama.cpp -B llama.cpp/build -DCMAKE_BUILD_TYPE=Release -DLLAMA_CURL=OFF -DLLAMA_BUILD_TESTS=OFF
62
+ cmake --build llama.cpp/build -j"$(nproc)" --target llama-cli llama-completion llama-quantize
63
+
64
+ echo "[4/4] model"
65
+ MODEL="$ROOT/models/$GGUF_NAME"
66
+ if [ "${SKIP_MODEL:-0}" = "1" ]; then
67
+ echo "skipped (SKIP_MODEL=1)"
68
+ else
69
+ mkdir -p "$ROOT/models"
70
+ if [ ! -f "$MODEL" ]; then
71
+ curl -fL --retry 3 "${AUTH[@]}" -o "$MODEL.part" "$HF_BASE/$GGUF_NAME"
72
+ mv "$MODEL.part" "$MODEL"
73
+ fi
74
+ check_sha "$MODEL" "$GGUF_SHA256"
75
+ echo "model ready: $MODEL"
76
+ fi
77
+
78
+ cat <<EOF
79
+
80
+ done. try:
81
+ $ROOT/llama.cpp/build/bin/llama-completion -m $MODEL -no-cnv --temp 0 -n 128 --no-display-prompt \\
82
+ -p "[unused9]系统:你是一个有帮助的助手。[unused10][unused9]用户:用一句话介绍什么是大语言模型。 /no_think[unused10][unused9]助手:[unused16]"
83
+ EOF
openPangu-R-7B-2512-Q4_K_M.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efeb81edbf64ad9d7a80254332f3128d86deec589ee39315a3c1f7ec1aa5f10a
3
+ size 5067641664
openpangu-r-llama.cpp-v0.7.0.patch ADDED
@@ -0,0 +1,710 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/conversion/__init__.py b/conversion/__init__.py
2
+ index 8ce4cb7..f7455f4 100644
3
+ --- a/conversion/__init__.py
4
+ +++ b/conversion/__init__.py
5
+ @@ -228,6 +228,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
6
+ "PLaMo3ForCausalLM": "plamo",
7
+ "PaddleOCRVLForConditionalGeneration": "ernie",
8
+ "PanguEmbeddedForCausalLM": "pangu",
9
+ + "PanguEmbeddedRForCausalLM": "pangu",
10
+ "Phi3ForCausalLM": "phi",
11
+ "Phi4ForCausalLMV": "phi",
12
+ "PhiForCausalLM": "phi",
13
+ diff --git a/conversion/base.py b/conversion/base.py
14
+ index a5a80f2..1a5276b 100644
15
+ --- a/conversion/base.py
16
+ +++ b/conversion/base.py
17
+ @@ -3121,6 +3121,12 @@ def get_model_architecture(hparams: dict[str, Any], model_type: ModelType) -> st
18
+ arch = text_config["architectures"][0]
19
+ elif model_type == ModelType.MMPROJ and vision_config.get("architectures") is not None:
20
+ arch = vision_config["architectures"][0]
21
+ +
22
+ + # openPangu-R reuses the PanguEmbedded architecture name, but its config carries the
23
+ + # sliding-window / attention-sink / gate / conv extensions: route it to its own class
24
+ + if model_type == ModelType.TEXT and arch == "PanguEmbeddedForCausalLM" and "param_sink_number" in hparams:
25
+ + arch = "PanguEmbeddedRForCausalLM"
26
+ +
27
+ if arch is None:
28
+ raise ValueError("Failed to detect model architecture")
29
+ return arch
30
+ diff --git a/conversion/pangu.py b/conversion/pangu.py
31
+ index 74c7653..14b2250 100644
32
+ --- a/conversion/pangu.py
33
+ +++ b/conversion/pangu.py
34
+ @@ -45,3 +45,71 @@ class PanguEmbeddedModel(TextModel):
35
+ logger.info("Skipping tied output layer 'lm_head.weight'")
36
+ return
37
+ yield from super().modify_tensors(data_torch, name, bid)
38
+ +
39
+ +
40
+ +@ModelBase.register("PanguEmbeddedRForCausalLM")
41
+ +@ModelBase.example("openpangu/openPangu-R-7B-2512")
42
+ +class PanguEmbeddedRModel(TextModel):
43
+ + # openPangu-R: PanguEmbedded config + interleaved sliding-window/full attention,
44
+ + # per-layer attention sinks (learned K/V prefix), gated attention with per-head RMSNorm,
45
+ + # partial RoPE, a causal depthwise conv merge in the first and last layers, and an MTP head
46
+ + # (layer index == block_count, not used for inference).
47
+ + model_arch = gguf.MODEL_ARCH.PANGU_EMBED_R
48
+ +
49
+ + def set_vocab(self):
50
+ + self._set_vocab_sentencepiece()
51
+ +
52
+ + tokenizer_config_file = self.dir_model / 'tokenizer_config.json'
53
+ + if tokenizer_config_file.is_file():
54
+ + with open(tokenizer_config_file, "r", encoding="utf-8") as f:
55
+ + tokenizer_config_json = json.load(f)
56
+ + if "add_prefix_space" in tokenizer_config_json:
57
+ + self.gguf_writer.add_add_space_prefix(tokenizer_config_json["add_prefix_space"])
58
+ +
59
+ + def set_gguf_parameters(self):
60
+ + super().set_gguf_parameters()
61
+ + hparams = self.hparams
62
+ + self.gguf_writer.add_vocab_size(hparams["vocab_size"])
63
+ +
64
+ + # partial RoPE: only rotary_percent of head_dim is rotated (rounded up to an even count, as in HF)
65
+ + head_dim = hparams["head_dim"]
66
+ + rot_dim = int(head_dim * hparams["rotary_percent"])
67
+ + rot_dim += rot_dim % 2
68
+ + self.gguf_writer.add_rope_dimension_count(rot_dim)
69
+ +
70
+ + self.gguf_writer.add_sliding_window(hparams["sliding_window"])
71
+ + self.gguf_writer.add_sliding_window_pattern([t == "sliding_attention" for t in hparams["layer_types"]])
72
+ +
73
+ + def tensor_force_quant(self, name: str, new_name: str, bid: int | None, n_dims: int) -> gguf.GGMLQuantizationType | bool:
74
+ + # sinks and the conv merge are small; keep them in F32
75
+ + if any(self.match_model_tensor_name(new_name, key, bid) for key in (
76
+ + gguf.MODEL_TENSOR.ATTN_SINK_K,
77
+ + gguf.MODEL_TENSOR.ATTN_SINK_V,
78
+ + gguf.MODEL_TENSOR.FFN_MERGE_CONV,
79
+ + )):
80
+ + return gguf.GGMLQuantizationType.F32
81
+ + return super().tensor_force_quant(name, new_name, bid, n_dims)
82
+ +
83
+ + def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
84
+ + # the MTP module (layer block_count) and the second final norm are unused for inference
85
+ + if (bid is not None and bid >= self.block_count) or name == "model.norms.1.weight":
86
+ + return
87
+ +
88
+ + # HF param_sink_key/value: [n_sink, n_kv_head, head_dim]
89
+ + # GGUF ne = [head_dim, n_sink, n_kv_head] (key) and [n_sink, head_dim, n_kv_head] (value)
90
+ + if name.endswith(".self_attn.param_sink_key"):
91
+ + yield (self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_SINK_K, bid),
92
+ + data_torch.permute(1, 0, 2).contiguous())
93
+ + return
94
+ + if name.endswith(".self_attn.param_sink_value"):
95
+ + yield (self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_SINK_V, bid),
96
+ + data_torch.permute(1, 2, 0).contiguous())
97
+ + return
98
+ +
99
+ + # HF depthwise Conv1d weight [n_embd, 1, 3] -> GGUF ne = [n_embd, 3]
100
+ + if name.endswith(".merge_conv.weight"):
101
+ + yield (self.format_tensor_name(gguf.MODEL_TENSOR.FFN_MERGE_CONV, bid),
102
+ + data_torch.squeeze(1).permute(1, 0).contiguous())
103
+ + return
104
+ +
105
+ + yield from super().modify_tensors(data_torch, name, bid)
106
+ diff --git a/gguf-py/gguf/constants.py b/gguf-py/gguf/constants.py
107
+ index a39d046..8a7f15a 100644
108
+ --- a/gguf-py/gguf/constants.py
109
+ +++ b/gguf-py/gguf/constants.py
110
+ @@ -674,6 +674,7 @@ class MODEL_ARCH(IntEnum):
111
+ MINIMAXM3 = auto()
112
+ RND1 = auto()
113
+ PANGU_EMBED = auto()
114
+ + PANGU_EMBED_R = auto()
115
+ MISTRAL3 = auto()
116
+ EAGLE3 = auto()
117
+ DFLASH = auto()
118
+ @@ -743,6 +744,9 @@ class MODEL_TENSOR(IntEnum):
119
+ ATTN_ROT_EMBD = auto()
120
+ ATTN_SINKS = auto()
121
+ ATTN_GATE = auto()
122
+ + ATTN_SINK_K = auto()
123
+ + ATTN_SINK_V = auto()
124
+ + FFN_MERGE_CONV = auto()
125
+ FFN_GATE_INP = auto()
126
+ FFN_GATE_INP_SHEXP = auto()
127
+ FFN_NORM = auto()
128
+ @@ -1479,6 +1483,7 @@ MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = {
129
+ MODEL_ARCH.COGVLM: "cogvlm",
130
+ MODEL_ARCH.RND1: "rnd1",
131
+ MODEL_ARCH.PANGU_EMBED: "pangu-embedded",
132
+ + MODEL_ARCH.PANGU_EMBED_R: "openpangu-r",
133
+ MODEL_ARCH.MISTRAL3: "mistral3",
134
+ MODEL_ARCH.EAGLE3: "eagle3",
135
+ MODEL_ARCH.DFLASH: "dflash",
136
+ @@ -1544,6 +1549,9 @@ TENSOR_NAMES: dict[MODEL_TENSOR, str] = {
137
+ MODEL_TENSOR.ATTN_ROT_EMBD: "blk.{bid}.attn_rot_embd",
138
+ MODEL_TENSOR.ATTN_SINKS: "blk.{bid}.attn_sinks",
139
+ MODEL_TENSOR.ATTN_GATE: "blk.{bid}.attn_gate",
140
+ + MODEL_TENSOR.ATTN_SINK_K: "blk.{bid}.attn_sink_k",
141
+ + MODEL_TENSOR.ATTN_SINK_V: "blk.{bid}.attn_sink_v",
142
+ + MODEL_TENSOR.FFN_MERGE_CONV: "blk.{bid}.ffn_merge_conv",
143
+ MODEL_TENSOR.ATTN_Q_NORM: "blk.{bid}.attn_q_norm",
144
+ MODEL_TENSOR.ATTN_K_NORM: "blk.{bid}.attn_k_norm",
145
+ MODEL_TENSOR.ATTN_OUT_NORM: "blk.{bid}.attn_output_norm",
146
+ @@ -5488,6 +5496,25 @@ MODEL_TENSORS: dict[MODEL_ARCH, list[MODEL_TENSOR]] = {
147
+ MODEL_TENSOR.FFN_DOWN,
148
+ MODEL_TENSOR.FFN_UP,
149
+ ],
150
+ + MODEL_ARCH.PANGU_EMBED_R: [
151
+ + MODEL_TENSOR.TOKEN_EMBD,
152
+ + MODEL_TENSOR.OUTPUT_NORM,
153
+ + MODEL_TENSOR.OUTPUT,
154
+ + MODEL_TENSOR.ATTN_NORM,
155
+ + MODEL_TENSOR.ATTN_Q,
156
+ + MODEL_TENSOR.ATTN_K,
157
+ + MODEL_TENSOR.ATTN_V,
158
+ + MODEL_TENSOR.ATTN_OUT,
159
+ + MODEL_TENSOR.ATTN_GATE,
160
+ + MODEL_TENSOR.ATTN_OUT_NORM,
161
+ + MODEL_TENSOR.ATTN_SINK_K,
162
+ + MODEL_TENSOR.ATTN_SINK_V,
163
+ + MODEL_TENSOR.FFN_NORM,
164
+ + MODEL_TENSOR.FFN_GATE,
165
+ + MODEL_TENSOR.FFN_DOWN,
166
+ + MODEL_TENSOR.FFN_UP,
167
+ + MODEL_TENSOR.FFN_MERGE_CONV,
168
+ + ],
169
+ MODEL_ARCH.MISTRAL3: [
170
+ MODEL_TENSOR.TOKEN_EMBD,
171
+ MODEL_TENSOR.OUTPUT_NORM,
172
+ diff --git a/gguf-py/gguf/tensor_mapping.py b/gguf-py/gguf/tensor_mapping.py
173
+ index 63301cc..df154b8 100644
174
+ --- a/gguf-py/gguf/tensor_mapping.py
175
+ +++ b/gguf-py/gguf/tensor_mapping.py
176
+ @@ -101,6 +101,7 @@ class TensorNameMap:
177
+ "gpt_neox.final_layer_norm", # gptneox
178
+ "transformer.ln_f", # gpt2 gpt-j falcon jais exaone
179
+ "model.norm", # llama-hf baichuan internlm2 olmoe olmo2 phimoe plamo2
180
+ + "model.norms.0", # openpangu-r (final norm)
181
+ "norm", # llama-pth
182
+ "transformer.norm_f", # mpt dbrx
183
+ "ln_f", # refact bloom qwen gpt2
184
+ @@ -409,6 +410,7 @@ class TensorNameMap:
185
+ "encoder.layers.{bid}.norm1", # nomic-bert
186
+ "transformer.decoder_layer.{bid}.rms_norm_1", # Grok
187
+ "model.layers.{bid}.post_attn_norm", # grok-2
188
+ + "model.layers.{bid}.self_attn.groupnorm", # openpangu-r (per-head RMSNorm before gate)
189
+ "transformer.blocks.{bid}.norm_attn_norm.norm_2", # dbrx
190
+ ),
191
+
192
+ @@ -435,6 +437,7 @@ class TensorNameMap:
193
+
194
+ MODEL_TENSOR.ATTN_GATE: (
195
+ "model.layers.{bid}.self_attn.gate_proj", # afmoe muse-glimmer
196
+ + "model.layers.{bid}.self_attn.attention_gate", # openpangu-r
197
+ "model.layers.{bid}.linear_attn.in_proj_z", # qwen3.5
198
+ "layers.{bid}.linear_attn.in_proj_z", # qwen3.5 text
199
+ "model.layers.{bid}.self_attn.g_proj", # step3.5 head-wise attention gate
200
+ diff --git a/src/llama-arch.cpp b/src/llama-arch.cpp
201
+ index d1dd4cb..d30be8c 100644
202
+ --- a/src/llama-arch.cpp
203
+ +++ b/src/llama-arch.cpp
204
+ @@ -144,6 +144,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
205
+ { LLM_ARCH_COGVLM, "cogvlm" },
206
+ { LLM_ARCH_RND1, "rnd1" },
207
+ { LLM_ARCH_PANGU_EMBED, "pangu-embedded" },
208
+ + { LLM_ARCH_OPENPANGU_R, "openpangu-r" },
209
+ { LLM_ARCH_MISTRAL3, "mistral3" },
210
+ { LLM_ARCH_EAGLE3, "eagle3" },
211
+ { LLM_ARCH_DFLASH, "dflash" },
212
+ @@ -500,6 +501,9 @@ static const std::map<llm_tensor, const char *> LLM_TENSOR_NAMES = {
213
+ { LLM_TENSOR_ATTN_Q_NORM, "blk.%d.attn_q_norm" },
214
+ { LLM_TENSOR_ATTN_K_NORM, "blk.%d.attn_k_norm" },
215
+ { LLM_TENSOR_ATTN_GATE, "blk.%d.attn_gate" },
216
+ + { LLM_TENSOR_ATTN_SINK_K, "blk.%d.attn_sink_k" },
217
+ + { LLM_TENSOR_ATTN_SINK_V, "blk.%d.attn_sink_v" },
218
+ + { LLM_TENSOR_FFN_MERGE_CONV, "blk.%d.ffn_merge_conv" },
219
+ { LLM_TENSOR_FFN_POST_NORM, "blk.%d.post_ffw_norm" },
220
+ { LLM_TENSOR_FFN_POST_NORM_1, "blk.%d.post_ffw_norm_1" },
221
+ { LLM_TENSOR_FFN_POST_NORM_2, "blk.%d.post_ffw_norm_2" },
222
+ @@ -839,6 +843,9 @@ static const std::map<llm_tensor, llm_tensor_info> LLM_TENSOR_INFOS = {
223
+ {LLM_TENSOR_ATTN_QKV, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
224
+ {LLM_TENSOR_ATTN_OUT, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
225
+ {LLM_TENSOR_ATTN_GATE, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
226
+ + {LLM_TENSOR_ATTN_SINK_K, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
227
+ + {LLM_TENSOR_ATTN_SINK_V, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
228
+ + {LLM_TENSOR_FFN_MERGE_CONV, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL}},
229
+ {LLM_TENSOR_FFN_GATE, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
230
+ {LLM_TENSOR_FFN_DOWN, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
231
+ {LLM_TENSOR_FFN_UP, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL_MAT}},
232
+ diff --git a/src/llama-arch.h b/src/llama-arch.h
233
+ index 4e8e534..0fa9b42 100644
234
+ --- a/src/llama-arch.h
235
+ +++ b/src/llama-arch.h
236
+ @@ -146,6 +146,7 @@ enum llm_arch {
237
+ LLM_ARCH_COGVLM,
238
+ LLM_ARCH_RND1,
239
+ LLM_ARCH_PANGU_EMBED,
240
+ + LLM_ARCH_OPENPANGU_R,
241
+ LLM_ARCH_MISTRAL3,
242
+ LLM_ARCH_MISTRAL4,
243
+ LLM_ARCH_PADDLEOCR,
244
+ @@ -500,6 +501,9 @@ enum llm_tensor {
245
+ LLM_TENSOR_ATTN_ROT_EMBD,
246
+ LLM_TENSOR_ATTN_SINKS,
247
+ LLM_TENSOR_ATTN_GATE,
248
+ + LLM_TENSOR_ATTN_SINK_K,
249
+ + LLM_TENSOR_ATTN_SINK_V,
250
+ + LLM_TENSOR_FFN_MERGE_CONV,
251
+ LLM_TENSOR_FFN_GATE_INP,
252
+ LLM_TENSOR_FFN_GATE_INP_SHEXP,
253
+ LLM_TENSOR_FFN_NORM,
254
+ diff --git a/src/llama-model.cpp b/src/llama-model.cpp
255
+ index ded790b..a811c9d 100644
256
+ --- a/src/llama-model.cpp
257
+ +++ b/src/llama-model.cpp
258
+ @@ -324,6 +324,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
259
+ return new llama_model_cogvlm(params);
260
+ case LLM_ARCH_PANGU_EMBED:
261
+ return new llama_model_pangu_embed(params);
262
+ + case LLM_ARCH_OPENPANGU_R:
263
+ + return new llama_model_openpangu_r(params);
264
+ case LLM_ARCH_QWEN3NEXT:
265
+ return new llama_model_qwen3next(params);
266
+ case LLM_ARCH_QWEN35:
267
+ @@ -3590,6 +3592,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
268
+ case LLM_ARCH_MINIMAX_M3:
269
+ case LLM_ARCH_COGVLM:
270
+ case LLM_ARCH_PANGU_EMBED:
271
+ + case LLM_ARCH_OPENPANGU_R:
272
+ case LLM_ARCH_AFMOE:
273
+ case LLM_ARCH_LAGUNA:
274
+ case LLM_ARCH_QWEN3NEXT:
275
+ diff --git a/src/llama-model.h b/src/llama-model.h
276
+ index bcfbf1e..4ac2432 100644
277
+ --- a/src/llama-model.h
278
+ +++ b/src/llama-model.h
279
+ @@ -529,6 +529,12 @@ struct llama_layer {
280
+ // openai-moe
281
+ struct ggml_tensor * attn_sinks = nullptr;
282
+
283
+ + // openpangu-r
284
+ + struct ggml_tensor * attn_gate = nullptr;
285
+ + struct ggml_tensor * attn_sink_k = nullptr;
286
+ + struct ggml_tensor * attn_sink_v = nullptr;
287
+ + struct ggml_tensor * ffn_merge_conv = nullptr;
288
+ +
289
+ // DeepSeek-V4
290
+ struct ggml_tensor * attn_kv_norm = nullptr;
291
+ struct ggml_tensor * hc_attn_fn = nullptr;
292
+ diff --git a/src/models/models.h b/src/models/models.h
293
+ index 88fd07d..773e3fe 100644
294
+ --- a/src/models/models.h
295
+ +++ b/src/models/models.h
296
+ @@ -2378,6 +2378,42 @@ struct llama_model_pangu_embed : public llama_model_base {
297
+ std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
298
+ };
299
+
300
+ +// openPangu-R-7B-2512
301
+ +struct llama_model_openpangu_r : public llama_model_base {
302
+ + llama_model_openpangu_r(const struct llama_model_params & params) : llama_model_base(params) {}
303
+ + void load_arch_hparams(llama_model_loader & ml) override;
304
+ + void load_arch_tensors(llama_model_loader & ml) override;
305
+ +
306
+ + // persistent history of the merge_conv layers: the last 2 post-attention hidden states [n_embd, 2]
307
+ + // (indexed by layer, nullptr elsewhere); owned by the model, zeroed when a sequence restarts at pos 0
308
+ + ggml_context_ptr conv_state_ctx;
309
+ + ggml_backend_buffer_ptr conv_state_buf;
310
+ + std::vector<ggml_tensor *> conv_state;
311
+ +
312
+ + struct graph : public llm_graph_context {
313
+ + graph(const llama_model & model, const llm_graph_params & params);
314
+ +
315
+ + // causal attention with per-layer learned sink keys/values (not cached, no RoPE)
316
+ + ggml_tensor * build_attn_sinks(
317
+ + llm_graph_input_attn_kv_iswa * inp,
318
+ + const llama_layer & layer,
319
+ + ggml_tensor * attn_in,
320
+ + ggml_tensor * q_cur,
321
+ + ggml_tensor * k_cur,
322
+ + ggml_tensor * v_cur,
323
+ + int il);
324
+ +
325
+ + // depthwise causal conv over tokens (kernel 3), continuing from the persisted history
326
+ + ggml_tensor * build_merge_conv(
327
+ + ggml_tensor * h,
328
+ + const llama_layer & layer,
329
+ + ggml_tensor * state,
330
+ + int il);
331
+ + };
332
+ +
333
+ + std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
334
+ +};
335
+ +
336
+
337
+ struct llama_model_qwen3next : public llama_model_base {
338
+ llama_model_qwen3next(const struct llama_model_params & params) : llama_model_base(params) {}
339
+ diff --git a/src/models/openpangu-r.cpp b/src/models/openpangu-r.cpp
340
+ new file mode 100644
341
+ index 0000000..5ece53e
342
+ --- /dev/null
343
+ +++ b/src/models/openpangu-r.cpp
344
+ @@ -0,0 +1,366 @@
345
+ +#include "models.h"
346
+ +#include "llama-kv-cache-iswa.h"
347
+ +
348
+ +// openPangu-R-7B-2512 (HF architecture "PanguEmbeddedForCausalLM" with the R extensions)
349
+ +//
350
+ +// per layer:
351
+ +// h1 = h + wo( groupnorm(attn(q, k, v)) * sigmoid(attn_gate(x)) ) x = rmsnorm(h)
352
+ +// x' = merge_conv(h1) (layers 0 and N-1 only; causal depthwise conv, kernel 3, no bias)
353
+ +// h2 = h1 + ffn(rmsnorm(x'))
354
+ +// attention:
355
+ +// - interleaved sliding-window (even layers, window 128) and full attention (odd layers)
356
+ +// - partial RoPE (first 32 of 128 dims, NEOX layout)
357
+ +// - per-layer learned sinks: n_sink (key, value) pairs per KV head that every query can attend to;
358
+ +// they are not cached and not rotated, so they are added to the softmax as extra logits
359
+ +// - per-head RMSNorm (groupnorm, weight shared across heads) on the attention output
360
+ +// the MTP module (layer N) is not used for inference
361
+ +//
362
+ +// limitations: one sequence per batch; the merge_conv history is kept in the model, so it only follows
363
+ +// a single sequence that is decoded contiguously (positions restart at 0 for a new sequence)
364
+ +
365
+ +namespace {
366
+ +
367
+ +// zeroes the merge_conv history when a sequence starts at position 0
368
+ +class llm_graph_input_openpangu_r_state : public llm_graph_input_i {
369
+ +public:
370
+ + explicit llm_graph_input_openpangu_r_state(std::vector<ggml_tensor *> states) : states(std::move(states)) {}
371
+ +
372
+ + void set_input(const llama_ubatch * ubatch) override {
373
+ + if (ubatch->n_seqs_unq > 1) {
374
+ + GGML_ABORT("openpangu-r: only one sequence per batch is supported");
375
+ + }
376
+ + if (ubatch->pos != nullptr && ubatch->n_tokens > 0 && ubatch->pos[0] == 0) {
377
+ + for (ggml_tensor * s : states) {
378
+ + if (s != nullptr) {
379
+ + ggml_backend_tensor_memset(s, 0, 0, ggml_nbytes(s));
380
+ + }
381
+ + }
382
+ + }
383
+ + }
384
+ +
385
+ + std::vector<ggml_tensor *> states;
386
+ +};
387
+ +
388
+ +} // namespace
389
+ +
390
+ +void llama_model_openpangu_r::load_arch_hparams(llama_model_loader & ml) {
391
+ + ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
392
+ +
393
+ + // interleaved sliding-window / full attention; the pattern comes from the GGUF (sliding_window_pattern)
394
+ + hparams.swa_type = LLAMA_SWA_TYPE_STANDARD;
395
+ + ml.get_key(LLM_KV_ATTENTION_SLIDING_WINDOW, hparams.n_swa);
396
+ + load_swa_pattern(ml, 2);
397
+ +
398
+ + // the HF implementation uses a single rotary embedding for both layer types
399
+ + ml.get_key(LLM_KV_ROPE_FREQ_BASE, hparams.rope_freq_base_train_swa);
400
+ +
401
+ + switch (hparams.n_layer()) {
402
+ + case 27: type = LLM_TYPE_7B; break;
403
+ + default: type = LLM_TYPE_UNKNOWN;
404
+ + }
405
+ +}
406
+ +
407
+ +void llama_model_openpangu_r::load_arch_tensors(llama_model_loader & ml) {
408
+ + LLAMA_LOAD_LOCALS;
409
+ +
410
+ + tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
411
+ +
412
+ + // output
413
+ + output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
414
+ + output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED);
415
+ +
416
+ + // if output is NULL, init from the input tok embed
417
+ + if (output == NULL) {
418
+ + output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED);
419
+ + }
420
+ +
421
+ + // number of sink tokens: dim 1 of attn_sink_k (GGUF ne = [head_dim, n_sink, n_kv_head])
422
+ + const ggml_tensor * sink_meta = ml.get_tensor_meta(tn(LLM_TENSOR_ATTN_SINK_K, "weight", 0).str().c_str());
423
+ + if (sink_meta == nullptr) {
424
+ + throw std::runtime_error("openpangu-r: missing attn_sink_k tensor");
425
+ + }
426
+ + const int64_t n_sink = sink_meta->ne[1];
427
+ +
428
+ + conv_state.assign(n_layer, nullptr);
429
+ +
430
+ + for (int i = 0; i < n_layer; ++i) {
431
+ + auto & layer = layers[i];
432
+ +
433
+ + layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
434
+ +
435
+ + create_tensor_qkv(layer, i, n_embd, n_embd_head_k * n_head, n_embd_k_gqa, n_embd_v_gqa, 0);
436
+ + layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_head_k * n_head, n_embd}, 0);
437
+ + layer.wo_b = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "bias", i), {n_embd}, 0);
438
+ +
439
+ + layer.attn_gate = create_tensor(tn(LLM_TENSOR_ATTN_GATE, "weight", i), {n_embd, n_embd_head_k * n_head}, 0);
440
+ + layer.attn_out_norm = create_tensor(tn(LLM_TENSOR_ATTN_OUT_NORM, "weight", i), {n_embd_head_k}, 0);
441
+ + layer.attn_sink_k = create_tensor(tn(LLM_TENSOR_ATTN_SINK_K, "weight", i), {n_embd_head_k, n_sink, n_head_kv}, 0);
442
+ + layer.attn_sink_v = create_tensor(tn(LLM_TENSOR_ATTN_SINK_V, "weight", i), {n_sink, n_embd_head_v, n_head_kv}, 0);
443
+ +
444
+ + layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
445
+ + layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
446
+ + layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
447
+ + layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), {n_ff, n_embd}, 0);
448
+ +
449
+ + if (i == 0 || i == n_layer - 1) {
450
+ + layer.ffn_merge_conv = create_tensor(tn(LLM_TENSOR_FFN_MERGE_CONV, "weight", i), {n_embd, 3}, 0);
451
+ + }
452
+ + }
453
+ +
454
+ + // persistent merge_conv history (2 tokens x n_embd per conv layer), allocated on the CPU
455
+ + int n_conv = 0;
456
+ + for (int i = 0; i < n_layer; ++i) {
457
+ + n_conv += layers[i].ffn_merge_conv != nullptr;
458
+ + }
459
+ +
460
+ + ggml_init_params params = {
461
+ + /*.mem_size =*/ ggml_tensor_overhead() * (n_conv + 1),
462
+ + /*.mem_buffer =*/ nullptr,
463
+ + /*.no_alloc =*/ true,
464
+ + };
465
+ + conv_state_ctx.reset(ggml_init(params));
466
+ + if (!conv_state_ctx) {
467
+ + throw std::runtime_error("openpangu-r: failed to create the conv state context");
468
+ + }
469
+ +
470
+ + for (int i = 0; i < n_layer; ++i) {
471
+ + if (layers[i].ffn_merge_conv == nullptr) {
472
+ + continue;
473
+ + }
474
+ + conv_state[i] = ggml_new_tensor_2d(conv_state_ctx.get(), GGML_TYPE_F32, n_embd, 2);
475
+ + ggml_format_name(conv_state[i], "openpangu_r_conv_state_%d", i);
476
+ + }
477
+ +
478
+ + conv_state_buf.reset(ggml_backend_alloc_ctx_tensors_from_buft(conv_state_ctx.get(), ggml_backend_cpu_buffer_type()));
479
+ + if (!conv_state_buf) {
480
+ + throw std::runtime_error("openpangu-r: failed to allocate the conv state buffer");
481
+ + }
482
+ +}
483
+ +
484
+ +std::unique_ptr<llm_graph_context> llama_model_openpangu_r::build_arch_graph(const llm_graph_params & params) const {
485
+ + return std::make_unique<graph>(*this, params);
486
+ +}
487
+ +
488
+ +// the attention of one layer; sinks are extra softmax terms, the K/V cache is written as usual
489
+ +ggml_tensor * llama_model_openpangu_r::graph::build_attn_sinks(
490
+ + llm_graph_input_attn_kv_iswa * inp,
491
+ + const llama_layer & layer,
492
+ + ggml_tensor * attn_in,
493
+ + ggml_tensor * q,
494
+ + ggml_tensor * k_cur,
495
+ + ggml_tensor * v_cur,
496
+ + int il) {
497
+ + const bool is_swa = hparams.is_swa(il);
498
+ +
499
+ + GGML_ASSERT(!(is_swa ? inp->self_k_rot_swa : inp->self_k_rot) && "openpangu-r: Hadamard-rotated KV cache is not supported");
500
+ + GGML_ASSERT(!(is_swa ? inp->self_v_rot_swa : inp->self_v_rot) && "openpangu-r: Hadamard-rotated KV cache is not supported");
501
+ +
502
+ + const int64_t n_embd_head = q->ne[0];
503
+ + const int64_t n_tokens = q->ne[2];
504
+ + const int64_t n_sink = layer.attn_sink_k->ne[1];
505
+ + const float kq_scale = 1.0f / sqrtf(float(n_embd_head));
506
+ +
507
+ + const auto * mctx_iswa = static_cast<const llama_kv_cache_iswa_context *>(mctx);
508
+ + const auto * mctx_cur = is_swa ? mctx_iswa->get_swa() : mctx_iswa->get_base();
509
+ +
510
+ + // store the current K/V, then read the whole cache (same as llm_graph_context::build_attn)
511
+ + ggml_build_forward_expand(gf, mctx_cur->cpy_k(ctx0, k_cur, is_swa ? inp->get_k_idxs_swa() : inp->get_k_idxs(), il));
512
+ + ggml_build_forward_expand(gf, mctx_cur->cpy_v(ctx0, v_cur, is_swa ? inp->get_v_idxs_swa() : inp->get_v_idxs(), il));
513
+ +
514
+ + ggml_tensor * k = mctx_cur->get_k(ctx0, il);
515
+ + ggml_tensor * v = mctx_cur->get_v(ctx0, il);
516
+ +
517
+ + GGML_ASSERT(k->ne[3] == 1 && "openpangu-r: multi-stream KV cache is not supported");
518
+ +
519
+ + const bool v_trans = v->nb[1] > v->nb[2];
520
+ +
521
+ + // [D, n_tokens, n_head], [D, n_kv, n_kv_head], [n_kv, D, n_kv_head]
522
+ + ggml_tensor * qp = ggml_permute(ctx0, q, 0, 2, 1, 3);
523
+ + ggml_tensor * kp = ggml_permute(ctx0, k, 0, 2, 1, 3);
524
+ + ggml_tensor * vp = ggml_permute(ctx0, v, 0, 2, 1, 3);
525
+ + if (!v_trans) {
526
+ + vp = ggml_cont(ctx0, ggml_transpose(ctx0, vp));
527
+ + }
528
+ +
529
+ + // cached keys: [n_kv, n_tokens, n_head]
530
+ + ggml_tensor * kq = ggml_mul_mat(ctx0, kp, qp);
531
+ + kq = ggml_scale(ctx0, kq, kq_scale);
532
+ +
533
+ + ggml_tensor * kq_mask = is_swa ? inp->get_kq_mask_swa() : inp->get_kq_mask();
534
+ + if (kq_mask != nullptr) {
535
+ + ggml_tensor * mask = ggml_cast(ctx0, kq_mask, GGML_TYPE_F32);
536
+ + mask = ggml_cont(ctx0, ggml_view_3d(ctx0, mask, kq->ne[0], n_tokens, 1, mask->nb[1], mask->nb[2], 0));
537
+ + kq = ggml_add(ctx0, kq, mask);
538
+ + }
539
+ +
540
+ + // sink keys: not cached, not rotated, always visible: [n_sink, n_tokens, n_head]
541
+ + ggml_tensor * ks = ggml_mul_mat(ctx0, layer.attn_sink_k, qp);
542
+ + ks = ggml_scale(ctx0, ks, kq_scale);
543
+ +
544
+ + // one softmax over [cached keys | sinks]
545
+ + ggml_tensor * p = ggml_soft_max(ctx0, ggml_concat(ctx0, kq, ks, 0));
546
+ +
547
+ + const int64_t n_kv = kq->ne[0];
548
+ + // the views have row strides of the full [n_kv + n_sink] row; the CPU mul_mat needs contiguous rows
549
+ + ggml_tensor * p_kv = ggml_cont(ctx0, ggml_view_3d(ctx0, p, n_kv, n_tokens, kq->ne[2], p->nb[1], p->nb[2], 0));
550
+ + ggml_tensor * p_sk = ggml_cont(ctx0, ggml_view_3d(ctx0, p, n_sink, n_tokens, kq->ne[2], p->nb[1], p->nb[2], n_kv*p->nb[0]));
551
+ +
552
+ + ggml_tensor * o_kv = ggml_mul_mat(ctx0, vp, p_kv); // [D, n_tokens, n_head]
553
+ + ggml_tensor * o_sk = ggml_mul_mat(ctx0, layer.attn_sink_v, p_sk); // [D, n_tokens, n_head]
554
+ + ggml_tensor * o = ggml_add(ctx0, o_kv, o_sk);
555
+ +
556
+ + o = ggml_cont(ctx0, ggml_permute(ctx0, o, 0, 2, 1, 3)); // [D, n_head, n_tokens]
557
+ + cb(o, "kqv", il);
558
+ +
559
+ + // per-head RMSNorm, then the sigmoid gate computed from the attention input
560
+ + o = build_norm(o, layer.attn_out_norm, NULL, LLM_NORM_RMS, il);
561
+ + o = ggml_reshape_2d(ctx0, o, n_embd_head * hparams.n_head(il), n_tokens);
562
+ +
563
+ + ggml_tensor * gate = build_lora_mm(layer.attn_gate, attn_in, nullptr);
564
+ + o = ggml_mul(ctx0, o, ggml_sigmoid(ctx0, gate));
565
+ +
566
+ + o = build_lora_mm(layer.wo, o, layer.wo_s);
567
+ + if (layer.wo_b) {
568
+ + o = ggml_add(ctx0, o, layer.wo_b);
569
+ + }
570
+ +
571
+ + return o;
572
+ +}
573
+ +
574
+ +// causal depthwise conv over the token axis: out[t] = w0*h[t-2] + w1*h[t-1] + w2*h[t]
575
+ +// history of the previous two tokens comes from `state`, which is updated with the last two tokens of h
576
+ +ggml_tensor * llama_model_openpangu_r::graph::build_merge_conv(
577
+ + ggml_tensor * h,
578
+ + const llama_layer & layer,
579
+ + ggml_tensor * state,
580
+ + int il) {
581
+ + const int64_t n_embd = h->ne[0];
582
+ + const int64_t n_tokens = h->ne[1];
583
+ +
584
+ + GGML_ASSERT(state->ne[0] == n_embd && state->ne[1] == 2);
585
+ +
586
+ + // [history(2) | h(n_tokens)] along the token axis
587
+ + ggml_tensor * cat = ggml_concat(ctx0, state, h, 1);
588
+ + cb(cat, "merge_conv_in", il);
589
+ +
590
+ + // persist the last two tokens for the next batch
591
+ + ggml_tensor * next = ggml_view_2d(ctx0, cat, n_embd, 2, cat->nb[1], n_tokens*cat->nb[1]);
592
+ + ggml_build_forward_expand(gf, ggml_cpy(ctx0, next, state));
593
+ +
594
+ + ggml_tensor * W = ggml_cast(ctx0, layer.ffn_merge_conv, GGML_TYPE_F32); // [n_embd, 3]
595
+ +
596
+ + ggml_tensor * out = nullptr;
597
+ + for (int k = 0; k < 3; ++k) {
598
+ + ggml_tensor * x_k = ggml_view_2d(ctx0, cat, n_embd, n_tokens, cat->nb[1], k*cat->nb[1]);
599
+ + ggml_tensor * w_k = ggml_view_2d(ctx0, W, n_embd, 1, W->nb[1], k*W->nb[1]);
600
+ + ggml_tensor * t = ggml_mul(ctx0, x_k, w_k);
601
+ + out = out == nullptr ? t : ggml_add(ctx0, out, t);
602
+ + }
603
+ +
604
+ + cb(out, "merge_conv_out", il);
605
+ + return out;
606
+ +}
607
+ +
608
+ +llama_model_openpangu_r::graph::graph(const llama_model & model, const llm_graph_params & params) : llm_graph_context(params) {
609
+ + const auto & self = static_cast<const llama_model_openpangu_r &>(model);
610
+ +
611
+ + const int64_t n_embd_head = hparams.n_embd_head_k();
612
+ +
613
+ + ggml_tensor * cur;
614
+ + ggml_tensor * inpL;
615
+ +
616
+ + inpL = build_inp_embd(model.tok_embd);
617
+ +
618
+ + // inp_pos - contains the positions
619
+ + ggml_tensor * inp_pos = build_inp_pos();
620
+ +
621
+ + res->add_input(std::make_unique<llm_graph_input_openpangu_r_state>(self.conv_state));
622
+ +
623
+ + auto * inp_attn = build_attn_inp_kv_iswa();
624
+ +
625
+ + ggml_tensor * inp_out_ids = build_inp_out_ids();
626
+ +
627
+ + for (int il = 0; il < n_layer; ++il) {
628
+ + const auto & layer = model.layers[il];
629
+ +
630
+ + ggml_tensor * inpSA = inpL;
631
+ +
632
+ + // norm
633
+ + cur = build_norm(inpL, layer.attn_norm, NULL, LLM_NORM_RMS, il);
634
+ + cb(cur, "attn_norm", il);
635
+ +
636
+ + // self attention
637
+ + {
638
+ + auto [Qcur, Kcur, Vcur] = build_qkv(layer, cur, n_embd_head, n_head, n_head_kv, il);
639
+ +
640
+ + // partial RoPE: only the first n_rot dims are rotated
641
+ + const float freq_base_l = model.get_rope_freq_base (cparams, il);
642
+ + const float freq_scale_l = model.get_rope_freq_scale(cparams, il);
643
+ +
644
+ + Qcur = ggml_rope_ext(
645
+ + ctx0, Qcur, inp_pos, nullptr,
646
+ + n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale_l,
647
+ + ext_factor, attn_factor, beta_fast, beta_slow);
648
+ +
649
+ + Kcur = ggml_rope_ext(
650
+ + ctx0, Kcur, inp_pos, nullptr,
651
+ + n_rot, rope_type, n_ctx_orig, freq_base_l, freq_scale_l,
652
+ + ext_factor, attn_factor, beta_fast, beta_slow);
653
+ +
654
+ + cb(Qcur, "Qcur", il);
655
+ + cb(Kcur, "Kcur", il);
656
+ + cb(Vcur, "Vcur", il);
657
+ +
658
+ + cur = build_attn_sinks(inp_attn, layer, cur, Qcur, Kcur, Vcur, il);
659
+ + }
660
+ +
661
+ + ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
662
+ + cb(ffn_inp, "ffn_inp", il);
663
+ +
664
+ + // merge conv runs over all tokens of the batch, before the output rows are selected
665
+ + ggml_tensor * x = ffn_inp;
666
+ + if (layer.ffn_merge_conv != nullptr) {
667
+ + x = build_merge_conv(ffn_inp, layer, self.conv_state[il], il);
668
+ + }
669
+ +
670
+ + if (il == n_layer - 1 && inp_out_ids) {
671
+ + x = ggml_get_rows(ctx0, x, inp_out_ids);
672
+ + ffn_inp = ggml_get_rows(ctx0, ffn_inp, inp_out_ids);
673
+ + }
674
+ +
675
+ + // feed-forward network
676
+ + cur = build_norm(x, layer.ffn_norm, NULL, LLM_NORM_RMS, il);
677
+ + cb(cur, "ffn_norm", il);
678
+ +
679
+ + cur = build_ffn(cur,
680
+ + layer.ffn_up, NULL, NULL,
681
+ + layer.ffn_gate, NULL, NULL,
682
+ + layer.ffn_down, NULL, NULL,
683
+ + NULL,
684
+ + LLM_FFN_SILU, LLM_FFN_PAR, il);
685
+ + cb(cur, "ffn_out", il);
686
+ +
687
+ + cur = ggml_add(ctx0, cur, ffn_inp);
688
+ +
689
+ + cur = build_cvec(cur, il);
690
+ + cb(cur, "l_out", il);
691
+ +
692
+ + // input for next layer
693
+ + inpL = cur;
694
+ + }
695
+ +
696
+ + cur = inpL;
697
+ +
698
+ + cur = build_norm(cur,
699
+ + model.output_norm, NULL,
700
+ + LLM_NORM_RMS, -1);
701
+ +
702
+ + cb(cur, "result_norm", -1);
703
+ + res->t_embd = cur;
704
+ +
705
+ + // lm_head
706
+ + cur = build_lora_mm(model.output, cur);
707
+ +
708
+ + cb(cur, "result_output", -1);
709
+ + res->t_logits = cur;
710
+ +}