lowbitcoffee commited on
Commit
55c92ae
·
verified ·
1 Parent(s): 98a899c

Add GLM-5.2-W4A16 (INT4 weights, BF16 activations)

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ 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
+ model.safetensors.index.json filter=lfs diff=lfs merge=lfs -text
37
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: transformers
4
+ pipeline_tag: text-generation
5
+ base_model: zai-org/GLM-5.2
6
+ tags:
7
+ - glm
8
+ - moe
9
+ - quantized
10
+ - w4a16
11
+ - int4
12
+ - compressed-tensors
13
+ - vllm
14
+ language:
15
+ - en
16
+ - zh
17
+ ---
18
+
19
+ # GLM-5.2-W4A16
20
+
21
+ 4-bit (W4A16) weight-quantized version of [**zai-org/GLM-5.2**](https://huggingface.co/zai-org/GLM-5.2).
22
+
23
+ Weights are quantized to **INT4** (group size 128); activations run in **BF16**. The
24
+ result is a **388 GB** checkpoint — about **3.9× smaller** than the 1.5 TB BF16
25
+ original — that fits on a single 8×A100 (80 GB) node while preserving full-precision
26
+ quality on reasoning and knowledge benchmarks.
27
+
28
+ Because compute stays in BF16 and only the weights are INT4, this model runs on
29
+ **NVIDIA Ampere (A100) and newer** — it does **not** require Hopper/Blackwell FP8 support.
30
+
31
+ ## Highlights
32
+
33
+ - **Quality on par with the FP8 release** — no measurable degradation (see below).
34
+ - **~3.9× smaller** than BF16: 388 GB vs. 1.5 TB.
35
+ - **Runs on A100** (Ampere) — no FP8 hardware needed.
36
+ - Serves out of the box with **vLLM** (`compressed-tensors` format).
37
+
38
+ ## Evaluation
39
+
40
+ Evaluated against the reference **FP8** deployment of GLM-5.2. Greedy decoding
41
+ (temperature 0); reasoning traces stripped and the final answer graded.
42
+
43
+ | Benchmark | This model (W4A16) | Reference (FP8) |
44
+ |---|---|---|
45
+ | GSM8K (n=200), exact-match | **96.5%** | 94.5% |
46
+ | MMLU (n=200), accuracy | **86.5%** | 80.0% |
47
+
48
+ W4A16 matches the FP8 reference within evaluation noise (n=200, standard error
49
+ ≈ 2 pts). The takeaway is **parity** — 4-bit quantization retains GLM-5.2's
50
+ reasoning and knowledge capability.
51
+
52
+ ## Model details
53
+
54
+ | | |
55
+ |---|---|
56
+ | Base model | `zai-org/GLM-5.2` |
57
+ | Architecture | `GlmMoeDsaForCausalLM` (MoE, 78 layers, 256 routed + 1 shared expert, top-8) |
58
+ | Weight precision | INT4, group size 128, symmetric |
59
+ | Activation precision | BF16 |
60
+ | Format | `compressed-tensors` (`pack-quantized`) |
61
+ | Checkpoint size | 388 GB (8 shards) |
62
+ | Context length | up to 1,048,576 tokens |
63
+
64
+ The sparse-attention (DSA) indexer, the MoE router, and the LM head are kept in
65
+ BF16; the large linear and expert weights carry the INT4 quantization.
66
+
67
+ ## Serving on A100 (8× A100 80 GB, vLLM)
68
+
69
+ The full INT4 checkpoint fits on one 8×A100-80GB node with room for KV cache.
70
+
71
+ ```bash
72
+ pip install "vllm>=0.24.0"
73
+
74
+ # A100 (Ampere) note: use BF16 compute paths and skip Hopper-only kernels.
75
+ export VLLM_USE_FLASHINFER_SAMPLER=0 # avoid FlashInfer sampler JIT on some CUDA toolkits
76
+ export VLLM_USE_DEEP_GEMM=0 # DeepGEMM (FP8 block-scale) is not needed on A100
77
+
78
+ vllm serve lowbitcoffee/GLM-5.2-W4A16 \
79
+ --tensor-parallel-size 8 \
80
+ --dtype bfloat16 \
81
+ --max-model-len 32768 \
82
+ --gpu-memory-utilization 0.92 \
83
+ --served-model-name glm-5.2-w4a16 \
84
+ --trust-remote-code
85
+ ```
86
+
87
+ vLLM auto-detects the quantization from the checkpoint — no `--quantization`
88
+ flag is required. Increase `--max-model-len` toward the model's 1M limit only if
89
+ you have KV-cache headroom; lower it to raise concurrency.
90
+
91
+ > On 8× **A100 40 GB**, the weights alone (388 GB) exceed the 320 GB of aggregate
92
+ > VRAM — use two nodes (`--tensor-parallel-size 16`) or the 80 GB SKU.
93
+
94
+ ### Query it (OpenAI-compatible)
95
+
96
+ ```bash
97
+ curl http://localhost:8000/v1/chat/completions \
98
+ -H "Content-Type: application/json" \
99
+ -d '{
100
+ "model": "glm-5.2-w4a16",
101
+ "messages": [{"role": "user", "content": "What is 84 * 3 / 2?"}],
102
+ "max_tokens": 1024,
103
+ "temperature": 0
104
+ }'
105
+ ```
106
+
107
+ ```python
108
+ from openai import OpenAI
109
+
110
+ client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
111
+ resp = client.chat.completions.create(
112
+ model="glm-5.2-w4a16",
113
+ messages=[{"role": "user", "content": "Explain MoE routing in two sentences."}],
114
+ max_tokens=1024,
115
+ temperature=0.6,
116
+ )
117
+ print(resp.choices[0].message.content)
118
+ ```
119
+
120
+ GLM-5.2 is a reasoning model: responses may include a `<think>…</think>` block
121
+ before the final answer. Strip it client-side, or configure a reasoning parser
122
+ in your serving stack if you want the fields separated.
123
+
124
+ ## License
125
+
126
+ Released under the **MIT** license, inheriting the license of the base model
127
+ `zai-org/GLM-5.2`.
chat_template.jinja ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [gMASK]<sop>
2
+ {%- set effective_reasoning_effort = 'high' if reasoning_effort is defined and reasoning_effort == 'high' else 'max' -%}
3
+ {%- if (enable_thinking is not defined or enable_thinking) and effective_reasoning_effort is not none -%}<|system|>Reasoning Effort: {{ effective_reasoning_effort | capitalize }}{%- endif -%}
4
+ {%- if tools -%}
5
+ {%- macro tool_to_json(tool) -%}
6
+ {%- set ns_tool = namespace(first=true) -%}
7
+ {{ '{' -}}
8
+ {%- for k, v in tool.items() -%}
9
+ {%- if k != 'defer_loading' and k != 'strict' -%}
10
+ {%- if not ns_tool.first -%}{{- ', ' -}}{%- endif -%}
11
+ {%- set ns_tool.first = false -%}
12
+ "{{ k }}": {{ v | tojson(ensure_ascii=False) }}
13
+ {%- endif -%}
14
+ {%- endfor -%}
15
+ {{- '}' -}}
16
+ {%- endmacro -%}
17
+ <|system|>
18
+ # Tools
19
+
20
+ You may call one or more functions to assist with the user query.
21
+
22
+ You are provided with function signatures within <tools></tools> XML tags:
23
+ <tools>
24
+ {% for tool in tools %}
25
+ {%- if 'function' in tool -%}
26
+ {%- set tool = tool['function'] -%}
27
+ {%- endif -%}
28
+ {% if tool.defer_loading is not defined or not tool.defer_loading %}
29
+ {{ tool_to_json(tool) }}
30
+ {% endif %}
31
+ {% endfor %}
32
+ </tools>
33
+
34
+ For each function call, output the function name and arguments within the following XML format:
35
+ <tool_call>{function-name}<arg_key>{arg-key-1}</arg_key><arg_value>{arg-value-1}</arg_value><arg_key>{arg-key-2}</arg_key><arg_value>{arg-value-2}</arg_value>...</tool_call>{%- endif -%}
36
+ {%- macro visible_text(content) -%}
37
+ {%- if content is string -%}
38
+ {{- content }}
39
+ {%- elif content is iterable and content is not mapping -%}
40
+ {%- for item in content -%}
41
+ {%- if item is mapping and item.type == 'text' -%}
42
+ {{- item.text }}
43
+ {%- elif item is string -%}
44
+ {{- item }}
45
+ {%- elif item is mapping and item.type in ['image', 'image_url', 'video', 'video_url', 'audio', 'audio_url', 'input_audio'] -%}
46
+ {%- set media_type = item.type | replace('_url', '') | replace('input_', '') -%}
47
+ {{- "<reminder>You are unable to process this " ~ media_type ~ " because you don't have multi-modal input ability. Try different methods.</reminder>" }}
48
+ {%- endif -%}
49
+ {%- endfor -%}
50
+ {%- else -%}
51
+ {{- content }}
52
+ {%- endif -%}
53
+ {%- endmacro -%}
54
+ {%- set ns = namespace(last_user_index=-1) -%}
55
+ {%- for m in messages %}
56
+ {%- if m.role == 'user' %}
57
+ {%- set ns.last_user_index = loop.index0 -%}
58
+ {%- endif %}
59
+ {%- endfor %}
60
+ {%- for m in messages -%}
61
+ {%- if m.role == 'user' -%}<|user|>{{ visible_text(m.content) }}
62
+ {%- elif m.role == 'assistant' -%}
63
+ <|assistant|>
64
+ {%- set content = visible_text(m.content) %}
65
+ {%- if m.reasoning_content is string %}
66
+ {%- set reasoning_content = m.reasoning_content %}
67
+ {%- elif '</think>' in content %}
68
+ {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}
69
+ {%- set content = content.split('</think>')[-1] %}
70
+ {%- endif %}
71
+ {%- if ((clear_thinking is defined and not clear_thinking) or loop.index0 > ns.last_user_index) and reasoning_content is defined -%}
72
+ {{ '<think>' + reasoning_content + '</think>'}}
73
+ {%- else -%}
74
+ {{ '<think></think>' }}
75
+ {%- endif -%}
76
+ {%- if content.strip() -%}
77
+ {{ content.strip() }}
78
+ {%- endif -%}
79
+ {% if m.tool_calls %}
80
+ {% for tc in m.tool_calls %}
81
+ {%- if tc.function %}
82
+ {%- set tc = tc.function %}
83
+ {%- endif %}
84
+ {{- '<tool_call>' + tc.name -}}
85
+ {% set _args = tc.arguments %}{% for k, v in _args.items() %}<arg_key>{{ k }}</arg_key><arg_value>{{ v | tojson(ensure_ascii=False) if v is not string else v }}</arg_value>{% endfor %}</tool_call>{% endfor %}
86
+ {% endif %}
87
+ {%- elif m.role == 'tool' -%}
88
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
89
+ {{- '<|observation|>' -}}
90
+ {%- endif %}
91
+ {%- if m.content is string -%}
92
+ {{- '<tool_response>' + m.content + '</tool_response>' -}}
93
+ {%- elif m.content is iterable and m.content is not mapping and m.content and m.content.0.type == "tool_reference" -%}
94
+ {{- '<tool_response><tools>\n' -}}
95
+ {% for tr in m.content %}
96
+ {%- for tool in tools -%}
97
+ {%- if 'function' in tool -%}
98
+ {%- set tool = tool['function'] -%}
99
+ {%- endif -%}
100
+ {%- if tool.name == tr.name -%}
101
+ {{- tool_to_json(tool) + '\n' -}}
102
+ {%- endif -%}
103
+ {%- endfor -%}
104
+ {%- endfor -%}
105
+ {{- '</tools></tool_response>' -}}
106
+ {%- elif m.content is iterable and m.content is not mapping and m.content and m.content.0 is mapping and m.content.0.output is defined -%}
107
+ {%- for tr in m.content -%}
108
+ {{- '<tool_response>' + tr.output + '</tool_response>' -}}
109
+ {%- endfor -%}
110
+ {%- else -%}
111
+ {{- '<tool_response>' + visible_text(m.content) + '</tool_response>' -}}
112
+ {% endif -%}
113
+ {%- elif m.role == 'system' -%}
114
+ <|system|>{{ visible_text(m.content) }}
115
+ {%- endif -%}
116
+ {%- endfor -%}
117
+ {%- if add_generation_prompt -%}
118
+ <|assistant|>{{- '<think></think>' if (enable_thinking is defined and not enable_thinking) else '<think>' -}}
119
+ {%- endif -%}
config.json ADDED
The diff for this file is too large to render. See raw diff
 
generation_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "do_sample": true,
4
+ "eos_token_id": [
5
+ 154820,
6
+ 154827,
7
+ 154829
8
+ ],
9
+ "pad_token_id": 154820,
10
+ "temperature": 1.0,
11
+ "top_p": 0.95,
12
+ "transformers_version": "5.10.1"
13
+ }
model-00001-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0c34baff8bc0746006fc73880f1ffc47a6405bcd0f0819b2c4210baf22ad5d19
3
+ size 49997402336
model-00002-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8d5ed084a714e0d89ffa067ca12a8bc3c3a17d0dc0f35b4a581aa894fdfb581b
3
+ size 49999575032
model-00003-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d34cc57c7d24b5bd339fa0083e20d4c91c61ab794d7e366853fb7d537f403445
3
+ size 49999575008
model-00004-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9d106fec8a9a59f1f680951393eed0a91c9f173d302d8e75ad20edeaf96c7c9e
3
+ size 49999575280
model-00005-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65a0ea903313997d647ec5711f72d105a764dc5522d2176df3bbd6bfc49bb93d
3
+ size 49999575520
model-00006-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:72caa80144360ec26705388f8af993c582926ed362140ad5c91e265c6f1e556e
3
+ size 50002867272
model-00007-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bd76639c4eff7c58c8e13e9a68aee04d0396698d48fbadb896c0d157b9b1630d
3
+ size 49999575032
model-00008-of-00008.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:61f3ecffa2e554661d1ebe5075715d9128a0cf0d5701267c1dc621db3f172a0a
3
+ size 37691064128
model.safetensors.index.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:74d73bfaa26425beaf618342f4a0851b21d9198138b76bfb678f88164d987beb
3
+ size 17041081
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:19e773648cb4e65de8660ea6365e10acca112d42a854923df93db4a6f333a82d
3
+ size 20217442
tokenizer_config.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": false,
4
+ "do_lower_case": false,
5
+ "eos_token": "<|endoftext|>",
6
+ "extra_special_tokens": [
7
+ "<|endoftext|>",
8
+ "[MASK]",
9
+ "[gMASK]",
10
+ "[sMASK]",
11
+ "<sop>",
12
+ "<eop>",
13
+ "<|system|>",
14
+ "<|user|>",
15
+ "<|assistant|>",
16
+ "<|observation|>",
17
+ "<|begin_of_image|>",
18
+ "<|end_of_image|>",
19
+ "<|begin_of_video|>",
20
+ "<|end_of_video|>",
21
+ "<|begin_of_audio|>",
22
+ "<|end_of_audio|>",
23
+ "<|begin_of_transcription|>",
24
+ "<|end_of_transcription|>"
25
+ ],
26
+ "is_local": true,
27
+ "local_files_only": true,
28
+ "model_max_length": 1048576,
29
+ "model_specific_special_tokens": {},
30
+ "pad_token": "<|endoftext|>",
31
+ "padding_side": "left",
32
+ "remove_space": false,
33
+ "tokenizer_class": "TokenizersBackend"
34
+ }