gyung commited on
Commit
c8cc224
·
verified ·
1 Parent(s): 6675e06

Add files using upload-large-folder tool

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* 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
 
 
 
 
 
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
+ KoHRM-Text-1.4B-BF16.gguf filter=lfs diff=lfs merge=lfs -text
37
+ KoHRM-Text-1.4B-Q5_K_M.gguf filter=lfs diff=lfs merge=lfs -text
38
+ KoHRM-Text-1.4B-Q6_K.gguf filter=lfs diff=lfs merge=lfs -text
39
+ KoHRM-Text-1.4B-Q8_0.gguf filter=lfs diff=lfs merge=lfs -text
KoHRM-Text-1.4B-BF16.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d5c66f994327c1e2f05b33b0a2ff798a1d05f8b905b7f93943e101bca06c8b0a
3
+ size 2774976832
KoHRM-Text-1.4B-Q5_K_M.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:90f47f54bd7cf545583a2be43a9d0c971cf6112ff16261e2e926cfabe2e9e35a
3
+ size 1007618400
KoHRM-Text-1.4B-Q6_K.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd54d24344e842c3cd0f261e4b740c42c0ec78ed0b3414cdb8b2ac5022b7fb8a
3
+ size 1142147424
KoHRM-Text-1.4B-Q8_0.gguf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8dae86207987804c7e8fc34fcba0d78ae2e54cd8563e907e9e5aea8442f7300c
3
+ size 1477364064
README.md ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - ko
5
+ - en
6
+ library_name: gguf
7
+ pipeline_tag: text-generation
8
+ base_model: LLM-OS-Models/KoHRM-Text-1.4B
9
+ base_model_relation: quantized
10
+ tags:
11
+ - gguf
12
+ - llama.cpp
13
+ - hrm-text
14
+ - kohrm
15
+ - korean
16
+ - text-generation
17
+ ---
18
+
19
+ # KoHRM-Text-1.4B-GGUF
20
+
21
+ GGUF exports for [LLM-OS-Models/KoHRM-Text-1.4B](https://huggingface.co/LLM-OS-Models/KoHRM-Text-1.4B).
22
+
23
+ This is a custom `hrm_text` architecture. Standard upstream `llama.cpp`, Ollama, LM Studio, and other GGUF frontends will not load these files until `hrm_text` support lands upstream. Use the included runtime patch:
24
+
25
+ ```text
26
+ runtime/llama.cpp-hrm_text.patch
27
+ ```
28
+
29
+ The patch is based on the HRM-Text GGUF work from [sinimiini/HRM-Text-1B-GGUF](https://huggingface.co/sinimiini/HRM-Text-1B-GGUF), adapted for KoHRM-Text-1.4B. The KoHRM conversion infers the physical H/L stack depth from safetensors, because the public config reports `num_hidden_layers=32` while the exported tensors are arranged as `H: 16` and `L: 16`.
30
+
31
+ ## Files
32
+
33
+ | file | type | size | sha256 |
34
+ |---|---:|---:|---|
35
+ | `KoHRM-Text-1.4B-BF16.gguf` | BF16 | 2.6G | `d5c66f994327c1e2f05b33b0a2ff798a1d05f8b905b7f93943e101bca06c8b0a` |
36
+ | `KoHRM-Text-1.4B-Q8_0.gguf` | Q8_0 | 1.4G | `8dae86207987804c7e8fc34fcba0d78ae2e54cd8563e907e9e5aea8442f7300c` |
37
+ | `KoHRM-Text-1.4B-Q6_K.gguf` | Q6_K | 1.1G | `dd54d24344e842c3cd0f261e4b740c42c0ec78ed0b3414cdb8b2ac5022b7fb8a` |
38
+ | `KoHRM-Text-1.4B-Q5_K_M.gguf` | Q5_K_M | 961M | `90f47f54bd7cf545583a2be43a9d0c971cf6112ff16261e2e926cfabe2e9e35a` |
39
+
40
+ ## Build Patched llama.cpp
41
+
42
+ ```bash
43
+ git clone https://github.com/ggml-org/llama.cpp
44
+ cd llama.cpp
45
+ git checkout 6a257d44633d4a752183ed778b88d2924d0a6b9d
46
+ git apply /path/to/runtime/llama.cpp-hrm_text.patch
47
+
48
+ cmake -S . -B build-hrm \
49
+ -DCMAKE_BUILD_TYPE=Release \
50
+ -DLLAMA_CURL=OFF \
51
+ -DGGML_NATIVE=OFF
52
+
53
+ cmake --build build-hrm --target llama-cli llama-quantize llama-completion llama-results -j 8
54
+ ```
55
+
56
+ ## CPU Run
57
+
58
+ Download a quantized GGUF file:
59
+
60
+ ```bash
61
+ huggingface-cli download LLM-OS-Models/KoHRM-Text-1.4B-GGUF \
62
+ KoHRM-Text-1.4B-Q5_K_M.gguf \
63
+ --local-dir .
64
+ ```
65
+
66
+ Run on CPU:
67
+
68
+ ```bash
69
+ ./build-hrm/bin/llama-cli \
70
+ -m ./KoHRM-Text-1.4B-Q5_K_M.gguf \
71
+ -ngl 0 \
72
+ -t 4 \
73
+ -c 512 \
74
+ -n 80 \
75
+ --single-turn \
76
+ --simple-io \
77
+ -p $'질문: 대한민국 민법상 미성년자의 법률행위 취소에 대해 한 문단으로 설명하라.\n답변:'
78
+ ```
79
+
80
+ Tested locally on CPU with the patched `llama.cpp` build:
81
+
82
+ ```text
83
+ build : b9263-6a257d446
84
+ model : KoHRM-Text-1.4B-Q5_K_M.gguf
85
+ Prompt : 16.9 t/s
86
+ Generation : 7.2 t/s
87
+ ```
88
+
89
+ The full smoke-test logs are in `reports/`.
90
+
91
+ ## Prompt Format
92
+
93
+ The source model card documents this project-side prompt wrapper:
94
+
95
+ ```text
96
+ <|im_start|><|object_ref_start|>PROMPT<|im_end|>
97
+ ```
98
+
99
+ The public checkpoint is a rolling pretraining-stage model, not a final chat/SFT model. Expect unstable instruction-following behavior and possible immediate end-token generation depending on prompt and sampler settings. The GGUF files here validate conversion and patched CPU runtime support, not final assistant quality.
100
+
101
+ ## GGUF Metadata
102
+
103
+ Key converted metadata:
104
+
105
+ ```text
106
+ general.architecture = hrm_text
107
+ hrm_text.context_length = 4096
108
+ hrm_text.embedding_length = 1536
109
+ hrm_text.block_count = 128
110
+ hrm_text.layers_per_stack = 16
111
+ hrm_text.h_cycles = 2
112
+ hrm_text.l_cycles = 3
113
+ tokenizer.ggml.model = gpt2
114
+ tokenizer.ggml.pre = qwen2
115
+ tokenizer.ggml.bos_token_id = 2
116
+ tokenizer.ggml.eos_token_id = 35
117
+ tokenizer.ggml.padding_token_id = 0
118
+ ```
119
+
120
+ ## Notes
121
+
122
+ - Source model: `LLM-OS-Models/KoHRM-Text-1.4B`
123
+ - Source revision converted: `c413eee318b28e4f970f1be83698b161e60b3adb`
124
+ - `llama.cpp` base commit used for the patch: `6a257d44633d4a752183ed778b88d2924d0a6b9d`
125
+ - BF16 conversion wrote 259 tensors.
126
+ - `llama-completion` can load the model non-interactively, but in local probes it immediately returned an end token for the tested prompts. `llama-cli --single-turn` produced visible CPU token generation and is the command shown above.
reports/conversion_report.md ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # KoHRM-Text-1.4B GGUF Conversion Report
2
+
3
+ Date: 2026-06-13 UTC
4
+
5
+ ## Inputs
6
+
7
+ - Source repo: `LLM-OS-Models/KoHRM-Text-1.4B`
8
+ - Source revision: `c413eee318b28e4f970f1be83698b161e60b3adb`
9
+ - Files used: `config.json`, `model.safetensors`, `tokenizer.json`, `tokenizer_config.json`
10
+ - Reference implementation: `sinimiini/HRM-Text-1B-GGUF`
11
+ - llama.cpp base commit: `6a257d44633d4a752183ed778b88d2924d0a6b9d`
12
+
13
+ ## Conversion Detail
14
+
15
+ KoHRM config reports `num_hidden_layers=32`, while tensor names show two physical stacks:
16
+
17
+ ```text
18
+ model.H_module.layers.0..15
19
+ model.L_module.layers.0..15
20
+ ```
21
+
22
+ The converter patch therefore infers `layers_per_stack=16` from safetensors instead of treating config `num_hidden_layers` as per-stack depth.
23
+
24
+ Key metadata in the BF16 GGUF:
25
+
26
+ ```text
27
+ general.architecture = hrm_text
28
+ hrm_text.block_count = 128
29
+ hrm_text.layers_per_stack = 16
30
+ hrm_text.h_cycles = 2
31
+ hrm_text.l_cycles = 3
32
+ tokenizer.ggml.bos_token_id = 2
33
+ tokenizer.ggml.eos_token_id = 35
34
+ tokenizer.ggml.padding_token_id = 0
35
+ ```
36
+
37
+ BF16 export completed with 259 tensors.
38
+
39
+ ## Commands
40
+
41
+ BF16:
42
+
43
+ ```bash
44
+ python convert_hf_to_gguf.py /home/work/.artifacts/kohrm_gguf/hf/KoHRM-Text-1.4B \
45
+ --outfile /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-BF16.gguf \
46
+ --outtype bf16 \
47
+ --model-name KoHRM-Text-1.4B
48
+ ```
49
+
50
+ Quantization:
51
+
52
+ ```bash
53
+ ./build-hrm/bin/llama-quantize KoHRM-Text-1.4B-BF16.gguf KoHRM-Text-1.4B-Q5_K_M.gguf Q5_K_M 8
54
+ ./build-hrm/bin/llama-quantize KoHRM-Text-1.4B-BF16.gguf KoHRM-Text-1.4B-Q6_K.gguf Q6_K 4
55
+ ./build-hrm/bin/llama-quantize KoHRM-Text-1.4B-BF16.gguf KoHRM-Text-1.4B-Q8_0.gguf Q8_0 4
56
+ ```
57
+
58
+ CPU smoke test:
59
+
60
+ ```bash
61
+ ./build-hrm/bin/llama-cli \
62
+ -m KoHRM-Text-1.4B-Q5_K_M.gguf \
63
+ -ngl 0 \
64
+ -t 4 \
65
+ -c 512 \
66
+ -n 80 \
67
+ --seed 42 \
68
+ --temp 0.7 \
69
+ --top-p 0.9 \
70
+ --single-turn \
71
+ --simple-io \
72
+ --no-warmup \
73
+ --display-prompt \
74
+ -p $'질문: 대한민국 민법상 미성년자의 법률행위 취소에 대해 한 문단으로 설명하라.\n답변:'
75
+ ```
76
+
77
+ ## CPU Smoke Result
78
+
79
+ The patched runtime loaded `KoHRM-Text-1.4B-Q5_K_M.gguf` and generated tokens on CPU.
80
+
81
+ Key lines:
82
+
83
+ ```text
84
+ build : b9263-6a257d446
85
+ model : KoHRM-Text-1.4B-Q5_K_M.gguf
86
+ Prompt: 16.9 t/s
87
+ Generation: 7.2 t/s
88
+ Exiting...
89
+ ```
90
+
91
+ The generated text is not a legal-quality answer; this source checkpoint is documented as a pretraining-stage model, not an instruction-tuned chat model.
92
+
93
+ ## Artifacts
94
+
95
+ ```text
96
+ d5c66f994327c1e2f05b33b0a2ff798a1d05f8b905b7f93943e101bca06c8b0a KoHRM-Text-1.4B-BF16.gguf
97
+ 90f47f54bd7cf545583a2be43a9d0c971cf6112ff16261e2e926cfabe2e9e35a KoHRM-Text-1.4B-Q5_K_M.gguf
98
+ dd54d24344e842c3cd0f261e4b740c42c0ec78ed0b3414cdb8b2ac5022b7fb8a KoHRM-Text-1.4B-Q6_K.gguf
99
+ 8dae86207987804c7e8fc34fcba0d78ae2e54cd8563e907e9e5aea8442f7300c KoHRM-Text-1.4B-Q8_0.gguf
100
+ ```
reports/cpu_smoke_test_q5_k_m.txt ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+ 0.00.021.160 I llama_completion: llama backend init
5
+ 0.00.021.165 I llama_completion: load the model and apply lora adapter, if any
6
+ 0.00.021.177 I common_init_result: fitting params to device memory ...
7
+ 0.00.021.178 I common_init_result: (for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)
8
+ 0.00.319.875 I common_params_fit_impl: projected to use 1601 MiB of host memory vs. 2063714 MiB of total host memory
9
+ 0.00.481.459 W load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect
10
+ 0.00.598.773 W llama_context: n_ctx_seq (512) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
11
+ 0.00.788.745 I llama_completion: llama threadpool init, n_threads = 4
12
+ 0.00.788.761 I
13
+ 0.00.788.815 I system_info: n_threads = 4 (n_threads_batch = 4) / 224 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
14
+ 0.00.788.817 I
15
+ 0.00.788.930 I sampler seed: 42
16
+ 0.00.788.938 I sampler params:
17
+ repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
18
+ dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = -1
19
+ top_k = 40, top_p = 0.900, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.700
20
+ mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000, adaptive_target = -1.000, adaptive_decay = 0.900
21
+ 0.00.788.945 I sampler chain: logits -> ?penalties -> ?dry -> ?top-n-sigma -> top-k -> ?typical -> top-p -> min-p -> ?xtc -> temp-ext -> dist
22
+ 0.00.788.947 I generate: n_ctx = 512, n_batch = 2048, n_predict = 80, n_keep = 0
23
+ 0.00.788.947 I
24
+ 질문: 대한민국 민법상 미성년자의 법률행위 취소에 대해 한 문단으로 설명하라.
25
+ 답변: [end of text]
26
+
27
+
28
+ 0.01.871.068 I common_perf_print: sampling time = 2.56 ms
29
+ 0.01.871.071 I common_perf_print: samplers time = 0.83 ms / 18 tokens
30
+ 0.01.871.088 I common_perf_print: load time = 1079.66 ms
31
+ 0.01.871.091 I common_perf_print: prompt eval time = 1079.42 ms / 17 tokens ( 63.50 ms per token, 15.75 tokens per second)
32
+ 0.01.871.092 I common_perf_print: eval time = 0.00 ms / 1 runs ( 0.00 ms per token, inf tokens per second)
33
+ 0.01.871.093 I common_perf_print: total time = 1082.33 ms / 18 tokens
34
+ 0.01.871.101 I common_perf_print: unaccounted time = 0.35 ms / 0.0 % (total - sampling - prompt eval - eval) / (total)
35
+ 0.01.871.103 I common_perf_print: graphs reused = 0
reports/cpu_smoke_test_q5_k_m_biased.txt ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+ 0.00.002.145 W DEPRECATED: argument '-l' specified multiple times, use comma-separated values instead (only last value will be used)
5
+ 0.00.002.148 W DEPRECATED: argument '-l' specified multiple times, use comma-separated values instead (only last value will be used)
6
+ 0.00.002.381 I llama_completion: llama backend init
7
+ 0.00.002.385 I llama_completion: load the model and apply lora adapter, if any
8
+ 0.00.002.393 I common_init_result: fitting params to device memory ...
9
+ 0.00.002.394 I common_init_result: (for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)
10
+ 0.00.298.352 I common_params_fit_impl: projected to use 1601 MiB of host memory vs. 2063714 MiB of total host memory
11
+ 0.00.460.515 W load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect
12
+ 0.00.568.735 W llama_context: n_ctx_seq (512) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
13
+ 0.00.745.245 I llama_completion: llama threadpool init, n_threads = 4
14
+ 0.00.745.260 I
15
+ 0.00.745.313 I system_info: n_threads = 4 (n_threads_batch = 4) / 224 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
16
+ 0.00.745.315 I
17
+ 0.00.745.406 I sampler seed: 42
18
+ 0.00.745.414 I sampler params:
19
+ repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
20
+ dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = -1
21
+ top_k = 40, top_p = 0.920, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.650
22
+ mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000, adaptive_target = -1.000, adaptive_decay = 0.900
23
+ 0.00.745.419 I sampler chain: logits -> logit-bias -> ?penalties -> ?dry -> ?top-n-sigma -> top-k -> ?typical -> top-p -> min-p -> ?xtc -> temp-ext -> dist
24
+ 0.00.745.421 I generate: n_ctx = 512, n_batch = 2048, n_predict = 80, n_keep = 0
25
+ 0.00.745.421 I
26
+ <|im_start|><|object_ref_start|>환율 변동이 개인 투자에 미치는 영향과 대비 전략은 무엇인가요?<|im_end|> [end of text]
27
+
28
+
29
+ 0.00.745.437 I common_perf_print: sampling time = 0.00 ms
30
+ 0.00.745.438 I common_perf_print: samplers time = 0.00 ms / 16 tokens
31
+ 0.00.745.440 I common_perf_print: load time = 199.67 ms
32
+ 0.00.745.441 I common_perf_print: prompt eval time = 0.00 ms / 1 tokens ( 0.00 ms per token, inf tokens per second)
33
+ 0.00.745.442 I common_perf_print: eval time = 0.00 ms / 1 runs ( 0.00 ms per token, inf tokens per second)
34
+ 0.00.745.442 I common_perf_print: total time = 0.19 ms / 2 tokens
35
+ 0.00.745.443 I common_perf_print: unaccounted time = 0.19 ms / 98.5 % (total - sampling - prompt eval - eval) / (total)
36
+ 0.00.745.443 I common_perf_print: graphs reused = 0
reports/cpu_smoke_test_q5_k_m_biased2.txt ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+ 0.00.019.298 I llama_completion: llama backend init
5
+ 0.00.019.304 I llama_completion: load the model and apply lora adapter, if any
6
+ 0.00.019.314 I common_init_result: fitting params to device memory ...
7
+ 0.00.019.315 I common_init_result: (for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)
8
+ 0.00.319.746 I common_params_fit_impl: projected to use 1601 MiB of host memory vs. 2063714 MiB of total host memory
9
+ 0.00.482.433 W load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect
10
+ 0.00.600.443 W llama_context: n_ctx_seq (512) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
11
+ 0.00.793.072 I llama_completion: llama threadpool init, n_threads = 4
12
+ 0.00.793.087 I
13
+ 0.00.793.144 I system_info: n_threads = 4 (n_threads_batch = 4) / 224 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
14
+ 0.00.793.146 I
15
+ 0.00.793.243 I sampler seed: 42
16
+ 0.00.793.251 I sampler params:
17
+ repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
18
+ dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = -1
19
+ top_k = 40, top_p = 0.920, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.650
20
+ mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000, adaptive_target = -1.000, adaptive_decay = 0.900
21
+ 0.00.793.258 I sampler chain: logits -> logit-bias -> ?penalties -> ?dry -> ?top-n-sigma -> top-k -> ?typical -> top-p -> min-p -> ?xtc -> temp-ext -> dist
22
+ 0.00.793.259 I generate: n_ctx = 512, n_batch = 2048, n_predict = 80, n_keep = 0
23
+ 0.00.793.259 I
24
+ <|im_start|><|object_ref_start|>환율 변동이 개인 투자에 미치는 영향과 대비 전략은 무엇인가요?<|im_end|> [end of text]
25
+
26
+
27
+ 0.00.793.278 I common_perf_print: sampling time = 0.00 ms
28
+ 0.00.793.278 I common_perf_print: samplers time = 0.00 ms / 16 tokens
29
+ 0.00.793.281 I common_perf_print: load time = 209.04 ms
30
+ 0.00.793.282 I common_perf_print: prompt eval time = 0.00 ms / 1 tokens ( 0.00 ms per token, inf tokens per second)
31
+ 0.00.793.284 I common_perf_print: eval time = 0.00 ms / 1 runs ( 0.00 ms per token, inf tokens per second)
32
+ 0.00.793.284 I common_perf_print: total time = 0.21 ms / 2 tokens
33
+ 0.00.793.285 I common_perf_print: unaccounted time = 0.20 ms / 98.1 % (total - sampling - prompt eval - eval) / (total)
34
+ 0.00.793.285 I common_perf_print: graphs reused = 0
reports/cpu_smoke_test_q5_k_m_ignore_eos.txt ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+ 0.00.018.587 I llama_completion: llama backend init
5
+ 0.00.018.594 I llama_completion: load the model and apply lora adapter, if any
6
+ 0.00.018.605 I common_init_result: fitting params to device memory ...
7
+ 0.00.018.606 I common_init_result: (for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)
8
+ 0.00.319.421 I common_params_fit_impl: projected to use 1601 MiB of host memory vs. 2063714 MiB of total host memory
9
+ 0.00.484.114 W load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect
10
+ 0.00.594.877 W llama_context: n_ctx_seq (512) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
11
+ 0.00.780.020 I llama_completion: llama threadpool init, n_threads = 4
12
+ 0.00.780.042 I
13
+ 0.00.780.115 I system_info: n_threads = 4 (n_threads_batch = 4) / 224 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
14
+ 0.00.780.118 I
15
+ 0.00.780.300 I sampler seed: 42
16
+ 0.00.780.311 I sampler params:
17
+ repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
18
+ dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = -1
19
+ top_k = 40, top_p = 0.920, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.650
20
+ mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000, adaptive_target = -1.000, adaptive_decay = 0.900
21
+ 0.00.780.318 I sampler chain: logits -> logit-bias -> ?penalties -> ?dry -> ?top-n-sigma -> top-k -> ?typical -> top-p -> min-p -> ?xtc -> temp-ext -> dist
22
+ 0.00.780.321 I generate: n_ctx = 512, n_batch = 2048, n_predict = 80, n_keep = 0
23
+ 0.00.780.321 I
24
+ <|im_start|><|object_ref_start|>환율 변동이 개인 투자에 미치는 영향과 대비 전략은 무엇인가요?<|im_end|> [end of text]
25
+
26
+
27
+ 0.00.780.350 I common_perf_print: sampling time = 0.00 ms
28
+ 0.00.780.350 I common_perf_print: samplers time = 0.00 ms / 16 tokens
29
+ 0.00.780.354 I common_perf_print: load time = 202.76 ms
30
+ 0.00.780.355 I common_perf_print: prompt eval time = 0.00 ms / 1 tokens ( 0.00 ms per token, inf tokens per second)
31
+ 0.00.780.357 I common_perf_print: eval time = 0.00 ms / 1 runs ( 0.00 ms per token, inf tokens per second)
32
+ 0.00.780.357 I common_perf_print: total time = 0.33 ms / 2 tokens
33
+ 0.00.780.358 I common_perf_print: unaccounted time = 0.33 ms / 99.1 % (total - sampling - prompt eval - eval) / (total)
34
+ 0.00.780.358 I common_perf_print: graphs reused = 0
reports/cpu_smoke_test_q5_k_m_llama_cli_single_turn.txt ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+
5
+ Loading model...
6
+
7
+
8
+ ▄▄ ▄▄
9
+ ██ ██
10
+ ██ ██ ▀▀█▄ ███▄███▄ ▀▀█▄ ▄████ ████▄ ████▄
11
+ ██ ██ ▄█▀██ ██ ██ ██ ▄█▀██ ██ ██ ██ ██ ██
12
+ ██ ██ ▀█▄██ ██ ██ ██ ▀█▄██ ██ ▀████ ████▀ ████▀
13
+ ██ ██
14
+ ▀▀ ▀▀
15
+
16
+ build : b9263-6a257d446
17
+ model : KoHRM-Text-1.4B-Q5_K_M.gguf
18
+ modalities : text
19
+
20
+ available commands:
21
+ /exit or Ctrl+C stop or exit
22
+ /regen regenerate the last response
23
+ /clear clear the chat history
24
+ /read <file> add a text file
25
+ /glob <pattern> add text files using globbing pattern
26
+
27
+
28
+ > 질문: 대한민국 민법상 미성년자의 법률행위 취소에 대해 한 문단으로 설명하라.
29
+ 답변:
30
+
31
+
32
+ The user wants a single-word, concise explanation of 대한민국 민법상 미성년자의 법률행위 취소, which is a common misconception. The key insight is that 미성년자는 법적으로 일정 기간 동안(보통 10년)을 동안(10년)만 유효한, 즉, 10년 동안(10년)을 한 번 이상, 또는 10년 동안(10년)을 10,000,000,000,
33
+
34
+ [ Prompt: 16.9 t/s | Generation: 7.2 t/s ]
35
+
36
+ Exiting...
reports/file_sizes.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ -rw-r--r-- 1 work work 2.6G Jun 13 20:54 /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-BF16.gguf
2
+ -rw-r--r-- 1 work work 961M Jun 13 20:57 /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q5_K_M.gguf
3
+ -rw-r--r-- 1 work work 1.1G Jun 13 20:57 /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q6_K.gguf
4
+ -rw-r--r-- 1 work work 1.4G Jun 13 20:57 /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q8_0.gguf
reports/sha256sums.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ d5c66f994327c1e2f05b33b0a2ff798a1d05f8b905b7f93943e101bca06c8b0a /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-BF16.gguf
2
+ 90f47f54bd7cf545583a2be43a9d0c971cf6112ff16261e2e926cfabe2e9e35a /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q5_K_M.gguf
3
+ dd54d24344e842c3cd0f261e4b740c42c0ec78ed0b3414cdb8b2ac5022b7fb8a /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q6_K.gguf
4
+ 8dae86207987804c7e8fc34fcba0d78ae2e54cd8563e907e9e5aea8442f7300c /home/work/.artifacts/kohrm_gguf/gguf/KoHRM-Text-1.4B-Q8_0.gguf
reports/tokenization_probe_q5_k_m.txt ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ warning: no usable GPU found, --gpu-layers option will be ignored
2
+ warning: one possible reason is that llama.cpp was compiled without GPU support
3
+ warning: consult docs/build.md for compilation instructions
4
+ 0.00.020.667 I llama_completion: llama backend init
5
+ 0.00.020.672 I llama_completion: load the model and apply lora adapter, if any
6
+ 0.00.020.681 I common_init_result: fitting params to device memory ...
7
+ 0.00.020.682 I common_init_result: (for bugs during this step try to reproduce them with -fit off, or provide --verbose logs if the bug only occurs with -fit on)
8
+ 0.00.319.399 I common_params_fit_impl: projected to use 1601 MiB of host memory vs. 2063714 MiB of total host memory
9
+ 0.00.482.839 W load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect
10
+ 0.00.591.446 W llama_context: n_ctx_seq (512) < n_ctx_train (4096) -- the full capacity of the model will not be utilized
11
+ 0.00.768.838 I llama_completion: llama threadpool init, n_threads = 4
12
+ 0.00.768.852 I
13
+ 0.00.768.907 I system_info: n_threads = 4 (n_threads_batch = 4) / 224 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
14
+ 0.00.768.909 I
15
+ 0.00.768.999 I llama_completion: prompt: '<|im_start|><|object_ref_start|>환율 변동이 개인 투자에 미치는 영향과 대비 전략은 무엇인가요?<|im_end|>'
16
+ 0.00.769.001 I llama_completion: number of tokens in prompt = 16
17
+ 0.00.769.002 I 2 -> '<|im_start|>'
18
+ 0.00.769.002 I 32 -> '<|object_ref_start|>'
19
+ 0.00.769.003 I 89839 -> '환율'
20
+ 0.00.769.003 I 22305 -> ' 변동이'
21
+ 0.00.769.003 I 2647 -> ' 개인'
22
+ 0.00.769.003 I 58182 -> ' 투자에'
23
+ 0.00.769.004 I 8642 -> ' 미치는'
24
+ 0.00.769.004 I 101589 -> ' 영향과'
25
+ 0.00.769.004 I 8785 -> ' 대비'
26
+ 0.00.769.004 I 13153 -> ' 전략'
27
+ 0.00.769.005 I 406 -> '은'
28
+ 0.00.769.007 I 33789 -> ' 무엇'
29
+ 0.00.769.007 I 7156 -> '인가'
30
+ 0.00.769.007 I 703 -> '요'
31
+ 0.00.769.008 I 76 -> '?'
32
+ 0.00.769.008 I 3 -> '<|im_end|>'
33
+ 0.00.769.008 I
34
+ 0.00.769.010 I sampler seed: 42
35
+ 0.00.769.017 I sampler params:
36
+ repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
37
+ dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = -1
38
+ top_k = 40, top_p = 0.950, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, top_n_sigma = -1.000, temp = 0.800
39
+ mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000, adaptive_target = -1.000, adaptive_decay = 0.900
40
+ 0.00.769.022 I sampler chain: logits -> ?penalties -> ?dry -> ?top-n-sigma -> top-k -> ?typical -> top-p -> min-p -> ?xtc -> temp-ext -> dist
41
+ 0.00.769.023 I generate: n_ctx = 512, n_batch = 2048, n_predict = 1, n_keep = 0
42
+ 0.00.769.024 I
43
+ <|im_start|><|object_ref_start|>환율 변동이 개인 투자에 미치는 영향과 대비 전략은 무엇인가요?<|im_end|> [end of text]
44
+
45
+
46
+ 0.00.769.037 I common_perf_print: sampling time = 0.00 ms
47
+ 0.00.769.038 I common_perf_print: samplers time = 0.00 ms / 16 tokens
48
+ 0.00.769.040 I common_perf_print: load time = 200.87 ms
49
+ 0.00.769.042 I common_perf_print: prompt eval time = 0.00 ms / 1 tokens ( 0.00 ms per token, inf tokens per second)
50
+ 0.00.769.042 I common_perf_print: eval time = 0.00 ms / 1 runs ( 0.00 ms per token, inf tokens per second)
51
+ 0.00.769.043 I common_perf_print: total time = 0.20 ms / 2 tokens
52
+ 0.00.769.044 I common_perf_print: unaccounted time = 0.20 ms / 98.0 % (total - sampling - prompt eval - eval) / (total)
53
+ 0.00.769.045 I common_perf_print: graphs reused = 0
runtime/llama.cpp-hrm_text.patch ADDED
@@ -0,0 +1,582 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/conversion/__init__.py b/conversion/__init__.py
2
+ index 2c38123df..ecf1be2db 100644
3
+ --- a/conversion/__init__.py
4
+ +++ b/conversion/__init__.py
5
+ @@ -95,6 +95,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
6
+ "HunYuanDenseV1ForCausalLM": "hunyuan",
7
+ "HunYuanMoEV1ForCausalLM": "hunyuan",
8
+ "HunYuanVLForConditionalGeneration": "hunyuan",
9
+ + "HrmTextForCausalLM": "hrm_text",
10
+ "IQuestCoderForCausalLM": "llama",
11
+ "InternLM2ForCausalLM": "internlm",
12
+ "InternLM3ForCausalLM": "internlm",
13
+ diff --git a/conversion/hrm_text.py b/conversion/hrm_text.py
14
+ new file mode 100644
15
+ index 000000000..f5002a5c7
16
+ --- /dev/null
17
+ +++ b/conversion/hrm_text.py
18
+ @@ -0,0 +1,146 @@
19
+ +from __future__ import annotations
20
+ +
21
+ +import re
22
+ +import json
23
+ +from pathlib import Path
24
+ +
25
+ +from typing import Iterable, TYPE_CHECKING
26
+ +
27
+ +import torch
28
+ +from safetensors import safe_open
29
+ +
30
+ +if TYPE_CHECKING:
31
+ + from torch import Tensor
32
+ +
33
+ +from .base import ModelBase, TextModel, gguf, logger
34
+ +
35
+ +
36
+ +@ModelBase.register("HrmTextForCausalLM")
37
+ +class HrmTextModel(TextModel):
38
+ + model_arch = gguf.MODEL_ARCH.HRM_TEXT
39
+ +
40
+ + def __init__(self, *args, **kwargs):
41
+ + super().__init__(*args, **kwargs)
42
+ +
43
+ + with open(self.dir_model / "config.json", "r", encoding="utf-8") as f:
44
+ + self.raw_hparams = json.load(f)
45
+ +
46
+ + self.layers_per_stack = self._infer_layers_per_stack()
47
+ + self.h_cycles = self.raw_hparams["H_cycles"]
48
+ + self.l_cycles = self.raw_hparams["L_cycles"]
49
+ + self.physical_block_count = self.layers_per_stack * 2
50
+ + self.cache_block_count = self.layers_per_stack * self.h_cycles * (self.l_cycles + 1)
51
+ +
52
+ + # GGUF tensors store one physical L stack followed by one physical H stack.
53
+ + # The runtime expands these 32 physical layers across 128 KV-cache slots.
54
+ + self.block_count = self.physical_block_count
55
+ + self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
56
+ +
57
+ + def _infer_layers_per_stack(self) -> int:
58
+ + """Infer HRM stack depth from tensor names.
59
+ +
60
+ + Upstream HRM-Text exports use config["num_hidden_layers"] as the stack
61
+ + depth. KoHRM-Text exports currently store the total physical layer count
62
+ + there, while safetensors still contain separate 0..15 H and L stacks.
63
+ + The GGUF runtime needs the per-stack depth, so tensor names are the
64
+ + source of truth.
65
+ + """
66
+ + stack_depths: dict[str, set[int]] = {"H": set(), "L": set()}
67
+ + for path in sorted(Path(self.dir_model).glob("*.safetensors")):
68
+ + with safe_open(path, framework="pt", device="cpu") as f:
69
+ + for name in f.keys():
70
+ + match = re.match(r"model\.([LH])_module\.layers\.(\d+)\.", name)
71
+ + if match:
72
+ + stack_depths[match.group(1)].add(int(match.group(2)))
73
+ + if stack_depths["H"] and stack_depths["L"]:
74
+ + h_depth = max(stack_depths["H"]) + 1
75
+ + l_depth = max(stack_depths["L"]) + 1
76
+ + if h_depth != l_depth:
77
+ + raise ValueError(f"HRM H/L stack depth mismatch: H={h_depth}, L={l_depth}")
78
+ + return h_depth
79
+ + return int(self.raw_hparams["num_hidden_layers"])
80
+ +
81
+ + def set_vocab(self):
82
+ + # HRM-Text ships a Qwen2-style tokenizer.json. Keep it as a plain tokenizer;
83
+ + # do not add a chat template for validation GGUFs.
84
+ + self._set_vocab_gpt2()
85
+ +
86
+ + def get_vocab_base_pre(self, tokenizer) -> str:
87
+ + del tokenizer
88
+ + return "qwen2"
89
+ +
90
+ + def set_gguf_parameters(self):
91
+ + hp = self.raw_hparams
92
+ + head_dim = hp["head_dim"]
93
+ +
94
+ + self.gguf_writer.add_context_length(hp["max_position_embeddings"])
95
+ + self.gguf_writer.add_embedding_length(hp["hidden_size"])
96
+ + self.gguf_writer.add_block_count(self.cache_block_count)
97
+ + self.gguf_writer.add_feed_forward_length(hp["intermediate_size"])
98
+ + self.gguf_writer.add_head_count(hp["num_attention_heads"])
99
+ + self.gguf_writer.add_head_count_kv(hp["num_key_value_heads"])
100
+ + self.gguf_writer.add_key_length(head_dim)
101
+ + self.gguf_writer.add_value_length(head_dim)
102
+ + self.gguf_writer.add_rope_dimension_count(head_dim)
103
+ + self.gguf_writer.add_rope_freq_base(hp.get("rope_theta", 10000.0))
104
+ + self.gguf_writer.add_layer_norm_rms_eps(hp["rms_norm_eps"])
105
+ + self.gguf_writer.add_embedding_scale(hp["embedding_scale"])
106
+ +
107
+ + arch = self.gguf_writer.arch
108
+ + self.gguf_writer.add_uint32(gguf.Keys.LLM.HRM_LAYERS_PER_STACK.format(arch=arch), self.layers_per_stack)
109
+ + self.gguf_writer.add_uint32(gguf.Keys.LLM.HRM_H_CYCLES.format(arch=arch), self.h_cycles)
110
+ + self.gguf_writer.add_uint32(gguf.Keys.LLM.HRM_L_CYCLES.format(arch=arch), self.l_cycles)
111
+ + self.gguf_writer.add_bool(gguf.Keys.LLM.HRM_PREFIX_LM.format(arch=arch), bool(hp.get("prefix_lm", False)))
112
+ +
113
+ + def _format(self, key: gguf.MODEL_TENSOR, bid: int | None = None, suffix: str = ".weight") -> str:
114
+ + return self.format_tensor_name(key, bid=bid, suffix=suffix)
115
+ +
116
+ + def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
117
+ + if name == "model.embed_tokens.weight":
118
+ + yield self._format(gguf.MODEL_TENSOR.TOKEN_EMBD), data_torch
119
+ + return
120
+ +
121
+ + if name == "lm_head.weight":
122
+ + yield self._format(gguf.MODEL_TENSOR.OUTPUT), data_torch
123
+ + return
124
+ +
125
+ + if name == "model.z_L_init":
126
+ + yield self._format(gguf.MODEL_TENSOR.HRM_Z_L_INIT, suffix=""), data_torch
127
+ + return
128
+ +
129
+ + match = re.fullmatch(r"model\.([LH])_module\.layers\.(\d+)\.(.+)", name)
130
+ + if match is None:
131
+ + raise ValueError(f"Can not map tensor {name!r}")
132
+ +
133
+ + stack, layer_s, tensor_name = match.groups()
134
+ + layer_idx = int(layer_s)
135
+ + if layer_idx >= self.layers_per_stack:
136
+ + raise ValueError(f"Layer index {layer_idx} outside HRM stack size {self.layers_per_stack}")
137
+ +
138
+ + physical_bid = layer_idx + (self.layers_per_stack if stack == "H" else 0)
139
+ +
140
+ + if tensor_name == "attn.gqkv_proj.weight":
141
+ + gate, q, k, v = torch.chunk(data_torch, 4, dim=0)
142
+ + logger.debug("Split %s as gate, q, k, v", name)
143
+ + yield self._format(gguf.MODEL_TENSOR.ATTN_GATE, physical_bid), gate.contiguous()
144
+ + yield self._format(gguf.MODEL_TENSOR.ATTN_Q, physical_bid), q.contiguous()
145
+ + yield self._format(gguf.MODEL_TENSOR.ATTN_K, physical_bid), k.contiguous()
146
+ + yield self._format(gguf.MODEL_TENSOR.ATTN_V, physical_bid), v.contiguous()
147
+ + return
148
+ +
149
+ + if tensor_name == "attn.o_proj.weight":
150
+ + yield self._format(gguf.MODEL_TENSOR.ATTN_OUT, physical_bid), data_torch
151
+ + return
152
+ +
153
+ + if tensor_name == "mlp.gate_up_proj.weight":
154
+ + gate, up = torch.chunk(data_torch, 2, dim=0)
155
+ + logger.debug("Split %s as gate, up", name)
156
+ + yield self._format(gguf.MODEL_TENSOR.FFN_GATE, physical_bid), gate.contiguous()
157
+ + yield self._format(gguf.MODEL_TENSOR.FFN_UP, physical_bid), up.contiguous()
158
+ + return
159
+ +
160
+ + if tensor_name == "mlp.down_proj.weight":
161
+ + yield self._format(gguf.MODEL_TENSOR.FFN_DOWN, physical_bid), data_torch
162
+ + return
163
+ +
164
+ + raise ValueError(f"Can not map tensor {name!r}")
165
+ diff --git a/gguf-py/gguf/constants.py b/gguf-py/gguf/constants.py
166
+ index 7fdcf03d7..b84cc8827 100644
167
+ --- a/gguf-py/gguf/constants.py
168
+ +++ b/gguf-py/gguf/constants.py
169
+ @@ -144,6 +144,10 @@ class Keys:
170
+ TOKEN_SHIFT_COUNT = "{arch}.token_shift_count"
171
+ INTERLEAVE_MOE_LAYER_STEP = "{arch}.interleave_moe_layer_step"
172
+ FULL_ATTENTION_INTERVAL = "{arch}.full_attention_interval"
173
+ + HRM_LAYERS_PER_STACK = "{arch}.layers_per_stack"
174
+ + HRM_H_CYCLES = "{arch}.h_cycles"
175
+ + HRM_L_CYCLES = "{arch}.l_cycles"
176
+ + HRM_PREFIX_LM = "{arch}.prefix_lm"
177
+ ACTIVATION_SPARSITY_SCALE = "{arch}.activation_sparsity_scale"
178
+ ALTUP_ACTIVE_IDX = "{arch}.altup.active_idx"
179
+ ALTUP_NUM_INPUTS = "{arch}.altup.num_inputs"
180
+ @@ -410,6 +414,7 @@ class MODEL_ARCH(IntEnum):
181
+ QWEN3 = auto()
182
+ QWEN3MOE = auto()
183
+ QWEN3NEXT = auto()
184
+ + HRM_TEXT = auto()
185
+ QWEN3VL = auto()
186
+ QWEN3VLMOE = auto()
187
+ QWEN35 = auto()
188
+ @@ -527,6 +532,7 @@ class MODEL_TENSOR(IntEnum):
189
+ TOKEN_TYPES = auto()
190
+ POS_EMBD = auto()
191
+ OUTPUT = auto()
192
+ + HRM_Z_L_INIT = auto()
193
+ DENSE_2_OUT = auto() # embeddinggemma 2_Dense
194
+ DENSE_3_OUT = auto() # embeddinggemma 3_Dense
195
+ OUTPUT_NORM = auto()
196
+ @@ -925,6 +931,7 @@ MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = {
197
+ MODEL_ARCH.QWEN3: "qwen3",
198
+ MODEL_ARCH.QWEN3MOE: "qwen3moe",
199
+ MODEL_ARCH.QWEN3NEXT: "qwen3next",
200
+ + MODEL_ARCH.HRM_TEXT: "hrm_text",
201
+ MODEL_ARCH.QWEN3VL: "qwen3vl",
202
+ MODEL_ARCH.QWEN3VLMOE: "qwen3vlmoe",
203
+ MODEL_ARCH.QWEN35: "qwen35",
204
+ @@ -1042,6 +1049,7 @@ TENSOR_NAMES: dict[MODEL_TENSOR, str] = {
205
+ MODEL_TENSOR.POS_EMBD: "position_embd",
206
+ MODEL_TENSOR.OUTPUT_NORM: "output_norm",
207
+ MODEL_TENSOR.OUTPUT: "output",
208
+ + MODEL_TENSOR.HRM_Z_L_INIT: "hrm.z_l_init",
209
+ MODEL_TENSOR.DENSE_2_OUT: "dense_2", # embeddinggemma 2_Dense
210
+ MODEL_TENSOR.DENSE_3_OUT: "dense_3", # embeddinggemma 2_Dense
211
+ MODEL_TENSOR.ROPE_FREQS: "rope_freqs",
212
+ @@ -2057,6 +2065,19 @@ MODEL_TENSORS: dict[MODEL_ARCH, list[MODEL_TENSOR]] = {
213
+ MODEL_TENSOR.SSM_BETA_ALPHA,
214
+ MODEL_TENSOR.SSM_OUT
215
+ ],
216
+ + MODEL_ARCH.HRM_TEXT: [
217
+ + MODEL_TENSOR.TOKEN_EMBD,
218
+ + MODEL_TENSOR.OUTPUT,
219
+ + MODEL_TENSOR.HRM_Z_L_INIT,
220
+ + MODEL_TENSOR.ATTN_Q,
221
+ + MODEL_TENSOR.ATTN_K,
222
+ + MODEL_TENSOR.ATTN_V,
223
+ + MODEL_TENSOR.ATTN_GATE,
224
+ + MODEL_TENSOR.ATTN_OUT,
225
+ + MODEL_TENSOR.FFN_GATE,
226
+ + MODEL_TENSOR.FFN_DOWN,
227
+ + MODEL_TENSOR.FFN_UP,
228
+ + ],
229
+ MODEL_ARCH.QWEN3VL: [
230
+ MODEL_TENSOR.TOKEN_EMBD,
231
+ MODEL_TENSOR.OUTPUT_NORM,
232
+ diff --git a/src/llama-arch.cpp b/src/llama-arch.cpp
233
+ index c9eead18a..5b8ee3781 100644
234
+ --- a/src/llama-arch.cpp
235
+ +++ b/src/llama-arch.cpp
236
+ @@ -37,6 +37,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
237
+ { LLM_ARCH_QWEN3, "qwen3" },
238
+ { LLM_ARCH_QWEN3MOE, "qwen3moe" },
239
+ { LLM_ARCH_QWEN3NEXT, "qwen3next" },
240
+ + { LLM_ARCH_HRM_TEXT, "hrm_text" },
241
+ { LLM_ARCH_QWEN3VL, "qwen3vl" },
242
+ { LLM_ARCH_QWEN3VLMOE, "qwen3vlmoe" },
243
+ { LLM_ARCH_QWEN35, "qwen35" },
244
+ @@ -209,6 +210,10 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
245
+ { LLM_KV_TOKEN_SHIFT_COUNT, "%s.token_shift_count" },
246
+ { LLM_KV_INTERLEAVE_MOE_LAYER_STEP, "%s.interleave_moe_layer_step" },
247
+ { LLM_KV_FULL_ATTENTION_INTERVAL, "%s.full_attention_interval" },
248
+ + { LLM_KV_HRM_LAYERS_PER_STACK, "%s.layers_per_stack" },
249
+ + { LLM_KV_HRM_H_CYCLES, "%s.h_cycles" },
250
+ + { LLM_KV_HRM_L_CYCLES, "%s.l_cycles" },
251
+ + { LLM_KV_HRM_PREFIX_LM, "%s.prefix_lm" },
252
+
253
+ { LLM_KV_ATTENTION_HEAD_COUNT, "%s.attention.head_count" },
254
+ { LLM_KV_ATTENTION_HEAD_COUNT_KV, "%s.attention.head_count_kv" },
255
+ @@ -346,6 +351,7 @@ static const std::map<llm_tensor, const char *> LLM_TENSOR_NAMES = {
256
+ { LLM_TENSOR_OUTPUT_NORM, "output_norm" },
257
+ { LLM_TENSOR_OUTPUT_NORM_LFM2, "token_embd_norm" }, // fix for wrong tensor name
258
+ { LLM_TENSOR_OUTPUT, "output" },
259
+ + { LLM_TENSOR_HRM_Z_L_INIT, "hrm.z_l_init" },
260
+ { LLM_TENSOR_ROPE_FREQS, "rope_freqs" },
261
+ { LLM_TENSOR_ATTN_NORM, "blk.%d.attn_norm" },
262
+ { LLM_TENSOR_ATTN_Q, "blk.%d.attn_q" },
263
+ @@ -565,6 +571,7 @@ static const std::map<llm_tensor, llm_tensor_info> LLM_TENSOR_INFOS = {
264
+ {LLM_TENSOR_POS_EMBD, {LLM_TENSOR_LAYER_INPUT, GGML_OP_GET_ROWS}},
265
+ {LLM_TENSOR_TOKEN_TYPES, {LLM_TENSOR_LAYER_INPUT, GGML_OP_GET_ROWS}},
266
+ {LLM_TENSOR_TOKEN_EMBD_NORM, {LLM_TENSOR_LAYER_REPEATING, GGML_OP_MUL}}, // do the norms on the first layer (not the input layer)
267
+ + {LLM_TENSOR_HRM_Z_L_INIT, {LLM_TENSOR_LAYER_INPUT, GGML_OP_MUL}},
268
+ {LLM_TENSOR_OUTPUT, {LLM_TENSOR_LAYER_OUTPUT, GGML_OP_MUL_MAT}},
269
+ {LLM_TENSOR_CLS, {LLM_TENSOR_LAYER_OUTPUT, GGML_OP_MUL_MAT}},
270
+ {LLM_TENSOR_CLS_OUT, {LLM_TENSOR_LAYER_OUTPUT, GGML_OP_MUL_MAT}},
271
+ diff --git a/src/llama-arch.h b/src/llama-arch.h
272
+ index 89cf16cc3..fa04b684b 100644
273
+ --- a/src/llama-arch.h
274
+ +++ b/src/llama-arch.h
275
+ @@ -41,6 +41,7 @@ enum llm_arch {
276
+ LLM_ARCH_QWEN3,
277
+ LLM_ARCH_QWEN3MOE,
278
+ LLM_ARCH_QWEN3NEXT,
279
+ + LLM_ARCH_HRM_TEXT,
280
+ LLM_ARCH_QWEN3VL,
281
+ LLM_ARCH_QWEN3VLMOE,
282
+ LLM_ARCH_QWEN35,
283
+ @@ -213,6 +214,10 @@ enum llm_kv {
284
+ LLM_KV_TOKEN_SHIFT_COUNT,
285
+ LLM_KV_INTERLEAVE_MOE_LAYER_STEP,
286
+ LLM_KV_FULL_ATTENTION_INTERVAL,
287
+ + LLM_KV_HRM_LAYERS_PER_STACK,
288
+ + LLM_KV_HRM_H_CYCLES,
289
+ + LLM_KV_HRM_L_CYCLES,
290
+ + LLM_KV_HRM_PREFIX_LM,
291
+
292
+ LLM_KV_ATTENTION_HEAD_COUNT,
293
+ LLM_KV_ATTENTION_HEAD_COUNT_KV,
294
+ @@ -354,6 +359,7 @@ enum llm_tensor {
295
+ LLM_TENSOR_DENSE_2_OUT,
296
+ LLM_TENSOR_DENSE_3_OUT,
297
+ LLM_TENSOR_OUTPUT,
298
+ + LLM_TENSOR_HRM_Z_L_INIT,
299
+ LLM_TENSOR_OUTPUT_NORM,
300
+ LLM_TENSOR_OUTPUT_NORM_LFM2, // fix for wrong tensor name
301
+ LLM_TENSOR_ROPE_FREQS,
302
+ diff --git a/src/llama-context.cpp b/src/llama-context.cpp
303
+ index ad36c0666..fa80f4260 100644
304
+ --- a/src/llama-context.cpp
305
+ +++ b/src/llama-context.cpp
306
+ @@ -2208,6 +2208,9 @@ uint32_t llama_context::graph_max_nodes(uint32_t n_tokens) const {
307
+ if (model.arch == LLM_ARCH_QWEN3NEXT || model.arch == LLM_ARCH_KIMI_LINEAR || model.arch == LLM_ARCH_QWEN35 || model.arch == LLM_ARCH_QWEN35MOE) {
308
+ return std::max<uint32_t>(n_tokens * 40, 32u * model.n_tensors());
309
+ }
310
+ + if (model.arch == LLM_ARCH_HRM_TEXT) {
311
+ + return std::max<uint32_t>(n_tokens * 80, 64u * model.n_tensors());
312
+ + }
313
+ uint32_t res = std::max<uint32_t>(1024u, 8u*model.n_tensors());
314
+ for (const auto & lora : model.loras) {
315
+ res += lora->get_n_nodes();
316
+ diff --git a/src/llama-hparams.h b/src/llama-hparams.h
317
+ index e2d051edc..812598f69 100644
318
+ --- a/src/llama-hparams.h
319
+ +++ b/src/llama-hparams.h
320
+ @@ -164,6 +164,12 @@ struct llama_hparams {
321
+ float f_embedding_scale = 0.0f;
322
+ float f_attention_scale = 0.0f;
323
+
324
+ + // HRM-Text recurrence metadata. n_layer remains the expanded KV-cache slot count.
325
+ + uint32_t n_hrm_layer_per_stack = 0;
326
+ + uint32_t n_hrm_h_cycles = 0;
327
+ + uint32_t n_hrm_l_cycles = 0;
328
+ + bool hrm_prefix_lm = false;
329
+ +
330
+ // grok-2
331
+ float f_attn_out_scale = 0.0f;
332
+ uint32_t attn_temp_length = 0;
333
+ diff --git a/src/llama-model-saver.cpp b/src/llama-model-saver.cpp
334
+ index 528e4c9c0..8a6e009c6 100644
335
+ --- a/src/llama-model-saver.cpp
336
+ +++ b/src/llama-model-saver.cpp
337
+ @@ -245,6 +245,10 @@ void llama_model_saver::add_kv_from_model() {
338
+ add_kv(LLM_KV_TOKEN_SHIFT_COUNT, hparams.token_shift_count);
339
+ add_kv(LLM_KV_INTERLEAVE_MOE_LAYER_STEP, hparams.n_moe_layer_step);
340
+ // add_kv(LLM_KV_FULL_ATTENTION_INTERVAL, ???);
341
+ + add_kv(LLM_KV_HRM_LAYERS_PER_STACK, hparams.n_hrm_layer_per_stack);
342
+ + add_kv(LLM_KV_HRM_H_CYCLES, hparams.n_hrm_h_cycles);
343
+ + add_kv(LLM_KV_HRM_L_CYCLES, hparams.n_hrm_l_cycles);
344
+ + add_kv(LLM_KV_HRM_PREFIX_LM, hparams.hrm_prefix_lm);
345
+
346
+ add_kv(LLM_KV_ATTENTION_HEAD_COUNT, hparams.n_head_arr, true);
347
+ add_kv(LLM_KV_ATTENTION_HEAD_COUNT_KV, hparams.n_head_kv_arr, true);
348
+ diff --git a/src/llama-model.cpp b/src/llama-model.cpp
349
+ index 8bf20a716..a3cc996aa 100644
350
+ --- a/src/llama-model.cpp
351
+ +++ b/src/llama-model.cpp
352
+ @@ -96,6 +96,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
353
+ return new llama_model_qwen2moe(params);
354
+ case LLM_ARCH_QWEN3:
355
+ return new llama_model_qwen3(params);
356
+ + case LLM_ARCH_HRM_TEXT:
357
+ + return new llama_model_hrm_text(params);
358
+ case LLM_ARCH_QWEN3MOE:
359
+ return new llama_model_qwen3moe(params);
360
+ case LLM_ARCH_QWEN3VL:
361
+ @@ -2339,6 +2341,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
362
+ case LLM_ARCH_PANGU_EMBED:
363
+ case LLM_ARCH_AFMOE:
364
+ case LLM_ARCH_QWEN3NEXT:
365
+ + case LLM_ARCH_HRM_TEXT:
366
+ case LLM_ARCH_MIMO2:
367
+ case LLM_ARCH_STEP35:
368
+ return LLAMA_ROPE_TYPE_NEOX;
369
+ diff --git a/src/models/hrm-text.cpp b/src/models/hrm-text.cpp
370
+ new file mode 100644
371
+ index 000000000..e0a3e9f59
372
+ --- /dev/null
373
+ +++ b/src/models/hrm-text.cpp
374
+ @@ -0,0 +1,183 @@
375
+ +#include "models.h"
376
+ +
377
+ +#include <cmath>
378
+ +#include <vector>
379
+ +
380
+ +void llama_model_hrm_text::load_arch_hparams(llama_model_loader & ml) {
381
+ + ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
382
+ + ml.get_key(LLM_KV_EMBEDDING_SCALE, hparams.f_embedding_scale);
383
+ + ml.get_key(LLM_KV_HRM_LAYERS_PER_STACK, hparams.n_hrm_layer_per_stack);
384
+ + ml.get_key(LLM_KV_HRM_H_CYCLES, hparams.n_hrm_h_cycles);
385
+ + ml.get_key(LLM_KV_HRM_L_CYCLES, hparams.n_hrm_l_cycles);
386
+ + ml.get_key(LLM_KV_HRM_PREFIX_LM, hparams.hrm_prefix_lm, false);
387
+ +
388
+ + switch (hparams.n_embd) {
389
+ + case 1536: type = LLM_TYPE_1B; break;
390
+ + default: type = LLM_TYPE_UNKNOWN;
391
+ + }
392
+ +}
393
+ +
394
+ +void llama_model_hrm_text::load_arch_tensors(llama_model_loader &) {
395
+ + LLAMA_LOAD_LOCALS;
396
+ +
397
+ + const int64_t n_stack = hparams.n_hrm_layer_per_stack;
398
+ + const int64_t n_cycle_slots = n_stack * (hparams.n_hrm_l_cycles + 1);
399
+ +
400
+ + tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
401
+ + output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, 0);
402
+ +
403
+ + hrm_z_l_init = create_tensor(tn(LLM_TENSOR_HRM_Z_L_INIT), {n_embd}, 0);
404
+ +
405
+ + std::vector<bool> loaded_physical(2 * n_stack, false);
406
+ +
407
+ + for (int il = 0; il < n_layer; ++il) {
408
+ + auto & layer = layers[il];
409
+ +
410
+ + const int64_t layer_in_stack = il % n_stack;
411
+ + const int64_t phase = (il % n_cycle_slots) / n_stack;
412
+ + const bool is_h_stack = phase == int64_t(hparams.n_hrm_l_cycles);
413
+ + const int physical_bid = int((is_h_stack ? n_stack : 0) + layer_in_stack);
414
+ +
415
+ + const int flags = loaded_physical[physical_bid] ? TENSOR_DUPLICATED : 0;
416
+ + loaded_physical[physical_bid] = true;
417
+ +
418
+ + create_tensor_qkv(layer, physical_bid,
419
+ + n_embd,
420
+ + n_embd_head_k * n_head,
421
+ + n_embd_k_gqa,
422
+ + n_embd_v_gqa,
423
+ + flags);
424
+ +
425
+ + layer.wqkv_gate = create_tensor(tn(LLM_TENSOR_ATTN_GATE, "weight", physical_bid), {n_embd, n_embd_head_k * n_head}, flags);
426
+ + layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", physical_bid), {n_embd_head_k * n_head, n_embd}, flags);
427
+ +
428
+ + layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", physical_bid), {n_embd, n_ff}, flags);
429
+ + layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", physical_bid), {n_ff, n_embd}, flags);
430
+ + layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", physical_bid), {n_embd, n_ff}, flags);
431
+ + }
432
+ +}
433
+ +
434
+ +std::unique_ptr<llm_graph_context> llama_model_hrm_text::build_arch_graph(const llm_graph_params & params) const {
435
+ + return std::make_unique<graph>(*this, params);
436
+ +}
437
+ +
438
+ +llama_model_hrm_text::graph::graph(const llama_model & model_, const llm_graph_params & params) : llm_graph_context(params) {
439
+ + const auto & model = static_cast<const llama_model_hrm_text &>(model_);
440
+ +
441
+ + GGML_ASSERT(model.tok_embd != nullptr);
442
+ + GGML_ASSERT(model.output != nullptr);
443
+ + GGML_ASSERT(model.hrm_z_l_init != nullptr);
444
+ +
445
+ + const int64_t n_embd_head = hparams.n_embd_head_v();
446
+ + GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
447
+ + GGML_ASSERT(n_embd_head == n_rot);
448
+ +
449
+ + const int64_t n_stack = hparams.n_hrm_layer_per_stack;
450
+ + const int64_t h_cycles = hparams.n_hrm_h_cycles;
451
+ + const int64_t l_cycles = hparams.n_hrm_l_cycles;
452
+ +
453
+ + ggml_tensor * inp_pos = build_inp_pos();
454
+ + auto * inp_attn = build_attn_inp_kv();
455
+ + ggml_tensor * inp_out_ids = build_inp_out_ids();
456
+ +
457
+ + ggml_tensor * hidden_high = build_inp_embd(model.tok_embd);
458
+ + ggml_tensor * hidden_low = ggml_repeat(ctx0, model.hrm_z_l_init, hidden_high);
459
+ + cb(hidden_low, "hrm_z_l_init", -1);
460
+ +
461
+ + const float kq_scale = 1.0f / std::sqrt(float(n_embd_head));
462
+ +
463
+ + auto build_stack = [&](ggml_tensor * stack_inp, int slot_offset) -> ggml_tensor * {
464
+ + ggml_tensor * stack_cur = stack_inp;
465
+ +
466
+ + for (int layer_idx = 0; layer_idx < n_stack; ++layer_idx) {
467
+ + const int il = slot_offset + layer_idx;
468
+ + const auto & layer = model.layers[il];
469
+ +
470
+ + ggml_tensor * inpSA = stack_cur;
471
+ + ggml_tensor * cur = build_norm(stack_cur, nullptr, nullptr, LLM_NORM_RMS, il);
472
+ + cb(cur, "attn_norm", il);
473
+ +
474
+ + {
475
+ + ggml_tensor * attn_inp = cur;
476
+ + auto [Qcur, Kcur, Vcur] = build_qkv(layer, cur, n_embd_head, n_head, n_head_kv, il);
477
+ +
478
+ + ggml_tensor * gate = build_lora_mm(layer.wqkv_gate, attn_inp, layer.wqkv_gate_s);
479
+ + cb(gate, "attn_gate_proj", il);
480
+ +
481
+ + Qcur = ggml_rope_ext(
482
+ + ctx0, Qcur, inp_pos, nullptr,
483
+ + n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
484
+ + ext_factor, attn_factor, beta_fast, beta_slow);
485
+ + cb(Qcur, "Qcur_rope", il);
486
+ +
487
+ + Kcur = ggml_rope_ext(
488
+ + ctx0, Kcur, inp_pos, nullptr,
489
+ + n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
490
+ + ext_factor, attn_factor, beta_fast, beta_slow);
491
+ + cb(Kcur, "Kcur_rope", il);
492
+ +
493
+ + cur = build_attn(inp_attn,
494
+ + nullptr, nullptr, nullptr,
495
+ + Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, kq_scale, il);
496
+ + cb(cur, "attn_out", il);
497
+ +
498
+ + gate = ggml_sigmoid(ctx0, gate);
499
+ + cb(gate, "attn_gate_sig", il);
500
+ +
501
+ + cur = ggml_mul(ctx0, cur, gate);
502
+ + cb(cur, "attn_gated", il);
503
+ +
504
+ + cur = build_lora_mm(layer.wo, cur, layer.wo_s);
505
+ + cb(cur, "attn_o_proj", il);
506
+ + }
507
+ +
508
+ + ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
509
+ + cb(ffn_inp, "ffn_inp", il);
510
+ +
511
+ + cur = build_norm(ffn_inp, nullptr, nullptr, LLM_NORM_RMS, il);
512
+ + cb(cur, "ffn_norm", il);
513
+ +
514
+ + cur = build_ffn(cur,
515
+ + layer.ffn_up, nullptr, layer.ffn_up_s,
516
+ + layer.ffn_gate, nullptr, layer.ffn_gate_s,
517
+ + layer.ffn_down, nullptr, layer.ffn_down_s,
518
+ + nullptr,
519
+ + LLM_FFN_SILU, LLM_FFN_PAR, il);
520
+ + cb(cur, "ffn_out", il);
521
+ +
522
+ + cur = ggml_add(ctx0, cur, ffn_inp);
523
+ + cur = build_cvec(cur, il);
524
+ + cb(cur, "hrm_layer_out", il);
525
+ +
526
+ + stack_cur = cur;
527
+ + }
528
+ +
529
+ + stack_cur = build_norm(stack_cur, nullptr, nullptr, LLM_NORM_RMS, slot_offset);
530
+ + cb(stack_cur, "stack_final_norm", slot_offset);
531
+ + return stack_cur;
532
+ + };
533
+ +
534
+ + for (int h = 0; h < h_cycles; ++h) {
535
+ + for (int l = 0; l < l_cycles; ++l) {
536
+ + const int slot_offset = int((h * (l_cycles + 1) + l) * n_stack);
537
+ + hidden_low = build_stack(ggml_add(ctx0, hidden_low, hidden_high), slot_offset);
538
+ + }
539
+ +
540
+ + const int slot_offset = int((h * (l_cycles + 1) + l_cycles) * n_stack);
541
+ + hidden_high = build_stack(ggml_add(ctx0, hidden_high, hidden_low), slot_offset);
542
+ + }
543
+ +
544
+ + ggml_tensor * cur = hidden_high;
545
+ +
546
+ + if (inp_out_ids) {
547
+ + cur = ggml_get_rows(ctx0, cur, inp_out_ids);
548
+ + }
549
+ +
550
+ + res->t_embd = cur;
551
+ +
552
+ + cur = build_lora_mm(model.output, cur, model.output_s);
553
+ + cb(cur, "result_output", -1);
554
+ +
555
+ + res->t_logits = cur;
556
+ + ggml_build_forward_expand(gf, cur);
557
+ +}
558
+ diff --git a/src/models/models.h b/src/models/models.h
559
+ index 7e551eb96..7da6b7f7f 100644
560
+ --- a/src/models/models.h
561
+ +++ b/src/models/models.h
562
+ @@ -515,6 +515,20 @@ struct llama_model_qwen3 : public llama_model_base {
563
+ std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
564
+ };
565
+
566
+ +struct llama_model_hrm_text : public llama_model_base {
567
+ + llama_model_hrm_text(const struct llama_model_params & params) : llama_model_base(params) {}
568
+ + void load_arch_hparams(llama_model_loader & ml) override;
569
+ + void load_arch_tensors(llama_model_loader & ml) override;
570
+ +
571
+ + ggml_tensor * hrm_z_l_init = nullptr;
572
+ +
573
+ + struct graph : public llm_graph_context {
574
+ + graph(const llama_model & model, const llm_graph_params & params);
575
+ + };
576
+ +
577
+ + std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
578
+ +};
579
+ +
580
+
581
+ struct llama_model_qwen3moe : public llama_model_base {
582
+ llama_model_qwen3moe(const struct llama_model_params & params) : llama_model_base(params) {}