Any-to-Any
Transformers
ONNX
Safetensors
minicpmo
feature-extraction
minicpm-o
minicpm-v
multimodal
full-duplex
custom_code
Instructions to use openbmb/MiniCPM-o-4_5 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use openbmb/MiniCPM-o-4_5 with Transformers:
# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("openbmb/MiniCPM-o-4_5", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Update modeling_minicpmo.py
#20
by cherry77-cloud - opened
- modeling_minicpmo.py +43 -36
- processing_minicpmo.py +1 -1
modeling_minicpmo.py
CHANGED
|
@@ -763,37 +763,36 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 763 |
audio_embs = audio_embeddings[i]
|
| 764 |
bounds = audio_bounds[i]
|
| 765 |
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 774 |
device=input_embeddings.device,
|
| 775 |
dtype=input_embeddings.dtype,
|
| 776 |
)
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
for bound in bounds:
|
| 792 |
-
audio_len = int(bound[1] - bound[0])
|
| 793 |
-
input_embeddings[i, bound[0] : bound[1]] = flat_audio_embs[
|
| 794 |
-
offset : offset + audio_len
|
| 795 |
-
]
|
| 796 |
-
offset += audio_len
|
| 797 |
|
| 798 |
elif self.training:
|
| 799 |
for i in range(bs):
|
|
@@ -853,10 +852,12 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 853 |
result_text = []
|
| 854 |
for result in result_ids:
|
| 855 |
result = result[result != 0]
|
| 856 |
-
if result[0] == tokenizer.bos_id:
|
| 857 |
result = result[1:]
|
| 858 |
-
|
| 859 |
-
|
|
|
|
|
|
|
| 860 |
result_text.append(tokenizer.decode(result))
|
| 861 |
return result_text
|
| 862 |
|
|
@@ -1129,8 +1130,10 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 1129 |
input_images_list = []
|
| 1130 |
input_audios_list = []
|
| 1131 |
audio_parts_list = []
|
|
|
|
| 1132 |
|
| 1133 |
for image, msgs in zip(images_list, msgs_list):
|
|
|
|
| 1134 |
if isinstance(msgs, str):
|
| 1135 |
msgs = json.loads(msgs)
|
| 1136 |
copy_msgs = deepcopy(msgs)
|
|
@@ -1161,7 +1164,7 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 1161 |
audios.append(c)
|
| 1162 |
audio_parts.append(i)
|
| 1163 |
cur_msgs.append("<audio>./</audio>")
|
| 1164 |
-
|
| 1165 |
elif isinstance(c, str):
|
| 1166 |
cur_msgs.append(c)
|
| 1167 |
|
|
@@ -1175,13 +1178,18 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 1175 |
copy_msgs,
|
| 1176 |
tokenize=False,
|
| 1177 |
add_generation_prompt=False if teacher_forcing else True,
|
| 1178 |
-
use_tts_template=
|
| 1179 |
enable_thinking=enable_thinking,
|
| 1180 |
)
|
| 1181 |
)
|
| 1182 |
input_images_list.append(images)
|
| 1183 |
input_audios_list.append(audios)
|
| 1184 |
audio_parts_list.append(audio_parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1185 |
|
| 1186 |
if not merge_audio_from_same_content:
|
| 1187 |
audio_parts_list = None
|
|
@@ -1253,9 +1261,8 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 1253 |
|
| 1254 |
tts_bound = (tts_bos_idx, tts_eos_idx)
|
| 1255 |
|
| 1256 |
-
|
| 1257 |
-
|
| 1258 |
-
answer = answer.split("<|tts_eos|>")[0]
|
| 1259 |
|
| 1260 |
if use_tts_template and generate_audio and output_audio_path:
|
| 1261 |
import soundfile as sf
|
|
@@ -1284,7 +1291,7 @@ class MiniCPMO(MiniCPMOPreTrainedModel):
|
|
| 1284 |
traceback.print_exc()
|
| 1285 |
|
| 1286 |
if return_prompt:
|
| 1287 |
-
return answer, prompts_lists[0]
|
| 1288 |
else:
|
| 1289 |
return answer
|
| 1290 |
|
|
|
|
| 763 |
audio_embs = audio_embeddings[i]
|
| 764 |
bounds = audio_bounds[i]
|
| 765 |
|
| 766 |
+
one_to_one_match = len(audio_embs) == len(bounds) and all(
|
| 767 |
+
embs.shape[0] == int(bound[1] - bound[0])
|
| 768 |
+
for embs, bound in zip(audio_embs, bounds)
|
| 769 |
+
)
|
| 770 |
|
| 771 |
+
if one_to_one_match:
|
| 772 |
+
for embs, bound in zip(audio_embs, bounds):
|
| 773 |
+
input_embeddings[i, bound[0] : bound[1]] = embs.to(
|
| 774 |
+
device=input_embeddings.device,
|
| 775 |
+
dtype=input_embeddings.dtype,
|
| 776 |
+
)
|
| 777 |
+
else:
|
| 778 |
+
flat_audio_embs = torch.cat(audio_embs, dim=0).to(
|
| 779 |
device=input_embeddings.device,
|
| 780 |
dtype=input_embeddings.dtype,
|
| 781 |
)
|
| 782 |
+
|
| 783 |
+
total_bound_len = sum(int(bound[1] - bound[0]) for bound in bounds)
|
| 784 |
+
if flat_audio_embs.shape[0] != total_bound_len:
|
| 785 |
+
raise ValueError(
|
| 786 |
+
f"Audio total length mismatch: {flat_audio_embs.shape[0]} != {total_bound_len}"
|
| 787 |
+
)
|
| 788 |
+
|
| 789 |
+
offset = 0
|
| 790 |
+
for bound in bounds:
|
| 791 |
+
audio_len = int(bound[1] - bound[0])
|
| 792 |
+
input_embeddings[i, bound[0] : bound[1]] = flat_audio_embs[
|
| 793 |
+
offset : offset + audio_len
|
| 794 |
+
]
|
| 795 |
+
offset += audio_len
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 796 |
|
| 797 |
elif self.training:
|
| 798 |
for i in range(bs):
|
|
|
|
| 852 |
result_text = []
|
| 853 |
for result in result_ids:
|
| 854 |
result = result[result != 0]
|
| 855 |
+
if len(result) > 0 and result[0] == tokenizer.bos_id:
|
| 856 |
result = result[1:]
|
| 857 |
+
for idx, token_id in enumerate(result):
|
| 858 |
+
if token_id in terminators:
|
| 859 |
+
result = result[:idx]
|
| 860 |
+
break
|
| 861 |
result_text.append(tokenizer.decode(result))
|
| 862 |
return result_text
|
| 863 |
|
|
|
|
| 1130 |
input_images_list = []
|
| 1131 |
input_audios_list = []
|
| 1132 |
audio_parts_list = []
|
| 1133 |
+
use_tts_template_list = []
|
| 1134 |
|
| 1135 |
for image, msgs in zip(images_list, msgs_list):
|
| 1136 |
+
sample_use_tts_template = use_tts_template
|
| 1137 |
if isinstance(msgs, str):
|
| 1138 |
msgs = json.loads(msgs)
|
| 1139 |
copy_msgs = deepcopy(msgs)
|
|
|
|
| 1164 |
audios.append(c)
|
| 1165 |
audio_parts.append(i)
|
| 1166 |
cur_msgs.append("<audio>./</audio>")
|
| 1167 |
+
sample_use_tts_template = True
|
| 1168 |
elif isinstance(c, str):
|
| 1169 |
cur_msgs.append(c)
|
| 1170 |
|
|
|
|
| 1178 |
copy_msgs,
|
| 1179 |
tokenize=False,
|
| 1180 |
add_generation_prompt=False if teacher_forcing else True,
|
| 1181 |
+
use_tts_template=sample_use_tts_template,
|
| 1182 |
enable_thinking=enable_thinking,
|
| 1183 |
)
|
| 1184 |
)
|
| 1185 |
input_images_list.append(images)
|
| 1186 |
input_audios_list.append(audios)
|
| 1187 |
audio_parts_list.append(audio_parts)
|
| 1188 |
+
use_tts_template_list.append(sample_use_tts_template)
|
| 1189 |
+
|
| 1190 |
+
# Preserve the original downstream behavior for optional audio generation,
|
| 1191 |
+
# while keeping prompt template selection local to each batch sample.
|
| 1192 |
+
use_tts_template = any(use_tts_template_list)
|
| 1193 |
|
| 1194 |
if not merge_audio_from_same_content:
|
| 1195 |
audio_parts_list = None
|
|
|
|
| 1261 |
|
| 1262 |
tts_bound = (tts_bos_idx, tts_eos_idx)
|
| 1263 |
|
| 1264 |
+
answers = [answer.split("<|tts_eos|>")[0] if answer is not None else None for answer in res]
|
| 1265 |
+
answer = answers if batched else answers[0]
|
|
|
|
| 1266 |
|
| 1267 |
if use_tts_template and generate_audio and output_audio_path:
|
| 1268 |
import soundfile as sf
|
|
|
|
| 1291 |
traceback.print_exc()
|
| 1292 |
|
| 1293 |
if return_prompt:
|
| 1294 |
+
return answer, prompts_lists if batched else prompts_lists[0]
|
| 1295 |
else:
|
| 1296 |
return answer
|
| 1297 |
|
processing_minicpmo.py
CHANGED
|
@@ -1471,7 +1471,7 @@ class MiniCPMOProcessor(ProcessorMixin):
|
|
| 1471 |
audio_feature_lens = torch.hstack(audio_feature_lens)
|
| 1472 |
audio_feature_lens_list.append(audio_feature_lens)
|
| 1473 |
else:
|
| 1474 |
-
audio_feature_lens_list.append(
|
| 1475 |
|
| 1476 |
if audio_features_all:
|
| 1477 |
audio_features = [i.permute(1, 0) for i in audio_features_all]
|
|
|
|
| 1471 |
audio_feature_lens = torch.hstack(audio_feature_lens)
|
| 1472 |
audio_feature_lens_list.append(audio_feature_lens)
|
| 1473 |
else:
|
| 1474 |
+
audio_feature_lens_list.append(torch.empty(0, dtype=torch.long))
|
| 1475 |
|
| 1476 |
if audio_features_all:
|
| 1477 |
audio_features = [i.permute(1, 0) for i in audio_features_all]
|