AlexWuKing commited on
Commit
e6aa636
·
1 Parent(s): beb8107
.gitattributes CHANGED
@@ -33,3 +33,4 @@ 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
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .DS_Store
README.md CHANGED
@@ -1,3 +1,84 @@
1
- ---
2
- license: mit
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # gemma-3-4b-it-qat-4bit-lite
2
+
3
+ Optimized version of [gemma-3-4b-it-qat-4bit](https://huggingface.co/google/gemma-3-4b-it-qat-q4_0_4_8) for Apple Silicon edge devices. Reduces model size from 2.8 GB to 2.3 GB with lower runtime memory and significantly reduced thermal output, while preserving text and image understanding quality.
4
+
5
+ ## Optimizations Applied
6
+
7
+ | Step | Optimization | Effect |
8
+ |------|-------------|--------|
9
+ | 1 | Vocabulary pruning 262K → 144K tokens | -170 MB disk, token_map remapping |
10
+ | 2 | Vision fc2 bf16 → 4-bit (pad 4304 → 4352) | -191 MB disk |
11
+ | 3 | Remove text layers 31, 32, 33 (34 → 31 layers) | -159 MB disk, faster inference |
12
+ | 4 | Image resolution 896 → 672 | ~3x less vision attention compute |
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ Text model:
18
+ vocab_size: 262,208 (token_map → 144,257 compact embeddings)
19
+ hidden_size: 2560
20
+ intermediate_size: 10240
21
+ num_hidden_layers: 31
22
+ num_attention_heads: 8 (GQA, 4 KV heads)
23
+ head_dim: 256
24
+ quantization: 4-bit, group_size=64
25
+
26
+ Vision model (SigLIP):
27
+ hidden_size: 1152
28
+ intermediate_size: 4352 (padded from 4304, fc2 4-bit quantized)
29
+ num_hidden_layers: 27
30
+ image_size: 672
31
+ patch_size: 14
32
+ mm_tokens_per_image: 144
33
+ ```
34
+
35
+ ## Model Files
36
+
37
+ | File | Size | Description |
38
+ |------|------|-------------|
39
+ | `model.safetensors` | 2.3 GB | All weights (language + vision) |
40
+ | `config.json` | - | Model configuration with `vocab_pruning` metadata |
41
+
42
+ ## Requirements
43
+
44
+ This model uses **token_map** for vocabulary pruning. The inference engine must:
45
+
46
+ 1. Read `vocab_pruning.compact_vocab_size` from config.json
47
+ 2. Initialize embedding layer with compact size (144,257) instead of original vocab size (262,208)
48
+ 3. Load `language_model.model.embed_tokens.token_map` (int32[262208]) from weights
49
+ 4. Remap token IDs before embedding lookup: `embedding(token_map[input_ids])`
50
+
51
+ Standard `mlx_vlm.generate` works for models **without** vocab pruning. For this model, use the custom Swift CLI or a compatible inference engine.
52
+
53
+ ## Usage
54
+
55
+ ### Swift (gemma-cli with MLX Swift)
56
+
57
+ ```bash
58
+ # Text generation
59
+ swift run -c release gemma-cli /path/to/gemma-3-4b-it-qat-4bit-lite \
60
+ --prompt "Hello, how are you?" --max-tokens 100 --temperature 0.0
61
+
62
+ # Image understanding
63
+ swift run -c release gemma-cli /path/to/gemma-3-4b-it-qat-4bit-lite \
64
+ --image photo.jpg \
65
+ --prompt "Describe this image in detail." --max-tokens 200 --temperature 0.0
66
+ ```
67
+
68
+ ## Benchmarks (Apple Silicon)
69
+
70
+ | Metric | Original | This Model |
71
+ |--------|----------|------------|
72
+ | Disk size | 2.8 GB | 2.3 GB |
73
+ | Prompt speed (text) | 109 t/s | ~120 t/s |
74
+ | Generation speed (text) | 90 t/s | ~110 t/s |
75
+ | Image understanding | Correct | Correct |
76
+ | Text quality | Perfect | Good |
77
+
78
+ ## Base Model
79
+
80
+ [google/gemma-3-4b-it-qat-q4_0_4_8](https://huggingface.co/google/gemma-3-4b-it-qat-q4_0_4_8)
81
+
82
+ ## License
83
+
84
+ Same as the base model. See [Gemma Terms of Use](https://ai.google.dev/gemma/terms).
added_tokens.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "<image_soft_token>": 262144
3
+ }
chat_template.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "chat_template": "{{ bos_token }}\n{%- if messages[0]['role'] == 'system' -%}\n {%- if messages[0]['content'] is string -%}\n {%- set first_user_prefix = messages[0]['content'] + '\n\n' -%}\n {%- else -%}\n {%- set first_user_prefix = messages[0]['content'][0]['text'] + '\n\n' -%}\n {%- endif -%}\n {%- set loop_messages = messages[1:] -%}\n{%- else -%}\n {%- set first_user_prefix = \"\" -%}\n {%- set loop_messages = messages -%}\n{%- endif -%}\n{%- for message in loop_messages -%}\n {%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) -%}\n {{ raise_exception(\"Conversation roles must alternate user/assistant/user/assistant/...\") }}\n {%- endif -%}\n {%- if (message['role'] == 'assistant') -%}\n {%- set role = \"model\" -%}\n {%- else -%}\n {%- set role = message['role'] -%}\n {%- endif -%}\n {{ '<start_of_turn>' + role + '\n' + (first_user_prefix if loop.first else \"\") }}\n {%- if message['content'] is string -%}\n {{ message['content'] | trim }}\n {%- elif message['content'] is iterable -%}\n {%- for item in message['content'] -%}\n {%- if item['type'] == 'image' -%}\n {{ '<start_of_image>' }}\n {%- elif item['type'] == 'text' -%}\n {{ item['text'] | trim }}\n {%- endif -%}\n {%- endfor -%}\n {%- else -%}\n {{ raise_exception(\"Invalid content type\") }}\n {%- endif -%}\n {{ '<end_of_turn>\n' }}\n{%- endfor -%}\n{%- if add_generation_prompt -%}\n {{'<start_of_turn>model\n'}}\n{%- endif -%}\n"
3
+ }
config.json ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_attn_implementation_autoset": false,
3
+ "add_cross_attention": false,
4
+ "architectures": [
5
+ "Gemma3ForConditionalGeneration"
6
+ ],
7
+ "bad_words_ids": null,
8
+ "begin_suppress_tokens": null,
9
+ "boi_token_index": 255999,
10
+ "bos_token_id": null,
11
+ "chunk_size_feed_forward": 0,
12
+ "cross_attention_hidden_size": null,
13
+ "decoder_start_token_id": null,
14
+ "diversity_penalty": 0.0,
15
+ "do_sample": false,
16
+ "early_stopping": false,
17
+ "encoder_no_repeat_ngram_size": 0,
18
+ "eoi_token_index": 256000,
19
+ "eos_token_id": [
20
+ 1,
21
+ 106
22
+ ],
23
+ "exponential_decay_length_penalty": null,
24
+ "finetuning_task": null,
25
+ "forced_bos_token_id": null,
26
+ "forced_eos_token_id": null,
27
+ "id2label": {
28
+ "0": "LABEL_0",
29
+ "1": "LABEL_1"
30
+ },
31
+ "image_token_index": 262144,
32
+ "initializer_range": 0.02,
33
+ "is_decoder": false,
34
+ "is_encoder_decoder": false,
35
+ "label2id": {
36
+ "LABEL_0": 0,
37
+ "LABEL_1": 1
38
+ },
39
+ "length_penalty": 1.0,
40
+ "max_length": 20,
41
+ "min_length": 0,
42
+ "mm_tokens_per_image": 144,
43
+ "model_type": "gemma3",
44
+ "no_repeat_ngram_size": 0,
45
+ "num_beam_groups": 1,
46
+ "num_beams": 1,
47
+ "num_return_sequences": 1,
48
+ "output_attentions": false,
49
+ "output_hidden_states": false,
50
+ "output_scores": false,
51
+ "pad_token_id": null,
52
+ "prefix": null,
53
+ "problem_type": null,
54
+ "pruned_heads": {},
55
+ "quantization": {
56
+ "group_size": 64,
57
+ "bits": 4
58
+ },
59
+ "remove_invalid_values": false,
60
+ "repetition_penalty": 1.0,
61
+ "return_dict": true,
62
+ "return_dict_in_generate": false,
63
+ "sep_token_id": null,
64
+ "suppress_tokens": null,
65
+ "task_specific_params": null,
66
+ "temperature": 1.0,
67
+ "text_config": {
68
+ "return_dict": true,
69
+ "output_hidden_states": false,
70
+ "output_attentions": false,
71
+ "torchscript": false,
72
+ "torch_dtype": "bfloat16",
73
+ "use_bfloat16": false,
74
+ "tf_legacy_loss": false,
75
+ "pruned_heads": {},
76
+ "tie_word_embeddings": true,
77
+ "chunk_size_feed_forward": 0,
78
+ "is_encoder_decoder": false,
79
+ "is_decoder": false,
80
+ "cross_attention_hidden_size": null,
81
+ "add_cross_attention": false,
82
+ "tie_encoder_decoder": false,
83
+ "max_length": 20,
84
+ "min_length": 0,
85
+ "do_sample": false,
86
+ "early_stopping": false,
87
+ "num_beams": 1,
88
+ "num_beam_groups": 1,
89
+ "diversity_penalty": 0.0,
90
+ "temperature": 1.0,
91
+ "top_k": 50,
92
+ "top_p": 1.0,
93
+ "typical_p": 1.0,
94
+ "repetition_penalty": 1.0,
95
+ "length_penalty": 1.0,
96
+ "no_repeat_ngram_size": 0,
97
+ "encoder_no_repeat_ngram_size": 0,
98
+ "bad_words_ids": null,
99
+ "num_return_sequences": 1,
100
+ "output_scores": false,
101
+ "return_dict_in_generate": false,
102
+ "forced_bos_token_id": null,
103
+ "forced_eos_token_id": null,
104
+ "remove_invalid_values": false,
105
+ "exponential_decay_length_penalty": null,
106
+ "suppress_tokens": null,
107
+ "begin_suppress_tokens": null,
108
+ "architectures": null,
109
+ "finetuning_task": null,
110
+ "id2label": {
111
+ "0": "LABEL_0",
112
+ "1": "LABEL_1"
113
+ },
114
+ "label2id": {
115
+ "LABEL_0": 0,
116
+ "LABEL_1": 1
117
+ },
118
+ "tokenizer_class": null,
119
+ "prefix": null,
120
+ "bos_token_id": 2,
121
+ "pad_token_id": 0,
122
+ "eos_token_id": 1,
123
+ "sep_token_id": null,
124
+ "decoder_start_token_id": null,
125
+ "task_specific_params": null,
126
+ "problem_type": null,
127
+ "_name_or_path": "",
128
+ "_attn_implementation_autoset": false,
129
+ "model_type": "gemma3_text",
130
+ "vocab_size": 262208,
131
+ "max_position_embeddings": 131072,
132
+ "hidden_size": 2560,
133
+ "intermediate_size": 10240,
134
+ "num_hidden_layers": 31,
135
+ "num_attention_heads": 8,
136
+ "head_dim": 256,
137
+ "num_key_value_heads": 4,
138
+ "initializer_range": 0.02,
139
+ "rms_norm_eps": 1e-06,
140
+ "use_cache": true,
141
+ "rope_theta": 1000000,
142
+ "attention_bias": false,
143
+ "attention_dropout": 0.0,
144
+ "hidden_activation": "gelu_pytorch_tanh",
145
+ "query_pre_attn_scalar": 256,
146
+ "sliding_window": 1024,
147
+ "final_logit_softcapping": null,
148
+ "attn_logit_softcapping": null,
149
+ "cache_implementation": "hybrid",
150
+ "rope_local_base_freq": 10000,
151
+ "sliding_window_pattern": 6,
152
+ "rope_scaling": {
153
+ "factor": 8.0,
154
+ "rope_type": "linear"
155
+ }
156
+ },
157
+ "tf_legacy_loss": false,
158
+ "tie_encoder_decoder": false,
159
+ "tie_word_embeddings": true,
160
+ "tokenizer_class": null,
161
+ "top_k": 50,
162
+ "top_p": 1.0,
163
+ "torchscript": false,
164
+ "transformers_version": "4.51.3",
165
+ "typical_p": 1.0,
166
+ "use_bfloat16": false,
167
+ "vision_config": {
168
+ "return_dict": true,
169
+ "output_hidden_states": false,
170
+ "output_attentions": false,
171
+ "torchscript": false,
172
+ "torch_dtype": "bfloat16",
173
+ "use_bfloat16": false,
174
+ "tf_legacy_loss": false,
175
+ "pruned_heads": {},
176
+ "tie_word_embeddings": true,
177
+ "chunk_size_feed_forward": 0,
178
+ "is_encoder_decoder": false,
179
+ "is_decoder": false,
180
+ "cross_attention_hidden_size": null,
181
+ "add_cross_attention": false,
182
+ "tie_encoder_decoder": false,
183
+ "max_length": 20,
184
+ "min_length": 0,
185
+ "do_sample": false,
186
+ "early_stopping": false,
187
+ "num_beams": 1,
188
+ "num_beam_groups": 1,
189
+ "diversity_penalty": 0.0,
190
+ "temperature": 1.0,
191
+ "top_k": 50,
192
+ "top_p": 1.0,
193
+ "typical_p": 1.0,
194
+ "repetition_penalty": 1.0,
195
+ "length_penalty": 1.0,
196
+ "no_repeat_ngram_size": 0,
197
+ "encoder_no_repeat_ngram_size": 0,
198
+ "bad_words_ids": null,
199
+ "num_return_sequences": 1,
200
+ "output_scores": false,
201
+ "return_dict_in_generate": false,
202
+ "forced_bos_token_id": null,
203
+ "forced_eos_token_id": null,
204
+ "remove_invalid_values": false,
205
+ "exponential_decay_length_penalty": null,
206
+ "suppress_tokens": null,
207
+ "begin_suppress_tokens": null,
208
+ "architectures": null,
209
+ "finetuning_task": null,
210
+ "id2label": {
211
+ "0": "LABEL_0",
212
+ "1": "LABEL_1"
213
+ },
214
+ "label2id": {
215
+ "LABEL_0": 0,
216
+ "LABEL_1": 1
217
+ },
218
+ "tokenizer_class": null,
219
+ "prefix": null,
220
+ "bos_token_id": null,
221
+ "pad_token_id": null,
222
+ "eos_token_id": null,
223
+ "sep_token_id": null,
224
+ "decoder_start_token_id": null,
225
+ "task_specific_params": null,
226
+ "problem_type": null,
227
+ "_name_or_path": "",
228
+ "_attn_implementation_autoset": false,
229
+ "model_type": "siglip_vision_model",
230
+ "vision_use_head": false,
231
+ "hidden_size": 1152,
232
+ "intermediate_size": 4352,
233
+ "num_hidden_layers": 27,
234
+ "num_attention_heads": 16,
235
+ "num_channels": 3,
236
+ "patch_size": 14,
237
+ "image_size": 672,
238
+ "attention_dropout": 0.0,
239
+ "layer_norm_eps": 1e-06,
240
+ "hidden_act": "gelu_pytorch_tanh"
241
+ },
242
+ "vocab_pruning": {
243
+ "original_vocab_size": 262208,
244
+ "compact_vocab_size": 144257,
245
+ "keep_ids_count": 144256,
246
+ "has_token_map": true,
247
+ "token_map_key": "language_model.model.embed_tokens.token_map"
248
+ },
249
+ "vision_fc2_quantization": {
250
+ "bits": 4,
251
+ "group_size": 64,
252
+ "quantized_layers": 27,
253
+ "original_intermediate_size": 4304,
254
+ "padded_intermediate_size": 4352,
255
+ "pad_amount": 48,
256
+ "saved_mb": 191.6
257
+ },
258
+ "text_layer_pruning": {
259
+ "removed_layers": [
260
+ 31,
261
+ 32,
262
+ 33
263
+ ],
264
+ "keep_layers": [
265
+ 0,
266
+ 1,
267
+ 2,
268
+ 3,
269
+ 4,
270
+ 5,
271
+ 6,
272
+ 7,
273
+ 8,
274
+ 9,
275
+ 10,
276
+ 11,
277
+ 12,
278
+ 13,
279
+ 14,
280
+ 15,
281
+ 16,
282
+ 17,
283
+ 18,
284
+ 19,
285
+ 20,
286
+ 21,
287
+ 22,
288
+ 23,
289
+ 24,
290
+ 25,
291
+ 26,
292
+ 27,
293
+ 28,
294
+ 29,
295
+ 30
296
+ ],
297
+ "old_num_layers": 34,
298
+ "new_num_layers": 31
299
+ },
300
+ "resolution_reduction": {
301
+ "original_image_size": 896,
302
+ "target_image_size": 672,
303
+ "original_patches": 4096,
304
+ "new_patches": 2304,
305
+ "original_mm_tokens": 256,
306
+ "new_mm_tokens": 144
307
+ }
308
+ }
generation_config.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cache_implementation": "hybrid",
3
+ "do_sample": true,
4
+ "eos_token_id": [
5
+ 1,
6
+ 106
7
+ ],
8
+ "top_k": 64,
9
+ "top_p": 0.95,
10
+ "transformers_version": "4.52.0.dev0"
11
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:90b33a6839e1b2bac46a3278405ec300415f274c2cbf7a62c0be9d9630f9dbdd
3
+ size 2475476883
preprocessor_config.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_convert_rgb": null,
3
+ "do_normalize": true,
4
+ "do_pan_and_scan": null,
5
+ "do_rescale": true,
6
+ "do_resize": true,
7
+ "image_mean": [
8
+ 0.5,
9
+ 0.5,
10
+ 0.5
11
+ ],
12
+ "image_processor_type": "Gemma3ImageProcessor",
13
+ "image_seq_length": 144,
14
+ "image_std": [
15
+ 0.5,
16
+ 0.5,
17
+ 0.5
18
+ ],
19
+ "pan_and_scan_max_num_crops": null,
20
+ "pan_and_scan_min_crop_size": null,
21
+ "pan_and_scan_min_ratio_to_activate": null,
22
+ "processor_class": "Gemma3Processor",
23
+ "resample": 2,
24
+ "rescale_factor": 0.00392156862745098,
25
+ "size": {
26
+ "height": 672,
27
+ "width": 672
28
+ }
29
+ }
processor_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "image_seq_length": 256,
3
+ "processor_class": "Gemma3Processor"
4
+ }
special_tokens_map.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "boi_token": "<start_of_image>",
3
+ "bos_token": {
4
+ "content": "<bos>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false
9
+ },
10
+ "eoi_token": "<end_of_image>",
11
+ "eos_token": {
12
+ "content": "<eos>",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false
17
+ },
18
+ "image_token": "<image_soft_token>",
19
+ "pad_token": {
20
+ "content": "<pad>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false
25
+ },
26
+ "unk_token": {
27
+ "content": "<unk>",
28
+ "lstrip": false,
29
+ "normalized": false,
30
+ "rstrip": false,
31
+ "single_word": false
32
+ }
33
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4667f2089529e8e7657cfb6d1c19910ae71ff5f28aa7ab2ff2763330affad795
3
+ size 33384568
tokenizer.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1299c11d7cf632ef3b4e11937501358ada021bbdf7c47638d13c0ee982f2e79c
3
+ size 4689074
tokenizer_config.json ADDED
The diff for this file is too large to render. See raw diff