zheqiushui commited on
Commit
876ac2c
·
verified ·
1 Parent(s): 1601280

Repackage into ax-llm model-directory format (AX650)

Browse files

Repo is now a ready-to-run ax-llm model dir: config.json (vlm_type=InternVL3, tokenizer_type=InternVL3_5), internvl3-5-2b_tokenizer.txt, post_config.json, internvl3-5_axmodel (Qwen3-1.7B, 28 layers) + vit-models. Removed legacy layout / demo scripts.

.gitattributes CHANGED
@@ -42,3 +42,4 @@ main_axcl_x86 filter=lfs diff=lfs merge=lfs -text
42
  *.jpg filter=lfs diff=lfs merge=lfs -text
43
  *.mp4 filter=lfs diff=lfs merge=lfs -text
44
  internvl3-5_tokenizer/tokenizer.json filter=lfs diff=lfs merge=lfs -text
 
 
42
  *.jpg filter=lfs diff=lfs merge=lfs -text
43
  *.mp4 filter=lfs diff=lfs merge=lfs -text
44
  internvl3-5_tokenizer/tokenizer.json filter=lfs diff=lfs merge=lfs -text
45
+ *_tokenizer.txt filter=lfs diff=lfs merge=lfs -text
.gitignore DELETED
@@ -1,3 +0,0 @@
1
- __pycache__
2
- *tmp/
3
-
 
 
 
 
README.md CHANGED
@@ -7,7 +7,6 @@ tags:
7
  - InternVL3
8
  - InternVL3_5-2B
9
  - InternVL3_5-2B_GPTQ_INT4
10
- - Int8
11
  - VLM
12
  pipeline_tag: image-text-to-text
13
  language:
@@ -16,133 +15,49 @@ language:
16
 
17
  # InternVL3_5-2B_GPTQ_INT4
18
 
19
- This version of InternVL3_5-2B_GPTQ_INT4 has been converted to run on the Axera NPU using **w4a16** quantization.
20
 
21
- This model has been optimized with the following LoRA:
 
 
22
 
23
- Compatible with Pulsar2 version: 5.1-patch1.
24
-
25
- Please note that the context of the model is 2k and the maximum prefill length is 1k.
26
-
27
- ## Convert tools links:
28
-
29
- For those who are interested in model conversion, you can try to export axmodel through the original repo:
30
-
31
- https://huggingface.co/OpenGVLab/InternVL3_5-2B
32
-
33
- [How to Convert LLM from Huggingface to axmodel](https://github.com/AXERA-TECH/InternVL3_5-2B_GPTQ_INT4.axera/tree/main/model_convert)
34
-
35
- [AXera NPU HOST LLM Runtime](https://github.com/AXERA-TECH/ax-llm/tree/ax-internvl)
36
-
37
- [AXera NPU AXCL LLM Runtime](https://github.com/AXERA-TECH/ax-llm/tree/axcl-internvl)
38
-
39
- ## Support Platform
40
-
41
- - AX650
42
- - AX650N DEMO Board
43
- - [M4N-Dock(爱芯派Pro)](https://wiki.sipeed.com/hardware/zh/maixIV/m4ndock/m4ndock.html)
44
- - [M.2 Accelerator card](https://axcl-docs.readthedocs.io/zh-cn/latest/doc_guide_hardware.html)
45
-
46
- |Chips|image encoder 448|ttft|w8a16|
47
- |--|--|--|--|
48
- |AX650| 364.412 ms | 4951.50 ms | 28.07 tokens/sec|
49
-
50
-
51
- ## How to use
52
-
53
- Download all files from this repository to the device
54
 
55
  ```
56
- $ tree -L 1
57
  .
58
- ├── assets
59
- ├── config.json
60
- ├── examples
61
- ├── gradio_demo.py
62
- ├── infer_axmodel.py
63
- ├── infer_torch.py
64
- ├── internvl3-5_axmodel
65
- ├── internvl3-5_tokenizer
66
- ├── README.md
67
- ├── utils
68
- └── vit-models
69
-
70
- 6 directories, 5 files
71
- ```
72
-
73
- #### Install transformer
74
-
75
- ```
76
- pip install transformers==4.57.1
77
  ```
78
 
79
- #### Inference with AX650 Host, such as M4N-Dock(爱芯派Pro) or AX650 DEMO Board
80
-
81
- Interactive conversations using the `Gradio API`:
82
-
83
- ```bash
84
- $ python3 gradio_demo.py --hf_model internvl3-5_tokenizer/ --axmodel_path internvl3-5_axmodel/ --vit_model vit-models/internvl_vit_model_1x3x448x448.axmodel
85
- ```
86
-
87
- Plain text dialogue:
88
-
89
- ![demo_1](assets/demo_1.png)
90
 
91
- Image understanding:
 
 
 
92
 
93
- ![demo_2](assets/demo_2.png)
 
 
94
 
95
- ---
96
 
97
- Run the following command on the Axera board to start a chat conversation:
98
 
99
  ```sh
100
- $ python3 infer_axmodel.py --hf_model internvl3-5_tokenizer/ --axmodel_path internvl3-5_axmodel/ --question "请计算函数[y=2x^2+2]的导数, 并提供 markdown 格式的推理过程"
101
- ```
102
 
103
- output:
104
-
105
- ```bash
106
- [INFO] Using provider: AxEngineExecutionProvider
107
- [INFO] Model type: 2 (triple core)
108
- [INFO] Compiler version: 5.1-dirty 0fdbfe15-dirty
109
- Model loaded successfully!
110
- slice_indices: [0]
111
- Slice prefill done: 0
112
- answer >> 函数 \( y = 2x^2 + 2 \) 的导数可以通过求导法则来计算。首先,我们对函数中的每一项分别求导:
113
-
114
- 1. 对于 \( 2x^2 \),使用幂法则求导:
115
- \[
116
- \frac{d}{dx}(2x^2) = 2 \cdot 2x = 4x
117
- \]
118
-
119
- 2. 对于常数项 \( 2 \),其导数为 0,因为常数的导数为 0。
120
-
121
- 将这两部分的结果相加,得到函数 \( y \) 的导数:
122
- \[
123
- y' = 4x
124
- \]
125
-
126
- 因此,函数 \( y = 2x^2 + 2 \) 的导数为 \( y' = 4x \)。
127
  ```
128
 
129
- Enter the following command to perform the single-image understanding task:
130
 
131
- ```sh
132
- $ python3 infer_axmodel.py --hf_model internvl3-5_tokenizer/ --axmodel_path internvl3-5_axmodel/ --question "请描述这幅图" -i examples/image_0.jpg --vit_model vit-models/internvl_vit_model_1x3x448x448.axmodel
133
- ```
134
-
135
- ![image_0.jpg](examples/image_0.jpg)
136
 
137
- output:
138
-
139
- ```bash
140
- [INFO] Model type: 2 (triple core)
141
- [INFO] Compiler version: 5.1-dirty 0fdbfe15-dirty
142
- Model loaded successfully!
143
- slice_indices: [0, 1, 2]
144
- Slice prefill done: 0
145
- Slice prefill done: 1
146
- Slice prefill done: 2
147
- answer >> 这是一张红熊猫的照片。红熊猫是一种红棕色的哺乳动物,通常生活在亚洲的森林中。它们以捕食昆虫和小型无脊椎动物为生。图片中,红熊猫正坐在一个木制的平台上,背景是绿色的树木和植被,显得非常自然和生动。红熊猫的表情看起来很友好,似乎在观察或等待什么。
148
- ```
 
7
  - InternVL3
8
  - InternVL3_5-2B
9
  - InternVL3_5-2B_GPTQ_INT4
 
10
  - VLM
11
  pipeline_tag: image-text-to-text
12
  language:
 
15
 
16
  # InternVL3_5-2B_GPTQ_INT4
17
 
18
+ InternVL3.5-2B (InternViT + Qwen3-1.7B) converted to run on the Axera NPU with **w4a16** quantization, packaged in **[ax-llm](https://github.com/AXERA-TECH/ax-llm)** model-directory format.
19
 
20
+ - Compatible with Pulsar2 5.1-patch1
21
+ - Context length: 2k, max prefill: 1k, image input: 448×448
22
+ - Target chip: **AX650** (AX650N host & AXCL M.2 accelerator)
23
 
24
+ This repository **is** a ready-to-run ax-llm model directory:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  ```
 
27
  .
28
+ ├── config.json # ax-llm runtime config (vlm_type=InternVL3, tokenizer_type=InternVL3_5)
29
+ ├── internvl3-5-2b_tokenizer.txt # tokenizer
30
+ ├── post_config.json # sampling config
31
+ ├── internvl3-5_axmodel/ # LLM: qwen3_p128_l0..l27 (28) + qwen3_post + embed
32
+ └── vit-models/ # InternViT image encoder (internvl_vit_model_1x3x448x448.axmodel)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  ```
34
 
35
+ ## Support Platform
 
 
 
 
 
 
 
 
 
 
36
 
37
+ - **AX650**
38
+ - AX650N DEMO Board
39
+ - [M4N-Dock (爱芯派Pro)](https://wiki.sipeed.com/hardware/zh/maixIV/m4ndock/m4ndock.html)
40
+ - [M.2 Accelerator card (AXCL)](https://axcl-docs.readthedocs.io/zh-cn/latest/doc_guide_hardware.html)
41
 
42
+ | Chip | image encoder 448 | ttft | w4a16 |
43
+ |--|--|--|--|
44
+ | AX650 | 364.412 ms | 4951.50 ms | 28.07 tokens/sec |
45
 
46
+ ## How to use
47
 
48
+ Build/obtain the ax-llm runtime: [AXera NPU LLM Runtime (ax-llm)](https://github.com/AXERA-TECH/ax-llm)
49
 
50
  ```sh
51
+ # interactive chat
52
+ ./axllm run InternVL3_5-2B_GPTQ_INT4
53
 
54
+ # OpenAI-compatible HTTP server (default port 8000)
55
+ ./axllm serve InternVL3_5-2B_GPTQ_INT4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  ```
57
 
58
+ On AXCL, choose the card via `AXLLM_DEVICES=<id>` or the `"devices"` field in `config.json`.
59
 
60
+ ## Source & conversion
 
 
 
 
61
 
62
+ - Base model: [OpenGVLab/InternVL3_5-2B](https://huggingface.co/OpenGVLab/InternVL3_5-2B)
63
+ - License: BSD-3-Clause
 
 
 
 
 
 
 
 
 
 
assets/demo_1.png DELETED

Git LFS Details

  • SHA256: 6340140c81bf679b2ba9aa494e1526f6db9b6e435221dc6c582b2887f8d8e9a6
  • Pointer size: 131 Bytes
  • Size of remote file: 395 kB
assets/demo_2.png DELETED

Git LFS Details

  • SHA256: 4c7d95c191d1afbf33ea4054a561a2540fd6c0d59dd78e397b88d41c0ed1fd33
  • Pointer size: 132 Bytes
  • Size of remote file: 1.31 MB
config.json CHANGED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_name": "AXERA-TECH/InternVL3_5-2B_GPTQ_INT4 (AX650)",
3
+ "url_tokenizer_model": "internvl3-5-2b_tokenizer.txt",
4
+ "tokenizer_type": "InternVL3_5",
5
+ "post_config_path": "post_config.json",
6
+ "template_filename_axmodel": "internvl3-5_axmodel/qwen3_p128_l%d_together.axmodel",
7
+ "axmodel_num": 28,
8
+ "filename_post_axmodel": "internvl3-5_axmodel/qwen3_post.axmodel",
9
+ "filename_tokens_embed": "internvl3-5_axmodel/model.embed_tokens.weight.bfloat16.bin",
10
+ "tokens_embed_num": 151936,
11
+ "tokens_embed_size": 2048,
12
+ "b_use_mmap_load_embed": true,
13
+ "vlm_type": "InternVL3",
14
+ "filename_image_encoder_axmodel": "vit-models/internvl_vit_model_1x3x448x448.axmodel",
15
+ "devices": [0]
16
+ }
examples/image_0.jpg DELETED

Git LFS Details

  • SHA256: c587294b3bf637dacbb3c96324c127187a2f242c94f639633a0d8a2775a9a399
  • Pointer size: 130 Bytes
  • Size of remote file: 78.1 kB
examples/image_1.jpg DELETED

Git LFS Details

  • SHA256: 08487494b8dc08d44bc36491adf3ab89ff30d13a3122da86f3cd67cad89eeee8
  • Pointer size: 131 Bytes
  • Size of remote file: 126 kB
examples/image_2.png DELETED

Git LFS Details

  • SHA256: 622ae2d01ff4467fa69a7888728d776650117a0f4887e96ba0fb9a8a6d77b3c3
  • Pointer size: 131 Bytes
  • Size of remote file: 355 kB
examples/image_3.png DELETED

Git LFS Details

  • SHA256: 729e80e77d8611778859d2f232cb7f2a8fda04ed67dd8dcc3e7cd7a657367402
  • Pointer size: 131 Bytes
  • Size of remote file: 394 kB
examples/laorenshuaidao.mp4 DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8f5c00b37b23af3d01d133da880eb7f6e50d4af608e3575784be7063eb137011
3
- size 2704112
 
 
 
 
examples/red-panda.mp4 DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d921c07bb97224d65a37801541d246067f0d506f08723ffa1ad85c217907ccb8
3
- size 1867237
 
 
 
 
examples/tuboshu.mp4 DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:ced4d95877b9a7f8b48f79bdfe4287eff8837f20348daec2f2e2987459ec1712
3
- size 5952043
 
 
 
 
gradio_demo.py DELETED
@@ -1,392 +0,0 @@
1
- import argparse
2
- import os
3
- import time
4
- from typing import Any, Dict, List, Optional, Generator, Tuple
5
-
6
- import gradio as gr
7
- import numpy as np
8
- import torch
9
- import torchvision.transforms as T
10
- from ml_dtypes import bfloat16
11
- from PIL import Image
12
- from torchvision.transforms.functional import InterpolationMode
13
- from transformers import AutoConfig, AutoTokenizer
14
-
15
- from utils.infer_func import InferManager
16
- from axengine import InferenceSession
17
-
18
- IMAGENET_MEAN = (0.485, 0.456, 0.406)
19
- IMAGENET_STD = (0.229, 0.224, 0.225)
20
- IMG_PLACEHOLDER_TOKEN_ID = 151669 # <img>
21
- IMG_CONTEXT_REPEAT = 256 # number of image context tokens expected by the model
22
-
23
-
24
- SYSTEM_PROMPT = (
25
- "<|im_start|>system\n"
26
- "你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型, 英文名叫 InternVL3, "
27
- "是一个有用无害的人工智能助手, 擅长思考和回答用户的问题. 请你在回答问题时使用简体中文."
28
- "<|im_end|>\n"
29
- )
30
-
31
-
32
- def build_transform(input_size: int):
33
- transform = T.Compose([
34
- T.Lambda(lambda img: img.convert("RGB") if img.mode != "RGB" else img),
35
- T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC),
36
- T.ToTensor(),
37
- T.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
38
- ])
39
- return transform
40
-
41
-
42
- def dynamic_preprocess(image: Image.Image, min_num: int = 1, max_num: int = 12, image_size: int = 448,
43
- use_thumbnail: bool = False):
44
- orig_width, orig_height = image.size
45
- aspect_ratio = orig_width / orig_height
46
-
47
- target_ratios = set(
48
- (i, j)
49
- for n in range(min_num, max_num + 1)
50
- for i in range(1, n + 1)
51
- for j in range(1, n + 1)
52
- if i * j <= max_num and i * j >= min_num
53
- )
54
- target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])
55
-
56
- def find_closest_aspect_ratio(ar: float, ratios: List[tuple]):
57
- best_ratio_diff = float("inf")
58
- best_ratio = (1, 1)
59
- area = orig_width * orig_height
60
- for ratio in ratios:
61
- target_aspect_ratio = ratio[0] / ratio[1]
62
- ratio_diff = abs(ar - target_aspect_ratio)
63
- if ratio_diff < best_ratio_diff:
64
- best_ratio_diff = ratio_diff
65
- best_ratio = ratio
66
- elif ratio_diff == best_ratio_diff:
67
- if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
68
- best_ratio = ratio
69
- return best_ratio
70
-
71
- target_aspect_ratio = find_closest_aspect_ratio(aspect_ratio, target_ratios)
72
- target_width = image_size * target_aspect_ratio[0]
73
- target_height = image_size * target_aspect_ratio[1]
74
- blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
75
-
76
- resized_img = image.resize((target_width, target_height))
77
- processed_images = []
78
- for i in range(blocks):
79
- box = (
80
- (i % (target_width // image_size)) * image_size,
81
- (i // (target_width // image_size)) * image_size,
82
- ((i % (target_width // image_size)) + 1) * image_size,
83
- ((i // (target_width // image_size)) + 1) * image_size,
84
- )
85
- split_img = resized_img.crop(box)
86
- processed_images.append(split_img)
87
- assert len(processed_images) == blocks
88
- if use_thumbnail and len(processed_images) != 1:
89
- processed_images.append(image.resize((image_size, image_size)))
90
- return processed_images
91
-
92
-
93
- def load_image(image_file: Image.Image, input_size: int = 448, max_num: int = 12):
94
- transform = build_transform(input_size=input_size)
95
- images = dynamic_preprocess(image_file, image_size=input_size, use_thumbnail=True, max_num=max_num)
96
- pixel_values = [transform(img) for img in images]
97
- pixel_values = torch.stack(pixel_values)
98
- return pixel_values
99
-
100
-
101
- class InternVLGradioDemo:
102
- def __init__(self, hf_model: str, axmodel_dir: str, vit_axmodel: str, max_seq_len: int = 2047):
103
- self.hf_model = hf_model
104
- self.axmodel_dir = axmodel_dir
105
- self.vit_axmodel = vit_axmodel
106
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
107
-
108
- self.embeds = np.load(os.path.join(axmodel_dir, "model.embed_tokens.weight.npy"))
109
- self.tokenizer = AutoTokenizer.from_pretrained(self.hf_model)
110
- config = AutoConfig.from_pretrained(self.hf_model, trust_remote_code=True)
111
- if hasattr(config, 'llm_config') and config.llm_config is not None:
112
- self.cfg = config.llm_config
113
- else:
114
- self.cfg = config
115
-
116
- self.vit_session = InferenceSession(self.vit_axmodel)
117
- self.infer_manager = InferManager(self.cfg, self.axmodel_dir, max_seq_len=max_seq_len)
118
-
119
- def _build_single_turn_prompt(self, user_text: str, vit_features: List[np.ndarray]):
120
- prompt = SYSTEM_PROMPT
121
- prompt += f"<|im_start|>user\n{user_text}"
122
- for _ in vit_features:
123
- prompt += "\n<img>" + "<IMG_CONTEXT>" * IMG_CONTEXT_REPEAT + "</img>"
124
- prompt += "<|im_end|>\n<|im_start|>assistant\n"
125
- return prompt
126
-
127
- def _insert_vision_features(self, token_ids: List[int], prefill_data: np.ndarray, vit_features: List[np.ndarray]):
128
- image_start_indices = np.where(np.array(token_ids) == IMG_PLACEHOLDER_TOKEN_ID)[0].tolist()
129
- if len(image_start_indices) != len(vit_features):
130
- raise ValueError("图片数量与占位符数量不一致, 请检查输入和模板生成逻辑")
131
- for idx, image_start_index in enumerate(image_start_indices):
132
- insert_pos = image_start_index + 1
133
- prefill_data[insert_pos: insert_pos + IMG_CONTEXT_REPEAT] = vit_features[idx][0, :, :]
134
- return prefill_data
135
-
136
- def _run_model(self, prompt: str, vit_features: List[np.ndarray]):
137
- """Non-streaming推理,保留以防需要一次性结果。"""
138
- for k_cache in self.infer_manager.k_caches:
139
- k_cache.fill(0)
140
- for v_cache in self.infer_manager.v_caches:
141
- v_cache.fill(0)
142
-
143
- token_ids = self.tokenizer.encode(prompt)
144
- prefill_data = np.take(self.embeds, token_ids, axis=0).astype(bfloat16)
145
- if vit_features:
146
- prefill_data = self._insert_vision_features(token_ids, prefill_data, vit_features)
147
-
148
- eos_token_id = None
149
- if isinstance(self.cfg.eos_token_id, list) and len(self.cfg.eos_token_id) > 1:
150
- eos_token_id = self.cfg.eos_token_id
151
-
152
- slice_len = 128
153
- token_ids = self.infer_manager.prefill(self.tokenizer, token_ids, prefill_data, slice_len=slice_len)
154
- return self.infer_manager.decode(
155
- self.tokenizer,
156
- token_ids,
157
- self.embeds,
158
- slice_len=slice_len,
159
- eos_token_id=eos_token_id,
160
- stream=False,
161
- )
162
-
163
- def _stream_generate(self, prompt: str, vit_features: List[np.ndarray]):
164
- """流式生成,逐 token 产出累积文本与计时信息 (TTFT 与平均 decode ms/token)。"""
165
- # reset kv cache per request
166
- for k_cache in self.infer_manager.k_caches:
167
- k_cache.fill(0)
168
- for v_cache in self.infer_manager.v_caches:
169
- v_cache.fill(0)
170
-
171
- token_ids = self.tokenizer.encode(prompt)
172
- prefill_data = np.take(self.embeds, token_ids, axis=0).astype(bfloat16)
173
- if vit_features:
174
- prefill_data = self._insert_vision_features(token_ids, prefill_data, vit_features)
175
-
176
- eos_token_id = None
177
- if isinstance(self.cfg.eos_token_id, list) and len(self.cfg.eos_token_id) > 1:
178
- eos_token_id = self.cfg.eos_token_id
179
-
180
- slice_len = 128
181
- t_start = time.time()
182
- token_ids = self.infer_manager.prefill(self.tokenizer, token_ids, prefill_data, slice_len=slice_len)
183
-
184
- # copy decode逻辑,实现手动流式输出
185
- mask = np.zeros((1, 1, self.infer_manager.max_seq_len + 1), dtype=np.float32).astype(bfloat16)
186
- mask[:, :, :self.infer_manager.max_seq_len] -= 65536
187
- seq_len = len(token_ids) - 1
188
- if slice_len > 0:
189
- mask[:, :, :seq_len] = 0
190
-
191
- ttft_ms: Optional[float] = None
192
- decode_tokens = 0
193
- decode_elapsed_ms: float = 0.0
194
- generated_text = ""
195
- yield generated_text, ttft_ms, None, None, False
196
-
197
- for step_idx in range(self.infer_manager.max_seq_len):
198
- if slice_len > 0 and step_idx < seq_len:
199
- continue
200
- cur_token = token_ids[step_idx]
201
- indices = np.array([step_idx], np.uint32).reshape((1, 1))
202
- data = self.embeds[cur_token, :].reshape((1, 1, self.cfg.hidden_size)).astype(bfloat16)
203
- for layer_idx in range(self.cfg.num_hidden_layers):
204
- input_feed = {
205
- "K_cache": self.infer_manager.k_caches[layer_idx],
206
- "V_cache": self.infer_manager.v_caches[layer_idx],
207
- "indices": indices,
208
- "input": data,
209
- "mask": mask,
210
- }
211
- outputs = self.infer_manager.decoder_sessions[layer_idx].run(None, input_feed, shape_group=0)
212
- self.infer_manager.k_caches[layer_idx][:, step_idx, :] = outputs[0][:, :, :]
213
- self.infer_manager.v_caches[layer_idx][:, step_idx, :] = outputs[1][:, :, :]
214
- data = outputs[2]
215
- mask[..., step_idx] = 0
216
- if step_idx < seq_len - 1:
217
- continue
218
- post_out = self.infer_manager.post_process_session.run(None, {"input": data})[0]
219
- next_token, possible_tokens, possible_probs = self.infer_manager.post_process(post_out, temperature=0.7)
220
- if eos_token_id is not None and next_token in eos_token_id:
221
- ttft_ms = ttft_ms or (time.time() - t_start) * 1000
222
- break
223
- if next_token == self.tokenizer.eos_token_id:
224
- ttft_ms = ttft_ms or (time.time() - t_start) * 1000
225
- break
226
-
227
- token_ids.append(next_token)
228
- # 使用完整 token 列表解码,避免多字节 UTF-8 字符被截断显示为乱码
229
- # 只解码新生成的 tokens(从 seq_len 开始)
230
- generated_text = self.tokenizer.decode(token_ids[seq_len:], skip_special_tokens=True)
231
-
232
- if ttft_ms is None:
233
- ttft_ms = (time.time() - t_start) * 1000
234
- else:
235
- decode_tokens += 1
236
- decode_elapsed_ms = (time.time() - t_start) * 1000 - ttft_ms
237
-
238
- avg_decode = (decode_elapsed_ms / decode_tokens) if decode_tokens > 0 else None
239
- yield generated_text, ttft_ms, avg_decode, decode_tokens, False
240
-
241
- total_ms = (time.time() - t_start) * 1000
242
- avg_decode = (decode_elapsed_ms / decode_tokens) if decode_tokens > 0 else None
243
- yield generated_text, ttft_ms, avg_decode, decode_tokens, True
244
-
245
- def chat(self, user_input: str, image: Optional[Image.Image]) -> Generator:
246
- user_text = (user_input or "").strip()
247
- if not user_text and image is None:
248
- yield [], gr.update(), gr.update(), gr.update(), gr.update()
249
- return
250
-
251
- # 先展示占位,保持图片不清空;同时占位速度信息
252
- yield [(user_text, "处理中…")], gr.update(value=""), gr.update(), gr.update(value="<div style='text-align: right; font-size: 13px; color: #6b7280; font-family: monospace;'>TTFT -- ms&nbsp;&nbsp;|&nbsp;&nbsp;Decode -- ms/token&nbsp;&nbsp;|&nbsp;&nbsp;Tokens --</div>"), gr.update(interactive=False)
253
-
254
- vit_outputs = []
255
- if image is not None:
256
- pixel_values = load_image(image, input_size=448, max_num=1)
257
- vit_output = self.vit_session.run(None, {"image": pixel_values.numpy()})[0]
258
- vit_outputs.append(vit_output.copy())
259
-
260
- prompt = self._build_single_turn_prompt(user_text, vit_outputs)
261
-
262
- chatbot_history = [(user_text, "")] # 将在流式过程中填充
263
- for partial, ttft_ms, avg_decode_ms, decode_tokens, finished in self._stream_generate(prompt, vit_outputs):
264
- chatbot_history[-1] = (user_text, partial)
265
- ttft_disp = f"{ttft_ms:.0f}" if ttft_ms is not None else "--"
266
- decode_disp = f"{avg_decode_ms:.1f}" if avg_decode_ms is not None else "--"
267
- tok_disp = f"{decode_tokens}" if decode_tokens is not None else "--"
268
- metrics_text = f"<div style='text-align: right; font-size: 13px; color: #6b7280; font-family: monospace;'>TTFT {ttft_disp} ms&nbsp;&nbsp;|&nbsp;&nbsp;Decode {decode_disp} ms/token&nbsp;&nbsp;|&nbsp;&nbsp;Tokens {tok_disp}</div>"
269
- if finished:
270
- yield chatbot_history, gr.update(value=""), gr.update(), gr.update(value=metrics_text), gr.update(interactive=True)
271
- else:
272
- yield chatbot_history, gr.update(value=""), gr.update(), gr.update(value=metrics_text), gr.update(interactive=False)
273
-
274
- @staticmethod
275
- def build_ui(demo: "InternVLGradioDemo", server_name: str = "0.0.0.0", server_port: int = 7860, share: bool = False):
276
- # 自定义 JavaScript: Enter 发送, Shift+Enter 换行
277
- custom_js = """
278
- function() {
279
- // 等待 DOM 加载完成后绑定事件
280
- setTimeout(() => {
281
- const textareas = document.querySelectorAll('#user-input textarea');
282
- textareas.forEach(textarea => {
283
- // 移除可能存在的旧监听器
284
- textarea.removeEventListener('keydown', textarea._customKeyHandler);
285
-
286
- textarea._customKeyHandler = function(e) {
287
- if (e.key === 'Enter') {
288
- if (e.shiftKey) {
289
- // Shift+Enter: 插入换行符
290
- e.preventDefault();
291
- const start = this.selectionStart;
292
- const end = this.selectionEnd;
293
- const value = this.value;
294
- this.value = value.substring(0, start) + '\\n' + value.substring(end);
295
- this.selectionStart = this.selectionEnd = start + 1;
296
- // 触发 input 事件让 Gradio 感知变化
297
- this.dispatchEvent(new Event('input', { bubbles: true }));
298
- } else {
299
- // Enter: 发送消息
300
- e.preventDefault();
301
- const sendBtn = document.querySelector('#send-btn');
302
- if (sendBtn) {
303
- sendBtn.click();
304
- }
305
- }
306
- }
307
- };
308
- textarea.addEventListener('keydown', textarea._customKeyHandler);
309
- });
310
- }, 500);
311
- }
312
- """
313
-
314
- with gr.Blocks(title="InternVL3_5-2B_GPTQ_INT4 AX Gradio Demo", theme=gr.themes.Soft(), js=custom_js) as iface:
315
- gr.HTML("""<style>
316
- #image-pane img {object-fit: contain; max-height: 380px;}
317
- #chat-wrap {position: relative;}
318
- #metrics-display {position: absolute; right: 12px; bottom: 12px; z-index: 5; pointer-events: none; text-align: right;}
319
- #metrics-display > div {display: inline-block;}
320
- </style>""")
321
- gr.Markdown("""### InternVL3_5-2B_GPTQ_INT4 图文对话演示\n上传一张图片 (可选),输入问题,获取中文回答。""")
322
-
323
- with gr.Row():
324
- # 左侧:对话框和输入区域
325
- with gr.Column(scale=5):
326
- with gr.Group(elem_id="chat-wrap"):
327
- chatbot = gr.Chatbot(height=500, label="对话")
328
- metrics_md = gr.Markdown("<div style='text-align: right; font-size: 13px; color: #6b7280; font-family: monospace;'>TTFT -- ms&nbsp;&nbsp;|&nbsp;&nbsp;Decode -- ms/token&nbsp;&nbsp;|&nbsp;&nbsp;Tokens --</div>", elem_id="metrics-display")
329
-
330
- with gr.Row():
331
- user_input = gr.Textbox(
332
- placeholder="按 Enter 发送,Shift+Enter 换行",
333
- lines=2,
334
- scale=7,
335
- max_lines=5,
336
- show_label=False,
337
- elem_id="user-input",
338
- )
339
- with gr.Column(scale=1, min_width=100):
340
- send_btn = gr.Button("发送", variant="primary", size="sm", elem_id="send-btn")
341
- clear_btn = gr.Button("清空对话", variant="secondary", size="sm")
342
-
343
- # 右侧:图像上传和信息提示
344
- with gr.Column(scale=3):
345
- image_input = gr.Image(
346
- type="pil",
347
- label="上传图片 (可选)",
348
- height=380,
349
- image_mode="RGB",
350
- show_download_button=False,
351
- elem_id="image-pane",
352
- )
353
- gr.Markdown("""- 支持单张图像理解\n- 仅当前问题与回答,不保留历史\n- 处理时间取决于硬件,请耐心等待""")
354
-
355
- def _clear():
356
- return [], gr.update(value=""), gr.update(), gr.update(value="<div style='text-align: right; font-size: 13px; color: #6b7280; font-family: monospace;'>TTFT -- ms&nbsp;&nbsp;|&nbsp;&nbsp;Decode -- ms/token&nbsp;&nbsp;|&nbsp;&nbsp;Tokens --</div>"), gr.update(interactive=True)
357
-
358
- send_btn.click(
359
- fn=demo.chat,
360
- inputs=[user_input, image_input],
361
- outputs=[chatbot, user_input, image_input, metrics_md, send_btn],
362
- show_progress=False,
363
- queue=True,
364
- )
365
- # 移除 user_input.submit,由自定义 JS 处理 Enter 发送,Shift+Enter 换行
366
- clear_btn.click(fn=_clear, inputs=None, outputs=[chatbot, user_input, image_input, metrics_md, send_btn])
367
-
368
- iface.queue().launch(server_name=server_name, server_port=server_port, share=share)
369
-
370
-
371
- def parse_args():
372
- parser = argparse.ArgumentParser(description="InternVL3-5-2B AX gradio demo")
373
- parser.add_argument("--hf_model", type=str, default="./InternVL3_5-2B",
374
- help="HuggingFace 模型路径")
375
- parser.add_argument("--axmodel_path", type=str, default="./InternVL3_5-2B_axmodel",
376
- help="LLM axmodel 目录")
377
- parser.add_argument("--vit_model", type=str, default="./vit-models/internvl_vit_model_1x3x448x448.axmodel",
378
- help="ViT axmodel 路径")
379
- parser.add_argument("--port", type=int, default=7860, help="Gradio 端口")
380
- parser.add_argument("--host", type=str, default="0.0.0.0", help="Gradio 监听地址")
381
- parser.add_argument("--share", action="store_true", help="启用 gradio share")
382
- return parser.parse_args()
383
-
384
-
385
- def main():
386
- args = parse_args()
387
- demo = InternVLGradioDemo(args.hf_model, args.axmodel_path, args.vit_model)
388
- InternVLGradioDemo.build_ui(demo, server_name=args.host, server_port=args.port, share=args.share)
389
-
390
-
391
- if __name__ == "__main__":
392
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
infer_axmodel.py DELETED
@@ -1,186 +0,0 @@
1
- from transformers import AutoProcessor, AutoModelForImageTextToText
2
- import torch
3
- import onnx
4
- import onnxruntime as ort
5
- import numpy as np
6
- import os
7
- from tqdm import tqdm
8
- from transformers import AutoConfig, AutoTokenizer
9
- from typing import List, Tuple
10
- from axengine import InferenceSession
11
- from ml_dtypes import bfloat16
12
- from utils.infer_func import InferManager
13
- import argparse
14
- from PIL import Image
15
- import torchvision.transforms as T
16
- from torchvision.transforms.functional import InterpolationMode
17
-
18
-
19
- IMAGENET_MEAN = (0.485, 0.456, 0.406)
20
- IMAGENET_STD = (0.229, 0.224, 0.225)
21
-
22
- def build_transform(input_size):
23
- MEAN, STD = IMAGENET_MEAN, IMAGENET_STD
24
- transform = T.Compose([
25
- T.Lambda(lambda img: img.convert('RGB') if img.mode != 'RGB' else img),
26
- T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC),
27
- T.ToTensor(),
28
- T.Normalize(mean=MEAN, std=STD)
29
- ])
30
- return transform
31
-
32
- def find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, image_size):
33
- best_ratio_diff = float('inf')
34
- best_ratio = (1, 1)
35
- area = width * height
36
- for ratio in target_ratios:
37
- target_aspect_ratio = ratio[0] / ratio[1]
38
- ratio_diff = abs(aspect_ratio - target_aspect_ratio)
39
- if ratio_diff < best_ratio_diff:
40
- best_ratio_diff = ratio_diff
41
- best_ratio = ratio
42
- elif ratio_diff == best_ratio_diff:
43
- if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
44
- best_ratio = ratio
45
- return best_ratio
46
-
47
- def dynamic_preprocess(image, min_num=1, max_num=12, image_size=448, use_thumbnail=False):
48
- orig_width, orig_height = image.size
49
- aspect_ratio = orig_width / orig_height
50
-
51
- # calculate the existing image aspect ratio
52
- target_ratios = set(
53
- (i, j) for n in range(min_num, max_num + 1) for i in range(1, n + 1) for j in range(1, n + 1) if
54
- i * j <= max_num and i * j >= min_num)
55
- target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])
56
-
57
- # find the closest aspect ratio to the target
58
- target_aspect_ratio = find_closest_aspect_ratio(
59
- aspect_ratio, target_ratios, orig_width, orig_height, image_size)
60
-
61
- # calculate the target width and height
62
- target_width = image_size * target_aspect_ratio[0]
63
- target_height = image_size * target_aspect_ratio[1]
64
- blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
65
-
66
- # resize the image
67
- resized_img = image.resize((target_width, target_height))
68
- processed_images = []
69
- for i in range(blocks):
70
- box = (
71
- (i % (target_width // image_size)) * image_size,
72
- (i // (target_width // image_size)) * image_size,
73
- ((i % (target_width // image_size)) + 1) * image_size,
74
- ((i // (target_width // image_size)) + 1) * image_size
75
- )
76
- # split the image
77
- split_img = resized_img.crop(box)
78
- processed_images.append(split_img)
79
- assert len(processed_images) == blocks
80
- if use_thumbnail and len(processed_images) != 1:
81
- thumbnail_img = image.resize((image_size, image_size))
82
- processed_images.append(thumbnail_img)
83
- return processed_images
84
-
85
- def load_image(image_file, input_size=448, max_num=12):
86
- image = Image.open(image_file).convert('RGB')
87
- transform = build_transform(input_size=input_size)
88
- images = dynamic_preprocess(image, image_size=input_size, use_thumbnail=True, max_num=max_num)
89
- pixel_values = [transform(image) for image in images]
90
- pixel_values = torch.stack(pixel_values)
91
- return pixel_values
92
-
93
- if __name__ == "__main__":
94
-
95
- """
96
- python3 infer_axmodel.py --vit_model vit-models/internvl_vit_model_1x3x448x448.axmodel --images examples/image_0.jpg
97
- """
98
- prompt = None
99
- parser = argparse.ArgumentParser(description="Model configuration parameters")
100
- parser.add_argument("--hf_model", type=str, default="./InternVL3_5-1B",
101
- help="Path to HuggingFace model")
102
- parser.add_argument("--axmodel_path", type=str, default="./InternVL3_5-1B_axmodel",
103
- help="Path to save compiled axmodel of llama model")
104
- parser.add_argument("--vit_model", type=str, default=None, help="Path to save compiled axmodel of llama model")
105
- parser.add_argument("-i", "--images", nargs='+', type=str, default=None,
106
- help="Path to the test image.")
107
- parser.add_argument("-q", "--question", type=str, default="请你描述这幅图的内容.",
108
- help="Your question that you want to ask the model.")
109
- args = parser.parse_args()
110
-
111
- hf_model_path = args.hf_model
112
- axmodel_path = args.axmodel_path
113
- images = args.images
114
- prompt = args.question
115
-
116
- device = "cuda" if torch.cuda.is_available() else "cpu"
117
- embeds = np.load(os.path.join(axmodel_path, "model.embed_tokens.weight.npy"))
118
-
119
- # load the tokenizer and the model
120
- tokenizer = AutoTokenizer.from_pretrained(hf_model_path)
121
- config = AutoConfig.from_pretrained(hf_model_path, trust_remote_code=True)
122
-
123
- # model = AutoModelForCausalLM.from_pretrained(
124
- # hf_model_path,
125
- # ).to(device)
126
-
127
- test_imgs_path = args.images
128
- vit_axmodel_path = args.vit_model
129
-
130
- # set the max number of tiles in `max_num`
131
- pixel_values_list = []
132
- if test_imgs_path is not None:
133
- for img_path in test_imgs_path:
134
- pixel_values = load_image(img_path, input_size=448, max_num=1)
135
- pixel_values_list.append(pixel_values)
136
- print(f"输入图像数: {len(pixel_values_list)}")
137
- print("preprocess image done!")
138
-
139
- # extract img feature by vit
140
- vit_session = InferenceSession(vit_axmodel_path)
141
- vit_output_list = []
142
- for idx, pixel_values in enumerate(pixel_values_list):
143
- vit_output = vit_session.run(None, {"image": pixel_values.numpy()})[0]
144
- vit_output_list.append(vit_output.copy()) # 避免 vit 输出结果使用同一块内存
145
-
146
- print(f"vit_output.shape is {vit_output_list[0].shape}, vit feature extract done!")
147
-
148
- prompt = "<|im_start|>system\n你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型, 英文名叫 InternVL3, 是一个有用无害的人工智能助手, 擅长思考和回答用户的问题. 请你在回答问题时使用简体中文.<|im_end|>\n"
149
- question = args.question
150
- prompt += "<|im_start|>user\n" + question
151
-
152
- if len(pixel_values_list) > 0:
153
- for idx in range(len(pixel_values_list)):
154
- prompt += "\n<img>" + "<IMG_CONTEXT>" * 256 + "</img>\n"
155
- prompt += "<|im_end|>\n<|im_start|>assistant\n"
156
- print(f"prompt is {prompt}")
157
- token_ids = tokenizer.encode(prompt)
158
- # 图像理解
159
- image_start_indices = np.where(np.array(token_ids) == 151669)[0].tolist() # <img> tag 151669, 151665
160
- prefill_data = np.take(embeds, token_ids, axis=0)
161
- prefill_data = prefill_data.astype(bfloat16)
162
- token_len = len(token_ids)
163
-
164
- for idx, image_start_index in enumerate(image_start_indices):
165
- image_insert_index = image_start_index + 1
166
- prefill_data[image_insert_index : image_insert_index + 256] = vit_output_list[idx][0, :, :]
167
- ##################################
168
-
169
- if hasattr(config, 'llm_config') and config.llm_config is not None: # 兼容 GPTQ INT4 模型
170
- cfg = config.llm_config
171
- else:
172
- cfg = config
173
-
174
- eos_token_id = None
175
- if isinstance(cfg.eos_token_id, list) and len(cfg.eos_token_id) > 1:
176
- eos_token_id = cfg.eos_token_id
177
-
178
- slice_len = 128
179
- prefill_max_len = 1024 - 1
180
- max_seq_len = 2048 - 1 # prefill + decode max length
181
-
182
- imer = InferManager(cfg, axmodel_path, max_seq_len=max_seq_len) # prefill + decode max length
183
- # import pdb; pdb.set_trace()
184
- token_ids = imer.prefill(tokenizer, token_ids, prefill_data, slice_len=slice_len)
185
- imer.decode(tokenizer, token_ids, embeds, slice_len=slice_len, eos_token_id=eos_token_id)
186
- print("\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
infer_torch.py DELETED
@@ -1,212 +0,0 @@
1
- import math
2
- import numpy as np
3
- import torch
4
- import torchvision.transforms as T
5
- from decord import VideoReader, cpu
6
- from PIL import Image
7
- from torchvision.transforms.functional import InterpolationMode
8
- from transformers import AutoModel, AutoTokenizer
9
-
10
- IMAGENET_MEAN = (0.485, 0.456, 0.406)
11
- IMAGENET_STD = (0.229, 0.224, 0.225)
12
-
13
- def build_transform(input_size):
14
- MEAN, STD = IMAGENET_MEAN, IMAGENET_STD
15
- transform = T.Compose([
16
- T.Lambda(lambda img: img.convert('RGB') if img.mode != 'RGB' else img),
17
- T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC),
18
- T.ToTensor(),
19
- T.Normalize(mean=MEAN, std=STD)
20
- ])
21
- return transform
22
-
23
- def find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, image_size):
24
- best_ratio_diff = float('inf')
25
- best_ratio = (1, 1)
26
- area = width * height
27
- for ratio in target_ratios:
28
- target_aspect_ratio = ratio[0] / ratio[1]
29
- ratio_diff = abs(aspect_ratio - target_aspect_ratio)
30
- if ratio_diff < best_ratio_diff:
31
- best_ratio_diff = ratio_diff
32
- best_ratio = ratio
33
- elif ratio_diff == best_ratio_diff:
34
- if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
35
- best_ratio = ratio
36
- return best_ratio
37
-
38
- def dynamic_preprocess(image, min_num=1, max_num=12, image_size=448, use_thumbnail=False):
39
- orig_width, orig_height = image.size
40
- aspect_ratio = orig_width / orig_height
41
-
42
- # calculate the existing image aspect ratio
43
- target_ratios = set(
44
- (i, j) for n in range(min_num, max_num + 1) for i in range(1, n + 1) for j in range(1, n + 1) if
45
- i * j <= max_num and i * j >= min_num)
46
- target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])
47
-
48
- # find the closest aspect ratio to the target
49
- target_aspect_ratio = find_closest_aspect_ratio(
50
- aspect_ratio, target_ratios, orig_width, orig_height, image_size)
51
-
52
- # calculate the target width and height
53
- target_width = image_size * target_aspect_ratio[0]
54
- target_height = image_size * target_aspect_ratio[1]
55
- blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
56
-
57
- # resize the image
58
- resized_img = image.resize((target_width, target_height))
59
- processed_images = []
60
- for i in range(blocks):
61
- box = (
62
- (i % (target_width // image_size)) * image_size,
63
- (i // (target_width // image_size)) * image_size,
64
- ((i % (target_width // image_size)) + 1) * image_size,
65
- ((i // (target_width // image_size)) + 1) * image_size
66
- )
67
- # split the image
68
- split_img = resized_img.crop(box)
69
- processed_images.append(split_img)
70
- assert len(processed_images) == blocks
71
- if use_thumbnail and len(processed_images) != 1:
72
- thumbnail_img = image.resize((image_size, image_size))
73
- processed_images.append(thumbnail_img)
74
- return processed_images
75
-
76
- def load_image(image_file, input_size=448, max_num=12):
77
- image = Image.open(image_file).convert('RGB')
78
- transform = build_transform(input_size=input_size)
79
- images = dynamic_preprocess(image, image_size=input_size, use_thumbnail=True, max_num=max_num)
80
- pixel_values = [transform(image) for image in images]
81
- pixel_values = torch.stack(pixel_values)
82
- return pixel_values
83
-
84
- path = './InternVL3_5-1B'
85
- model = AutoModel.from_pretrained(
86
- path,
87
- torch_dtype=torch.bfloat16,
88
- load_in_8bit=False,
89
- low_cpu_mem_usage=True,
90
- use_flash_attn=True,
91
- trust_remote_code=True,
92
- device_map="auto").eval()
93
- tokenizer = AutoTokenizer.from_pretrained(path, trust_remote_code=True, use_fast=False)
94
-
95
- # set the max number of tiles in `max_num`
96
- pixel_values = load_image('./examples/image_1.jpg', input_size=448, max_num=1).to(torch.bfloat16).cuda()
97
- generation_config = dict(max_new_tokens=1024, do_sample=True)
98
-
99
- # pure-text conversation (纯文本对话)
100
- question = '中国的首都'
101
- response, history = model.chat(tokenizer, None, question, generation_config, history=None, return_history=True)
102
- print(f'User: {question}\nAssistant: {response}')
103
-
104
-
105
- # single-image single-round conversation (单图单轮对话)
106
- question = '<image>\n请你描述这幅图的内容.'
107
- response = model.chat(tokenizer, pixel_values, question, generation_config)
108
- print(f'User: {question}\nAssistant: {response}')
109
-
110
- # # single-image multi-round conversation (单图多轮对话)
111
- # question = '<image>\nPlease describe the image in detail.'
112
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config, history=None, return_history=True)
113
- # print(f'User: {question}\nAssistant: {response}')
114
-
115
- # question = 'Please write a poem according to the image.'
116
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config, history=history, return_history=True)
117
- # print(f'User: {question}\nAssistant: {response}')
118
-
119
- # # multi-image multi-round conversation, combined images (多图多轮对话,拼接图像)
120
- # pixel_values1 = load_image('./examples/image1.jpg', max_num=12).to(torch.bfloat16).cuda()
121
- # pixel_values2 = load_image('./examples/image2.jpg', max_num=12).to(torch.bfloat16).cuda()
122
- # pixel_values = torch.cat((pixel_values1, pixel_values2), dim=0)
123
-
124
- # question = '<image>\nDescribe the two images in detail.'
125
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
126
- # history=None, return_history=True)
127
- # print(f'User: {question}\nAssistant: {response}')
128
-
129
- # question = 'What are the similarities and differences between these two images.'
130
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
131
- # history=history, return_history=True)
132
- # print(f'User: {question}\nAssistant: {response}')
133
-
134
- # # multi-image multi-round conversation, separate images (多图多轮对话,独立图像)
135
- # pixel_values1 = load_image('./examples/image1.jpg', max_num=12).to(torch.bfloat16).cuda()
136
- # pixel_values2 = load_image('./examples/image2.jpg', max_num=12).to(torch.bfloat16).cuda()
137
- # pixel_values = torch.cat((pixel_values1, pixel_values2), dim=0)
138
- # num_patches_list = [pixel_values1.size(0), pixel_values2.size(0)]
139
-
140
- # question = 'Image-1: <image>\nImage-2: <image>\nDescribe the two images in detail.'
141
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
142
- # num_patches_list=num_patches_list,
143
- # history=None, return_history=True)
144
- # print(f'User: {question}\nAssistant: {response}')
145
-
146
- # question = 'What are the similarities and differences between these two images.'
147
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
148
- # num_patches_list=num_patches_list,
149
- # history=history, return_history=True)
150
- # print(f'User: {question}\nAssistant: {response}')
151
-
152
- # # batch inference, single image per sample (单图批处理)
153
- # pixel_values1 = load_image('./examples/image1.jpg', max_num=12).to(torch.bfloat16).cuda()
154
- # pixel_values2 = load_image('./examples/image2.jpg', max_num=12).to(torch.bfloat16).cuda()
155
- # num_patches_list = [pixel_values1.size(0), pixel_values2.size(0)]
156
- # pixel_values = torch.cat((pixel_values1, pixel_values2), dim=0)
157
-
158
- # questions = ['<image>\nDescribe the image in detail.'] * len(num_patches_list)
159
- # responses = model.batch_chat(tokenizer, pixel_values,
160
- # num_patches_list=num_patches_list,
161
- # questions=questions,
162
- # generation_config=generation_config)
163
- # for question, response in zip(questions, responses):
164
- # print(f'User: {question}\nAssistant: {response}')
165
-
166
- # # video multi-round conversation (视频多轮对话)
167
- # def get_index(bound, fps, max_frame, first_idx=0, num_segments=32):
168
- # if bound:
169
- # start, end = bound[0], bound[1]
170
- # else:
171
- # start, end = -100000, 100000
172
- # start_idx = max(first_idx, round(start * fps))
173
- # end_idx = min(round(end * fps), max_frame)
174
- # seg_size = float(end_idx - start_idx) / num_segments
175
- # frame_indices = np.array([
176
- # int(start_idx + (seg_size / 2) + np.round(seg_size * idx))
177
- # for idx in range(num_segments)
178
- # ])
179
- # return frame_indices
180
-
181
- # def load_video(video_path, bound=None, input_size=448, max_num=1, num_segments=32):
182
- # vr = VideoReader(video_path, ctx=cpu(0), num_threads=1)
183
- # max_frame = len(vr) - 1
184
- # fps = float(vr.get_avg_fps())
185
-
186
- # pixel_values_list, num_patches_list = [], []
187
- # transform = build_transform(input_size=input_size)
188
- # frame_indices = get_index(bound, fps, max_frame, first_idx=0, num_segments=num_segments)
189
- # for frame_index in frame_indices:
190
- # img = Image.fromarray(vr[frame_index].asnumpy()).convert('RGB')
191
- # img = dynamic_preprocess(img, image_size=input_size, use_thumbnail=True, max_num=max_num)
192
- # pixel_values = [transform(tile) for tile in img]
193
- # pixel_values = torch.stack(pixel_values)
194
- # num_patches_list.append(pixel_values.shape[0])
195
- # pixel_values_list.append(pixel_values)
196
- # pixel_values = torch.cat(pixel_values_list)
197
- # return pixel_values, num_patches_list
198
-
199
- # video_path = './examples/red-panda.mp4'
200
- # pixel_values, num_patches_list = load_video(video_path, num_segments=8, max_num=1)
201
- # pixel_values = pixel_values.to(torch.bfloat16).cuda()
202
- # video_prefix = ''.join([f'Frame{i+1}: <image>\n' for i in range(len(num_patches_list))])
203
- # question = video_prefix + 'What is the red panda doing?'
204
- # # Frame1: <image>\nFrame2: <image>\n...\nFrame8: <image>\n{question}
205
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
206
- # num_patches_list=num_patches_list, history=None, return_history=True)
207
- # print(f'User: {question}\nAssistant: {response}')
208
-
209
- # question = 'Describe this video in detail.'
210
- # response, history = model.chat(tokenizer, pixel_values, question, generation_config,
211
- # num_patches_list=num_patches_list, history=history, return_history=True)
212
- # print(f'User: {question}\nAssistant: {response}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/merges.txt → internvl3-5-2b_tokenizer.txt RENAMED
The diff for this file is too large to render. See raw diff
 
internvl3-5_axmodel/model.embed_tokens.weight.float32.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:1604cef8ba75bc3c615e8b2853734464f54a26abea11f441e98f18fc49be24ab
3
- size 1244659712
 
 
 
 
internvl3-5_axmodel/model.embed_tokens.weight.npy DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0fd10721363fc0a9e0bd780faad607e032524fb4f6bcccf78068a5f7fe5319fc
3
- size 1244659840
 
 
 
 
internvl3-5_tokenizer/added_tokens.json DELETED
@@ -1,37 +0,0 @@
1
- {
2
- "</box>": 151677,
3
- "</img>": 151670,
4
- "</quad>": 151673,
5
- "</ref>": 151675,
6
- "</think>": 151668,
7
- "</tool_call>": 151658,
8
- "</tool_response>": 151666,
9
- "<IMG_CONTEXT>": 151671,
10
- "<box>": 151676,
11
- "<img>": 151669,
12
- "<quad>": 151672,
13
- "<ref>": 151674,
14
- "<think>": 151667,
15
- "<tool_call>": 151657,
16
- "<tool_response>": 151665,
17
- "<|box_end|>": 151649,
18
- "<|box_start|>": 151648,
19
- "<|endoftext|>": 151643,
20
- "<|file_sep|>": 151664,
21
- "<|fim_middle|>": 151660,
22
- "<|fim_pad|>": 151662,
23
- "<|fim_prefix|>": 151659,
24
- "<|fim_suffix|>": 151661,
25
- "<|im_end|>": 151645,
26
- "<|im_start|>": 151644,
27
- "<|image_pad|>": 151655,
28
- "<|object_ref_end|>": 151647,
29
- "<|object_ref_start|>": 151646,
30
- "<|quad_end|>": 151651,
31
- "<|quad_start|>": 151650,
32
- "<|repo_name|>": 151663,
33
- "<|video_pad|>": 151656,
34
- "<|vision_end|>": 151653,
35
- "<|vision_pad|>": 151654,
36
- "<|vision_start|>": 151652
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/config.json DELETED
@@ -1,89 +0,0 @@
1
- {
2
- "architectures": [
3
- "Qwen3ForCausalLM"
4
- ],
5
- "attention_bias": false,
6
- "attention_dropout": 0.0,
7
- "bos_token_id": 151643,
8
- "debug": false,
9
- "dtype": "bfloat16",
10
- "eos_token_id": 151645,
11
- "ep_size": 1,
12
- "head_dim": 128,
13
- "hidden_act": "silu",
14
- "hidden_size": 2048,
15
- "initializer_range": 0.02,
16
- "intermediate_size": 6144,
17
- "layer_types": [
18
- "full_attention",
19
- "full_attention",
20
- "full_attention",
21
- "full_attention",
22
- "full_attention",
23
- "full_attention",
24
- "full_attention",
25
- "full_attention",
26
- "full_attention",
27
- "full_attention",
28
- "full_attention",
29
- "full_attention",
30
- "full_attention",
31
- "full_attention",
32
- "full_attention",
33
- "full_attention",
34
- "full_attention",
35
- "full_attention",
36
- "full_attention",
37
- "full_attention",
38
- "full_attention",
39
- "full_attention",
40
- "full_attention",
41
- "full_attention",
42
- "full_attention",
43
- "full_attention",
44
- "full_attention",
45
- "full_attention"
46
- ],
47
- "max_position_embeddings": 40960,
48
- "max_window_layers": 28,
49
- "micro_forward": false,
50
- "model_type": "qwen3",
51
- "num_attention_heads": 16,
52
- "num_hidden_layers": 28,
53
- "num_key_value_heads": 8,
54
- "quantization_config": {
55
- "bits": 4,
56
- "checkpoint_format": "gptq",
57
- "desc_act": false,
58
- "group_size": 128,
59
- "lm_head": false,
60
- "meta": {
61
- "act_group_aware": false,
62
- "damp_auto_increment": 0.01,
63
- "damp_percent": 0.01,
64
- "mse": 0.0,
65
- "quantizer": [
66
- "gptqmodel:5.0.0-dev0"
67
- ],
68
- "static_groups": false,
69
- "true_sequential": true,
70
- "uri": "https://github.com/modelcloud/gptqmodel",
71
- "v2": false,
72
- "v2_alpha": 0.25
73
- },
74
- "pack_dtype": "int32",
75
- "quant_method": "gptq",
76
- "sym": true
77
- },
78
- "rms_norm_eps": 1e-06,
79
- "rope_scaling": null,
80
- "rope_theta": 1000000,
81
- "skip_checkpoint": false,
82
- "sliding_window": null,
83
- "tie_word_embeddings": false,
84
- "transformers_version": "4.56.2",
85
- "use_cache": false,
86
- "use_deepep": false,
87
- "use_sliding_window": false,
88
- "vocab_size": 151936
89
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/generation_config.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "_from_model_config": true,
3
- "transformers_version": "4.56.2"
4
- }
 
 
 
 
 
internvl3-5_tokenizer/quant_eval_results.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "cosine_mean": 0.96240234375,
3
- "cosine_std": 0.0167236328125,
4
- "cosine_min": 0.89794921875,
5
- "cosine_max": 0.9912109375
6
- }
 
 
 
 
 
 
 
internvl3-5_tokenizer/quant_log.csv DELETED
@@ -1,197 +0,0 @@
1
- layer,module,loss,samples,damp,time
2
- 0,self_attn.q_proj,0.0000028287,0.01000,1.122
3
- 0,self_attn.k_proj,0.0000013575,0.01000,0.480
4
- 0,self_attn.v_proj,0.0000011600,0.01000,0.476
5
- 0,self_attn.o_proj,0.0000036256,0.01000,0.470
6
- 0,mlp.gate_proj,0.0000437549,0.01000,0.482
7
- 0,mlp.up_proj,0.0000267884,0.01000,0.481
8
- 0,mlp.down_proj,0.0000072039,0.01000,1.513
9
- 1,self_attn.q_proj,0.0000029302,0.01000,0.817
10
- 1,self_attn.k_proj,0.0000015003,0.01000,0.502
11
- 1,self_attn.v_proj,0.0000014158,0.01000,0.500
12
- 1,self_attn.o_proj,0.0000016853,0.01000,0.489
13
- 1,mlp.gate_proj,0.0009522146,0.01000,0.493
14
- 1,mlp.up_proj,0.0003441322,0.01000,0.482
15
- 1,mlp.down_proj,0.0000125897,0.01000,1.510
16
- 2,self_attn.q_proj,0.0000063560,0.01000,0.669
17
- 2,self_attn.k_proj,0.0000029401,0.01000,0.483
18
- 2,self_attn.v_proj,0.0000029013,0.01000,0.483
19
- 2,self_attn.o_proj,0.0000026976,0.01000,0.491
20
- 2,mlp.gate_proj,0.0007206563,0.01000,0.481
21
- 2,mlp.up_proj,0.0002565878,0.01000,0.482
22
- 2,mlp.down_proj,0.0675307913,0.01000,1.505
23
- 3,self_attn.q_proj,0.0000384238,0.01000,0.648
24
- 3,self_attn.k_proj,0.0000200568,0.01000,0.485
25
- 3,self_attn.v_proj,0.0000195524,0.01000,0.483
26
- 3,self_attn.o_proj,0.0000032158,0.01000,0.475
27
- 3,mlp.gate_proj,0.0008880800,0.01000,0.484
28
- 3,mlp.up_proj,0.0003446824,0.01000,0.481
29
- 3,mlp.down_proj,0.0000226135,0.01000,1.513
30
- 4,self_attn.q_proj,0.0000386142,0.01000,0.654
31
- 4,self_attn.k_proj,0.0000196975,0.01000,0.490
32
- 4,self_attn.v_proj,0.0000199153,0.01000,0.491
33
- 4,self_attn.o_proj,0.0000056813,0.01000,0.482
34
- 4,mlp.gate_proj,0.0006523710,0.01000,0.485
35
- 4,mlp.up_proj,0.0002876575,0.01000,0.491
36
- 4,mlp.down_proj,0.0000332622,0.01000,1.537
37
- 5,self_attn.q_proj,0.0000574806,0.01000,0.686
38
- 5,self_attn.k_proj,0.0000248645,0.01000,0.490
39
- 5,self_attn.v_proj,0.0000303848,0.01000,0.491
40
- 5,self_attn.o_proj,0.0000087608,0.01000,0.482
41
- 5,mlp.gate_proj,0.0002589391,0.01000,0.487
42
- 5,mlp.up_proj,0.0001756437,0.01000,0.484
43
- 5,mlp.down_proj,0.0000397888,0.01000,1.526
44
- 6,self_attn.q_proj,0.0000415340,0.01000,0.656
45
- 6,self_attn.k_proj,0.0000201673,0.01000,0.490
46
- 6,self_attn.v_proj,0.0000206473,0.01000,0.488
47
- 6,self_attn.o_proj,0.0000094276,0.01000,0.481
48
- 6,mlp.gate_proj,0.0003516497,0.01000,0.488
49
- 6,mlp.up_proj,0.0002418573,0.01000,0.487
50
- 6,mlp.down_proj,0.0000589585,0.01000,1.537
51
- 7,self_attn.q_proj,0.0000895868,0.01000,0.651
52
- 7,self_attn.k_proj,0.0000390398,0.01000,0.490
53
- 7,self_attn.v_proj,0.0000468701,0.01000,0.488
54
- 7,self_attn.o_proj,0.0000154576,0.01000,0.478
55
- 7,mlp.gate_proj,0.0004709592,0.01000,0.484
56
- 7,mlp.up_proj,0.0003113569,0.01000,0.490
57
- 7,mlp.down_proj,0.0000668873,0.01000,1.534
58
- 8,self_attn.q_proj,0.0001087862,0.01000,0.669
59
- 8,self_attn.k_proj,0.0000534895,0.01000,0.489
60
- 8,self_attn.v_proj,0.0000521546,0.01000,0.489
61
- 8,self_attn.o_proj,0.0000117340,0.01000,0.480
62
- 8,mlp.gate_proj,0.0004199908,0.01000,0.477
63
- 8,mlp.up_proj,0.0003074690,0.01000,0.480
64
- 8,mlp.down_proj,0.0000799455,0.01000,1.522
65
- 9,self_attn.q_proj,0.0002144293,0.01000,0.858
66
- 9,self_attn.k_proj,0.0000993999,0.01000,0.485
67
- 9,self_attn.v_proj,0.0000977489,0.01000,0.486
68
- 9,self_attn.o_proj,0.0000329630,0.01000,0.474
69
- 9,mlp.gate_proj,0.0004030658,0.01000,0.481
70
- 9,mlp.up_proj,0.0003244922,0.01000,0.482
71
- 9,mlp.down_proj,0.0001223796,0.01000,1.511
72
- 10,self_attn.q_proj,0.0001646203,0.01000,0.661
73
- 10,self_attn.k_proj,0.0000742524,0.01000,0.492
74
- 10,self_attn.v_proj,0.0000792629,0.01000,0.491
75
- 10,self_attn.o_proj,0.0000381727,0.01000,0.475
76
- 10,mlp.gate_proj,0.0004072631,0.01000,0.482
77
- 10,mlp.up_proj,0.0003358870,0.01000,0.476
78
- 10,mlp.down_proj,0.0001950185,0.01000,1.540
79
- 11,self_attn.q_proj,0.0003723003,0.01000,0.662
80
- 11,self_attn.k_proj,0.0001662678,0.01000,0.494
81
- 11,self_attn.v_proj,0.0001578873,0.01000,0.488
82
- 11,self_attn.o_proj,0.0000987997,0.01000,0.478
83
- 11,mlp.gate_proj,0.0003472215,0.01000,0.488
84
- 11,mlp.up_proj,0.0003287667,0.01000,0.489
85
- 11,mlp.down_proj,0.0002170780,0.01000,1.532
86
- 12,self_attn.q_proj,0.0003013455,0.01000,0.655
87
- 12,self_attn.k_proj,0.0001367587,0.01000,0.488
88
- 12,self_attn.v_proj,0.0001409602,0.01000,0.491
89
- 12,self_attn.o_proj,0.0000535749,0.01000,0.474
90
- 12,mlp.gate_proj,0.0003395944,0.01000,0.482
91
- 12,mlp.up_proj,0.0003452886,0.01000,0.484
92
- 12,mlp.down_proj,0.0002339401,0.01000,1.532
93
- 13,self_attn.q_proj,0.0004235713,0.01000,0.650
94
- 13,self_attn.k_proj,0.0001706110,0.01000,0.491
95
- 13,self_attn.v_proj,0.0001876278,0.01000,0.490
96
- 13,self_attn.o_proj,0.0000764515,0.01000,0.480
97
- 13,mlp.gate_proj,0.0003770797,0.01000,0.483
98
- 13,mlp.up_proj,0.0003777360,0.01000,0.481
99
- 13,mlp.down_proj,0.0002857019,0.01000,1.512
100
- 14,self_attn.q_proj,0.0007051087,0.01000,0.643
101
- 14,self_attn.k_proj,0.0003071910,0.01000,0.486
102
- 14,self_attn.v_proj,0.0003141222,0.01000,0.481
103
- 14,self_attn.o_proj,0.0000914036,0.01000,0.474
104
- 14,mlp.gate_proj,0.0004245004,0.01000,0.483
105
- 14,mlp.up_proj,0.0004339850,0.01000,0.483
106
- 14,mlp.down_proj,0.0003975430,0.01000,1.505
107
- 15,self_attn.q_proj,0.0015869274,0.01000,0.868
108
- 15,self_attn.k_proj,0.0005557225,0.01000,0.479
109
- 15,self_attn.v_proj,0.0007385406,0.01000,0.479
110
- 15,self_attn.o_proj,0.0001717588,0.01000,0.469
111
- 15,mlp.gate_proj,0.0005073424,0.01000,0.477
112
- 15,mlp.up_proj,0.0005269765,0.01000,0.477
113
- 15,mlp.down_proj,0.0005912411,0.01000,1.506
114
- 16,self_attn.q_proj,0.0021061117,0.01000,0.868
115
- 16,self_attn.k_proj,0.0007697947,0.01000,0.478
116
- 16,self_attn.v_proj,0.0008052027,0.01000,0.476
117
- 16,self_attn.o_proj,0.0002286357,0.01000,0.466
118
- 16,mlp.gate_proj,0.0005959417,0.01000,0.479
119
- 16,mlp.up_proj,0.0006820880,0.01000,0.488
120
- 16,mlp.down_proj,0.0015508921,0.01000,1.524
121
- 17,self_attn.q_proj,0.0055543600,0.01000,0.650
122
- 17,self_attn.k_proj,0.0020179782,0.01000,0.488
123
- 17,self_attn.v_proj,0.0025371906,0.01000,0.481
124
- 17,self_attn.o_proj,0.0005401876,0.01000,0.471
125
- 17,mlp.gate_proj,0.0008525012,0.01000,0.478
126
- 17,mlp.up_proj,0.0009743239,0.01000,0.473
127
- 17,mlp.down_proj,0.0019300004,0.01000,1.497
128
- 18,self_attn.q_proj,0.0071615855,0.01000,0.836
129
- 18,self_attn.k_proj,0.0024612989,0.01000,0.479
130
- 18,self_attn.v_proj,0.0029228464,0.01000,0.477
131
- 18,self_attn.o_proj,0.0004554841,0.01000,0.461
132
- 18,mlp.gate_proj,0.0011518225,0.01000,0.479
133
- 18,mlp.up_proj,0.0012972882,0.01000,0.477
134
- 18,mlp.down_proj,0.0033720387,0.01000,1.492
135
- 19,self_attn.q_proj,0.0129074770,0.01000,0.640
136
- 19,self_attn.k_proj,0.0042499688,0.01000,0.478
137
- 19,self_attn.v_proj,0.0056665521,0.01000,0.483
138
- 19,self_attn.o_proj,0.0008474814,0.01000,0.472
139
- 19,mlp.gate_proj,0.0015841057,0.01000,0.480
140
- 19,mlp.up_proj,0.0018163190,0.01000,0.483
141
- 19,mlp.down_proj,0.0073965770,0.01000,1.515
142
- 20,self_attn.q_proj,0.0213903782,0.01000,0.638
143
- 20,self_attn.k_proj,0.0073983278,0.01000,0.480
144
- 20,self_attn.v_proj,0.0096556293,0.01000,0.478
145
- 20,self_attn.o_proj,0.0011031375,0.01000,0.470
146
- 20,mlp.gate_proj,0.0020351633,0.01000,0.478
147
- 20,mlp.up_proj,0.0022976996,0.01000,0.474
148
- 20,mlp.down_proj,0.0108348703,0.01000,1.502
149
- 21,self_attn.q_proj,0.0317660292,0.01000,0.639
150
- 21,self_attn.k_proj,0.0116202132,0.01000,0.479
151
- 21,self_attn.v_proj,0.0158023123,0.01000,0.476
152
- 21,self_attn.o_proj,0.0015908420,0.01000,0.474
153
- 21,mlp.gate_proj,0.0023832206,0.01000,0.479
154
- 21,mlp.up_proj,0.0027572736,0.01000,0.477
155
- 21,mlp.down_proj,0.0158048804,0.01000,1.495
156
- 22,self_attn.q_proj,0.0407548736,0.01000,0.640
157
- 22,self_attn.k_proj,0.0150106458,0.01000,0.477
158
- 22,self_attn.v_proj,0.0202007413,0.01000,0.477
159
- 22,self_attn.o_proj,0.0021502327,0.01000,0.463
160
- 22,mlp.gate_proj,0.0026785822,0.01000,0.474
161
- 22,mlp.up_proj,0.0030653916,0.01000,0.475
162
- 22,mlp.down_proj,0.0178709172,0.01000,1.495
163
- 23,self_attn.q_proj,0.0446284787,0.01000,0.634
164
- 23,self_attn.k_proj,0.0190296860,0.01000,0.480
165
- 23,self_attn.v_proj,0.0239933381,0.01000,0.479
166
- 23,self_attn.o_proj,0.0020754843,0.01000,0.470
167
- 23,mlp.gate_proj,0.0031200403,0.01000,0.482
168
- 23,mlp.up_proj,0.0035550402,0.01000,0.483
169
- 23,mlp.down_proj,0.0204610985,0.01000,1.501
170
- 24,self_attn.q_proj,0.0858624045,0.01000,0.842
171
- 24,self_attn.k_proj,0.0326525819,0.01000,0.478
172
- 24,self_attn.v_proj,0.0390621431,0.01000,0.477
173
- 24,self_attn.o_proj,0.0024571737,0.01000,0.465
174
- 24,mlp.gate_proj,0.0030477483,0.01000,0.478
175
- 24,mlp.up_proj,0.0035677395,0.01000,0.477
176
- 24,mlp.down_proj,0.0243642852,0.01000,1.499
177
- 25,self_attn.q_proj,0.1048494028,0.01000,0.821
178
- 25,self_attn.k_proj,0.0388391669,0.01000,0.480
179
- 25,self_attn.v_proj,0.0599689154,0.01000,0.481
180
- 25,self_attn.o_proj,0.0033398975,0.01000,0.469
181
- 25,mlp.gate_proj,0.0029867548,0.01000,0.484
182
- 25,mlp.up_proj,0.0035876434,0.01000,0.488
183
- 25,mlp.down_proj,0.0297861800,0.01000,1.520
184
- 26,self_attn.q_proj,0.1303999851,0.01000,0.858
185
- 26,self_attn.k_proj,0.0390620764,0.01000,0.486
186
- 26,self_attn.v_proj,0.0593836054,0.01000,0.496
187
- 26,self_attn.o_proj,0.0102463794,0.01000,0.474
188
- 26,mlp.gate_proj,0.0032039998,0.01000,0.488
189
- 26,mlp.up_proj,0.0038089303,0.01000,0.487
190
- 26,mlp.down_proj,0.0374598204,0.01000,1.521
191
- 27,self_attn.q_proj,0.0429687971,0.01000,0.632
192
- 27,self_attn.k_proj,0.0199527118,0.01000,0.472
193
- 27,self_attn.v_proj,0.0243092128,0.01000,0.477
194
- 27,self_attn.o_proj,0.0073438722,0.01000,0.463
195
- 27,mlp.gate_proj,0.0060571320,0.01000,0.479
196
- 27,mlp.up_proj,0.0061368420,0.01000,0.483
197
- 27,mlp.down_proj,0.0483323405,0.01000,1.496
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/quantize_config.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "bits": 4,
3
- "group_size": 128,
4
- "desc_act": false,
5
- "sym": true,
6
- "lm_head": false,
7
- "quant_method": "gptq",
8
- "checkpoint_format": "gptq",
9
- "pack_dtype": "int32",
10
- "meta": {
11
- "quantizer": [
12
- "gptqmodel:5.0.0-dev0"
13
- ],
14
- "uri": "https://github.com/modelcloud/gptqmodel",
15
- "damp_percent": 0.01,
16
- "damp_auto_increment": 0.01,
17
- "static_groups": false,
18
- "true_sequential": true,
19
- "mse": 0.0,
20
- "v2": false,
21
- "v2_alpha": 0.25,
22
- "act_group_aware": false
23
- }
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/quantize_done.txt DELETED
@@ -1 +0,0 @@
1
- done
 
 
internvl3-5_tokenizer/special_tokens_map.json DELETED
@@ -1,34 +0,0 @@
1
- {
2
- "additional_special_tokens": [
3
- "<|im_start|>",
4
- "<|im_end|>",
5
- "<|object_ref_start|>",
6
- "<|object_ref_end|>",
7
- "<|box_start|>",
8
- "<|box_end|>",
9
- "<|quad_start|>",
10
- "<|quad_end|>",
11
- "<|vision_start|>",
12
- "<|vision_end|>",
13
- "<|vision_pad|>",
14
- "<|image_pad|>",
15
- "<|video_pad|>",
16
- "<img>",
17
- "</img>",
18
- "<IMG_CONTEXT>",
19
- "<quad>",
20
- "</quad>",
21
- "<ref>",
22
- "</ref>",
23
- "<box>",
24
- "</box>"
25
- ],
26
- "eos_token": {
27
- "content": "<|im_end|>",
28
- "lstrip": false,
29
- "normalized": false,
30
- "rstrip": false,
31
- "single_word": false
32
- },
33
- "pad_token": "<|endoftext|>"
34
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/tokenizer.json DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:6581c44164d273d4222df982905a7e0450dcf3a4a7ebe98f9ec53e4de05beffe
3
- size 11424300
 
 
 
 
internvl3-5_tokenizer/tokenizer_config.json DELETED
@@ -1,323 +0,0 @@
1
- {
2
- "add_bos_token": false,
3
- "add_eos_token": false,
4
- "add_prefix_space": false,
5
- "added_tokens_decoder": {
6
- "151643": {
7
- "content": "<|endoftext|>",
8
- "lstrip": false,
9
- "normalized": false,
10
- "rstrip": false,
11
- "single_word": false,
12
- "special": true
13
- },
14
- "151644": {
15
- "content": "<|im_start|>",
16
- "lstrip": false,
17
- "normalized": false,
18
- "rstrip": false,
19
- "single_word": false,
20
- "special": true
21
- },
22
- "151645": {
23
- "content": "<|im_end|>",
24
- "lstrip": false,
25
- "normalized": false,
26
- "rstrip": false,
27
- "single_word": false,
28
- "special": true
29
- },
30
- "151646": {
31
- "content": "<|object_ref_start|>",
32
- "lstrip": false,
33
- "normalized": false,
34
- "rstrip": false,
35
- "single_word": false,
36
- "special": true
37
- },
38
- "151647": {
39
- "content": "<|object_ref_end|>",
40
- "lstrip": false,
41
- "normalized": false,
42
- "rstrip": false,
43
- "single_word": false,
44
- "special": true
45
- },
46
- "151648": {
47
- "content": "<|box_start|>",
48
- "lstrip": false,
49
- "normalized": false,
50
- "rstrip": false,
51
- "single_word": false,
52
- "special": true
53
- },
54
- "151649": {
55
- "content": "<|box_end|>",
56
- "lstrip": false,
57
- "normalized": false,
58
- "rstrip": false,
59
- "single_word": false,
60
- "special": true
61
- },
62
- "151650": {
63
- "content": "<|quad_start|>",
64
- "lstrip": false,
65
- "normalized": false,
66
- "rstrip": false,
67
- "single_word": false,
68
- "special": true
69
- },
70
- "151651": {
71
- "content": "<|quad_end|>",
72
- "lstrip": false,
73
- "normalized": false,
74
- "rstrip": false,
75
- "single_word": false,
76
- "special": true
77
- },
78
- "151652": {
79
- "content": "<|vision_start|>",
80
- "lstrip": false,
81
- "normalized": false,
82
- "rstrip": false,
83
- "single_word": false,
84
- "special": true
85
- },
86
- "151653": {
87
- "content": "<|vision_end|>",
88
- "lstrip": false,
89
- "normalized": false,
90
- "rstrip": false,
91
- "single_word": false,
92
- "special": true
93
- },
94
- "151654": {
95
- "content": "<|vision_pad|>",
96
- "lstrip": false,
97
- "normalized": false,
98
- "rstrip": false,
99
- "single_word": false,
100
- "special": true
101
- },
102
- "151655": {
103
- "content": "<|image_pad|>",
104
- "lstrip": false,
105
- "normalized": false,
106
- "rstrip": false,
107
- "single_word": false,
108
- "special": true
109
- },
110
- "151656": {
111
- "content": "<|video_pad|>",
112
- "lstrip": false,
113
- "normalized": false,
114
- "rstrip": false,
115
- "single_word": false,
116
- "special": true
117
- },
118
- "151657": {
119
- "content": "<tool_call>",
120
- "lstrip": false,
121
- "normalized": false,
122
- "rstrip": false,
123
- "single_word": false,
124
- "special": false
125
- },
126
- "151658": {
127
- "content": "</tool_call>",
128
- "lstrip": false,
129
- "normalized": false,
130
- "rstrip": false,
131
- "single_word": false,
132
- "special": false
133
- },
134
- "151659": {
135
- "content": "<|fim_prefix|>",
136
- "lstrip": false,
137
- "normalized": false,
138
- "rstrip": false,
139
- "single_word": false,
140
- "special": false
141
- },
142
- "151660": {
143
- "content": "<|fim_middle|>",
144
- "lstrip": false,
145
- "normalized": false,
146
- "rstrip": false,
147
- "single_word": false,
148
- "special": false
149
- },
150
- "151661": {
151
- "content": "<|fim_suffix|>",
152
- "lstrip": false,
153
- "normalized": false,
154
- "rstrip": false,
155
- "single_word": false,
156
- "special": false
157
- },
158
- "151662": {
159
- "content": "<|fim_pad|>",
160
- "lstrip": false,
161
- "normalized": false,
162
- "rstrip": false,
163
- "single_word": false,
164
- "special": false
165
- },
166
- "151663": {
167
- "content": "<|repo_name|>",
168
- "lstrip": false,
169
- "normalized": false,
170
- "rstrip": false,
171
- "single_word": false,
172
- "special": false
173
- },
174
- "151664": {
175
- "content": "<|file_sep|>",
176
- "lstrip": false,
177
- "normalized": false,
178
- "rstrip": false,
179
- "single_word": false,
180
- "special": false
181
- },
182
- "151665": {
183
- "content": "<tool_response>",
184
- "lstrip": false,
185
- "normalized": false,
186
- "rstrip": false,
187
- "single_word": false,
188
- "special": false
189
- },
190
- "151666": {
191
- "content": "</tool_response>",
192
- "lstrip": false,
193
- "normalized": false,
194
- "rstrip": false,
195
- "single_word": false,
196
- "special": false
197
- },
198
- "151667": {
199
- "content": "<think>",
200
- "lstrip": false,
201
- "normalized": false,
202
- "rstrip": false,
203
- "single_word": false,
204
- "special": false
205
- },
206
- "151668": {
207
- "content": "</think>",
208
- "lstrip": false,
209
- "normalized": false,
210
- "rstrip": false,
211
- "single_word": false,
212
- "special": false
213
- },
214
- "151669": {
215
- "content": "<img>",
216
- "lstrip": false,
217
- "normalized": false,
218
- "rstrip": false,
219
- "single_word": false,
220
- "special": true
221
- },
222
- "151670": {
223
- "content": "</img>",
224
- "lstrip": false,
225
- "normalized": false,
226
- "rstrip": false,
227
- "single_word": false,
228
- "special": true
229
- },
230
- "151671": {
231
- "content": "<IMG_CONTEXT>",
232
- "lstrip": false,
233
- "normalized": false,
234
- "rstrip": false,
235
- "single_word": false,
236
- "special": true
237
- },
238
- "151672": {
239
- "content": "<quad>",
240
- "lstrip": false,
241
- "normalized": false,
242
- "rstrip": false,
243
- "single_word": false,
244
- "special": true
245
- },
246
- "151673": {
247
- "content": "</quad>",
248
- "lstrip": false,
249
- "normalized": false,
250
- "rstrip": false,
251
- "single_word": false,
252
- "special": true
253
- },
254
- "151674": {
255
- "content": "<ref>",
256
- "lstrip": false,
257
- "normalized": false,
258
- "rstrip": false,
259
- "single_word": false,
260
- "special": true
261
- },
262
- "151675": {
263
- "content": "</ref>",
264
- "lstrip": false,
265
- "normalized": false,
266
- "rstrip": false,
267
- "single_word": false,
268
- "special": true
269
- },
270
- "151676": {
271
- "content": "<box>",
272
- "lstrip": false,
273
- "normalized": false,
274
- "rstrip": false,
275
- "single_word": false,
276
- "special": true
277
- },
278
- "151677": {
279
- "content": "</box>",
280
- "lstrip": false,
281
- "normalized": false,
282
- "rstrip": false,
283
- "single_word": false,
284
- "special": true
285
- }
286
- },
287
- "additional_special_tokens": [
288
- "<|im_start|>",
289
- "<|im_end|>",
290
- "<|object_ref_start|>",
291
- "<|object_ref_end|>",
292
- "<|box_start|>",
293
- "<|box_end|>",
294
- "<|quad_start|>",
295
- "<|quad_end|>",
296
- "<|vision_start|>",
297
- "<|vision_end|>",
298
- "<|vision_pad|>",
299
- "<|image_pad|>",
300
- "<|video_pad|>",
301
- "<img>",
302
- "</img>",
303
- "<IMG_CONTEXT>",
304
- "<quad>",
305
- "</quad>",
306
- "<ref>",
307
- "</ref>",
308
- "<box>",
309
- "</box>"
310
- ],
311
- "bos_token": null,
312
- "clean_up_tokenization_spaces": false,
313
- "eos_token": "<|im_end|>",
314
- "errors": "replace",
315
- "extra_special_tokens": {},
316
- "model_max_length": 14588,
317
- "pad_token": "<|endoftext|>",
318
- "processor_class": "InternVLProcessor",
319
- "split_special_tokens": false,
320
- "tokenizer_class": "Qwen2TokenizerFast",
321
- "unk_token": null,
322
- "_commit_hash": null
323
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
internvl3-5_tokenizer/vocab.json DELETED
The diff for this file is too large to render. See raw diff
 
post_config.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "enable_temperature" : true,
3
+ "temperature" : 0.7,
4
+
5
+ "enable_repetition_penalty" : true,
6
+ "repetition_penalty" : 1.2,
7
+ "penalty_window" : 30,
8
+
9
+ "enable_top_p_sampling" : false,
10
+ "top_p" : 0.9,
11
+
12
+ "enable_top_k_sampling" : true,
13
+ "top_k" : 10
14
+ }
utils/infer_func.py DELETED
@@ -1,283 +0,0 @@
1
- import torch
2
- import numpy as np
3
- from typing import List, Tuple
4
- from tqdm import tqdm
5
- from axengine import InferenceSession
6
- import os
7
- import re
8
- from ml_dtypes import bfloat16
9
-
10
-
11
- # Discover model files automatically from model_dir.
12
- # We expect files like: <prefix>_p128_l<idx>_together.axmodel and <prefix>_post.axmodel
13
- # we try to detect model prefix and layer files automatically
14
- def _find_axmodel_files(base_dir: str, expected_layers: int = None, expected_prefill: int = 128):
15
- files = os.listdir(base_dir)
16
- # match prefix, prefill size (dynamic), and layer index
17
- layer_pattern = re.compile(r"^(?P<prefix>.*)_p(?P<prefill>\d+)_l(?P<idx>\d+)_together\.axmodel$")
18
- post_pattern = re.compile(r"^(?P<prefix>.*)_post\.axmodel$")
19
-
20
- # collect prefix -> [(idx, fname)]
21
- prefix_map = {}
22
- for fname in files:
23
- m = layer_pattern.match(fname)
24
- if m:
25
- prefix = m.group("prefix")
26
- idx = int(m.group("idx"))
27
- prefix_map.setdefault(prefix, []).append((idx, fname))
28
-
29
- if not prefix_map:
30
- # fallback to hardcoded pattern if nothing detected
31
- prefix = "gemma3_text"
32
- layer_files = [(
33
- i, f"{prefix}_p{expected_prefill}_l{i}_together.axmodel"
34
- ) for i in range(expected_layers or 0)]
35
- else:
36
- # choose the prefix with the most layers (most likely the correct one)
37
- prefix = max(prefix_map.items(), key=lambda kv: len(kv[1]))[0]
38
- # debug info
39
- print(f"Detected prefixes: {list(prefix_map.keys())}, chosen: {prefix}, layers: {len(prefix_map[prefix])}")
40
- layer_files = sorted(prefix_map[prefix], key=lambda it: it[0])
41
-
42
- # find post process file
43
- post_file = None
44
- for fname in files:
45
- m = post_pattern.match(fname)
46
- if m and m.group("prefix") == prefix:
47
- post_file = fname
48
- break
49
- if post_file is None:
50
- candidate = os.path.join(base_dir, f"{prefix}_post.axmodel")
51
- if os.path.exists(candidate):
52
- post_file = f"{prefix}_post.axmodel"
53
- else:
54
- for fname in files:
55
- if fname.endswith("_post.axmodel"):
56
- post_file = fname
57
- break
58
-
59
- return layer_files, post_file, prefix
60
-
61
- class InferManager:
62
- def __init__(self, config, model_dir, max_seq_len=2047):
63
-
64
- self.config = config
65
- self.max_seq_len = max_seq_len
66
-
67
- self.sub_dim = config.hidden_size // config.num_attention_heads if not config.head_dim else config.head_dim
68
- self.kv_dim = self.sub_dim * config.num_key_value_heads
69
-
70
- self.k_caches = [
71
- np.zeros((1, self.max_seq_len, self.kv_dim), dtype=bfloat16)
72
- for _ in range(config.num_hidden_layers)
73
- ]
74
- self.v_caches = [
75
- np.zeros((1, self.max_seq_len, self.kv_dim), dtype=bfloat16)
76
- for _ in range(config.num_hidden_layers)
77
- ]
78
-
79
- layer_files, post_file, prefix = _find_axmodel_files(model_dir, config.num_hidden_layers)
80
-
81
- self.decoder_sessions = []
82
- for _, fname in tqdm(layer_files, desc="Init InferenceSession"):
83
- session = InferenceSession(os.path.join(model_dir, fname))
84
- self.decoder_sessions.append(session)
85
-
86
- # post_file was returned by _find_axmodel_files; ensure it was found
87
- if post_file is None:
88
- raise FileNotFoundError("Cannot find post process .axmodel file in model_dir")
89
- self.post_process_session = InferenceSession(os.path.join(model_dir, post_file))
90
- print("Model loaded successfully!")
91
-
92
- @staticmethod
93
- def _top_p(probs: np.ndarray, p: float) -> np.ndarray:
94
- sorted_indices = np.argsort(probs)
95
- filtered = probs.copy()
96
- cumulative = 0
97
- for idx in sorted_indices[::-1]:
98
- if cumulative >= p:
99
- filtered[idx] = 0
100
- cumulative += filtered[idx]
101
- return filtered / cumulative
102
-
103
- @staticmethod
104
- def _softmax(logits: np.ndarray) -> np.ndarray:
105
- logits = logits - logits.max()
106
- exp_logits = np.exp(logits)
107
- return (exp_logits / np.sum(exp_logits)).astype(np.float64)
108
-
109
- def post_process(self, logits, top_k=1, top_p=0.9, temperature=0.6):
110
- logits = logits.astype(np.float32).flatten()
111
- candidate_indices = np.argpartition(logits, -top_k)[-top_k:]
112
- candidate_logits = logits[candidate_indices] / temperature
113
- candidate_probs = self._softmax(candidate_logits)
114
- candidate_probs = self._top_p(candidate_probs, top_p)
115
- candidate_probs = candidate_probs.astype(np.float64) / candidate_probs.sum()
116
- chosen_idx = np.random.multinomial(1, candidate_probs).argmax()
117
- next_token = candidate_indices[chosen_idx]
118
- return next_token, candidate_indices, candidate_probs
119
-
120
- def gen_slice_indices(self, token_len, prefill=128, expand=128):
121
- remaining = max(0, token_len - prefill)
122
- extra_blocks = (remaining + expand - 1) // expand
123
- return list(range(extra_blocks + 1))
124
-
125
- def prefill(
126
- self,
127
- tokenizer,
128
- token_ids,
129
- embed_data,
130
- slice_len=128,
131
- ):
132
- """
133
- Prefill step for chunked inference.
134
- """
135
- seq_len = len(token_ids)
136
- slice_indices = [i for i in range(seq_len // slice_len + 1)]
137
- print(f"slice_indices: {slice_indices}")
138
- # total_prefill_len = (
139
- # slice_len * slice_indices[-1]
140
- # if slice_indices[-1] != 0
141
- # else slice_len
142
- # )
143
- total_prefill_len = slice_len * (slice_indices[-1] + 1)
144
- # slice_indices = self.gen_slice_indices(seq_len)
145
-
146
- if total_prefill_len > 0:
147
- for slice_idx in slice_indices:
148
- indices = np.arange(
149
- slice_idx * slice_len,
150
- (slice_idx + 1) * slice_len,
151
- dtype=np.uint32
152
- ).reshape((1, slice_len))
153
-
154
- mask = (
155
- np.zeros((1, slice_len, slice_len * (slice_idx + 1)))
156
- - 65536
157
- )
158
- data = np.zeros((1, slice_len, self.config.hidden_size)).astype(bfloat16)
159
- for i, t in enumerate(
160
- range(
161
- slice_idx * slice_len,
162
- (slice_idx + 1) * slice_len,
163
- )
164
- ):
165
- if t < len(token_ids):
166
- mask[:, i, : slice_idx * slice_len + i + 1] = 0
167
- data[:, i : i + 1, :] = (
168
- embed_data[t]
169
- .reshape((1, 1, self.config.hidden_size))
170
- .astype(bfloat16)
171
- )
172
-
173
- remain_len = (
174
- seq_len - slice_idx * slice_len
175
- if slice_idx == slice_indices[-1]
176
- else slice_len
177
- )
178
- mask = mask.astype(bfloat16)
179
- for layer_idx in range(self.config.num_hidden_layers):
180
- input_feed = {
181
- "K_cache": (
182
- self.k_caches[layer_idx][:, 0 : slice_len * slice_idx, :]
183
- if slice_idx
184
- else np.zeros((1, 1, self.config.hidden_size), dtype=bfloat16)
185
- ),
186
- "V_cache": (
187
- self.v_caches[layer_idx][:, 0 : slice_len * slice_idx, :]
188
- if slice_idx
189
- else np.zeros((1, 1, self.config.hidden_size), dtype=bfloat16)
190
- ),
191
- "indices": indices,
192
- "input": data,
193
- "mask": mask,
194
- }
195
- outputs = self.decoder_sessions[layer_idx].run(None, input_feed, shape_group=slice_idx + 1)
196
- self.k_caches[layer_idx][
197
- :,
198
- slice_idx * slice_len : slice_idx * slice_len + remain_len,
199
- :,
200
- ] = outputs[0][:, :remain_len, :]
201
- self.v_caches[layer_idx][
202
- :,
203
- slice_idx * slice_len : slice_idx * slice_len + remain_len,
204
- :,
205
- ] = outputs[1][:, :remain_len, :]
206
- data = outputs[2]
207
-
208
- print("Slice prefill done:", slice_idx)
209
-
210
- # return data[:, :remain_len, :]
211
- post_out = self.post_process_session.run(
212
- None,
213
- {
214
- "input": data[
215
- :, seq_len - (len(slice_indices) - 1) * slice_len - 1, None, :
216
- ]
217
- }
218
- )[0]
219
- next_token, possible_tokens, possible_probs = self.post_process(post_out)
220
- possible_decoded = [tokenizer.decode([t]) for t in possible_tokens]
221
- possible_probs_str = [str((t, p)) for t, p in zip(possible_decoded, possible_probs)]
222
- token_ids.append(next_token)
223
- return token_ids
224
-
225
- def decode(
226
- self,
227
- tokenizer,
228
- token_ids,
229
- embed_matrix,
230
- prefill_len=128,
231
- slice_len=128,
232
- eos_token_id=None, # 某些模型有多个 eos_token_id
233
- stream=True,
234
- ):
235
- """Autoregressive decode; optionally stream tokens or collect silently."""
236
-
237
- decoded_text = tokenizer.decode(token_ids[-1], skip_special_tokens=True)
238
- if stream:
239
- print("answer >>", decoded_text, end='', flush=True)
240
-
241
- mask = np.zeros((1, 1, self.max_seq_len + 1), dtype=np.float32).astype(bfloat16)
242
- mask[:, :, :self.max_seq_len] -= 65536
243
- seq_len = len(token_ids) - 1
244
- if prefill_len > 0:
245
- mask[:, :, :seq_len] = 0
246
-
247
- for step_idx in range(self.max_seq_len):
248
- if prefill_len > 0 and step_idx < seq_len:
249
- continue
250
- cur_token = token_ids[step_idx]
251
- indices = np.array([step_idx], np.uint32).reshape((1, 1))
252
- data = embed_matrix[cur_token, :].reshape((1, 1, self.config.hidden_size)).astype(bfloat16)
253
- for layer_idx in range(self.config.num_hidden_layers):
254
- input_feed = {
255
- "K_cache": self.k_caches[layer_idx],
256
- "V_cache": self.v_caches[layer_idx],
257
- "indices": indices,
258
- "input": data,
259
- "mask": mask,
260
- }
261
- outputs = self.decoder_sessions[layer_idx].run(None, input_feed, shape_group=0)
262
- self.k_caches[layer_idx][:, step_idx, :] = outputs[0][:, :, :]
263
- self.v_caches[layer_idx][:, step_idx, :] = outputs[1][:, :, :]
264
- data = outputs[2]
265
- mask[..., step_idx] = 0
266
- if step_idx < seq_len - 1:
267
- continue
268
- else:
269
- post_out = self.post_process_session.run(None, {"input": data})[0]
270
- next_token, possible_tokens, possible_probs = self.post_process(post_out, temperature=0.7)
271
- if eos_token_id is not None and next_token in eos_token_id:
272
- break
273
- elif next_token == tokenizer.eos_token_id:
274
- break
275
- token_ids.append(next_token)
276
-
277
- decoded_piece = tokenizer.decode(next_token, skip_special_tokens=True)
278
- decoded_text += decoded_piece
279
- if stream:
280
- print(decoded_piece, end='', flush=True)
281
-
282
- return decoded_text
283
-