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
Fix audio placeholder length mismatch for merged audio inputs
#19
by cherry77-cloud - opened
- processing_minicpmo.py +49 -20
processing_minicpmo.py
CHANGED
|
@@ -1039,16 +1039,16 @@ class MiniCPMOProcessor(ProcessorMixin):
|
|
| 1039 |
Returns:
|
| 1040 |
Audio placeholder string
|
| 1041 |
"""
|
| 1042 |
-
pool_step = self.pool_step
|
| 1043 |
feature_lens = math.ceil(audio_lens / self.audio_processor.hop_length)
|
| 1044 |
-
|
| 1045 |
feature_lens = (feature_lens - 1) // 2 + 1
|
| 1046 |
-
output_lens = (feature_lens - pool_step) // pool_step + 1
|
|
|
|
| 1047 |
|
|
|
|
| 1048 |
if chunk_input:
|
| 1049 |
fbank_feat_in_chunk = int(chunk_length * 100)
|
| 1050 |
cnn_feat_in_chunk = (fbank_feat_in_chunk - 1) // 2 + 1
|
| 1051 |
-
audio_embeds_in_chunk = (cnn_feat_in_chunk - pool_step) // pool_step + 1
|
| 1052 |
num_audio_chunks = (output_lens + audio_embeds_in_chunk - 1) // audio_embeds_in_chunk
|
| 1053 |
|
| 1054 |
place_holders = ""
|
|
@@ -1063,6 +1063,27 @@ class MiniCPMOProcessor(ProcessorMixin):
|
|
| 1063 |
|
| 1064 |
return audio_placeholder
|
| 1065 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1066 |
def _init_streaming_processor(
|
| 1067 |
self,
|
| 1068 |
chunk_ms: int = 100,
|
|
@@ -1382,7 +1403,7 @@ class MiniCPMOProcessor(ProcessorMixin):
|
|
| 1382 |
|
| 1383 |
if isinstance(audios, np.ndarray):
|
| 1384 |
audios_list = [[audios]]
|
| 1385 |
-
elif isinstance(audios[0], np.ndarray):
|
| 1386 |
audios_list = [audios]
|
| 1387 |
else:
|
| 1388 |
audios_list = audios
|
|
@@ -1393,37 +1414,45 @@ class MiniCPMOProcessor(ProcessorMixin):
|
|
| 1393 |
assert len(parts) == len(audios)
|
| 1394 |
|
| 1395 |
audio_feature_lens_list = []
|
| 1396 |
-
audio_ph_list = []
|
| 1397 |
audio_features_all = []
|
| 1398 |
|
| 1399 |
-
# audio placeholder not dependent on audio_parts
|
| 1400 |
-
for audios in audios_list:
|
| 1401 |
-
if audios:
|
| 1402 |
-
audio_ph_list.append(
|
| 1403 |
-
[
|
| 1404 |
-
self.get_audio_placeholder(len(a), chunk_input=stream_input, chunk_length=chunk_length)
|
| 1405 |
-
for a in audios
|
| 1406 |
-
]
|
| 1407 |
-
)
|
| 1408 |
-
else:
|
| 1409 |
-
audio_ph_list.append([])
|
| 1410 |
-
|
| 1411 |
for idx, audios in enumerate(audios_list):
|
| 1412 |
if audio_parts is not None:
|
| 1413 |
-
# same audio part merge
|
| 1414 |
audio_part = audio_parts[idx]
|
| 1415 |
merge_audio = []
|
| 1416 |
cur_audio = []
|
|
|
|
| 1417 |
for aid, (part, audio) in enumerate(zip(audio_part, audios)):
|
| 1418 |
if aid == 0 or audio_part[aid] == audio_part[aid - 1]:
|
| 1419 |
cur_audio.append(audio)
|
| 1420 |
else:
|
| 1421 |
merge_audio.append(np.hstack(cur_audio))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1422 |
cur_audio = [audio]
|
| 1423 |
if cur_audio:
|
| 1424 |
merge_audio.append(np.hstack(cur_audio))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1425 |
else:
|
| 1426 |
merge_audio = audios
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1427 |
|
| 1428 |
# If the audio exceeds 30 seconds, split it into chunks every 30 seconds.
|
| 1429 |
final_merge_audio = []
|
|
@@ -1471,7 +1500,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]
|
|
|
|
| 1039 |
Returns:
|
| 1040 |
Audio placeholder string
|
| 1041 |
"""
|
|
|
|
| 1042 |
feature_lens = math.ceil(audio_lens / self.audio_processor.hop_length)
|
|
|
|
| 1043 |
feature_lens = (feature_lens - 1) // 2 + 1
|
| 1044 |
+
output_lens = (feature_lens - self.pool_step) // self.pool_step + 1
|
| 1045 |
+
return self._get_audio_placeholder_by_output_lens(output_lens, chunk_input, chunk_length)
|
| 1046 |
|
| 1047 |
+
def _get_audio_placeholder_by_output_lens(self, output_lens: int, chunk_input: bool = True, chunk_length: int = 1):
|
| 1048 |
if chunk_input:
|
| 1049 |
fbank_feat_in_chunk = int(chunk_length * 100)
|
| 1050 |
cnn_feat_in_chunk = (fbank_feat_in_chunk - 1) // 2 + 1
|
| 1051 |
+
audio_embeds_in_chunk = (cnn_feat_in_chunk - self.pool_step) // self.pool_step + 1
|
| 1052 |
num_audio_chunks = (output_lens + audio_embeds_in_chunk - 1) // audio_embeds_in_chunk
|
| 1053 |
|
| 1054 |
place_holders = ""
|
|
|
|
| 1063 |
|
| 1064 |
return audio_placeholder
|
| 1065 |
|
| 1066 |
+
def _get_merged_audio_placeholders(self, audios, chunk_input: bool = True, chunk_length: int = 1):
|
| 1067 |
+
audio_placeholders = []
|
| 1068 |
+
prev_output_lens = 0
|
| 1069 |
+
total_audio_lens = 0
|
| 1070 |
+
for audio in audios:
|
| 1071 |
+
total_audio_lens += len(audio)
|
| 1072 |
+
output_lens = self.get_audio_placeholder(
|
| 1073 |
+
total_audio_lens,
|
| 1074 |
+
chunk_input=chunk_input,
|
| 1075 |
+
chunk_length=chunk_length,
|
| 1076 |
+
).count("<unk>")
|
| 1077 |
+
audio_placeholders.append(
|
| 1078 |
+
self._get_audio_placeholder_by_output_lens(
|
| 1079 |
+
output_lens - prev_output_lens,
|
| 1080 |
+
chunk_input=chunk_input,
|
| 1081 |
+
chunk_length=chunk_length,
|
| 1082 |
+
)
|
| 1083 |
+
)
|
| 1084 |
+
prev_output_lens = output_lens
|
| 1085 |
+
return audio_placeholders
|
| 1086 |
+
|
| 1087 |
def _init_streaming_processor(
|
| 1088 |
self,
|
| 1089 |
chunk_ms: int = 100,
|
|
|
|
| 1403 |
|
| 1404 |
if isinstance(audios, np.ndarray):
|
| 1405 |
audios_list = [[audios]]
|
| 1406 |
+
elif len(audios) > 0 and isinstance(audios[0], np.ndarray):
|
| 1407 |
audios_list = [audios]
|
| 1408 |
else:
|
| 1409 |
audios_list = audios
|
|
|
|
| 1414 |
assert len(parts) == len(audios)
|
| 1415 |
|
| 1416 |
audio_feature_lens_list = []
|
| 1417 |
+
audio_ph_list = [[] for _ in audios_list]
|
| 1418 |
audio_features_all = []
|
| 1419 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1420 |
for idx, audios in enumerate(audios_list):
|
| 1421 |
if audio_parts is not None:
|
|
|
|
| 1422 |
audio_part = audio_parts[idx]
|
| 1423 |
merge_audio = []
|
| 1424 |
cur_audio = []
|
| 1425 |
+
audio_phs = []
|
| 1426 |
for aid, (part, audio) in enumerate(zip(audio_part, audios)):
|
| 1427 |
if aid == 0 or audio_part[aid] == audio_part[aid - 1]:
|
| 1428 |
cur_audio.append(audio)
|
| 1429 |
else:
|
| 1430 |
merge_audio.append(np.hstack(cur_audio))
|
| 1431 |
+
audio_phs.extend(
|
| 1432 |
+
self._get_merged_audio_placeholders(
|
| 1433 |
+
cur_audio,
|
| 1434 |
+
chunk_input=stream_input,
|
| 1435 |
+
chunk_length=chunk_length,
|
| 1436 |
+
)
|
| 1437 |
+
)
|
| 1438 |
cur_audio = [audio]
|
| 1439 |
if cur_audio:
|
| 1440 |
merge_audio.append(np.hstack(cur_audio))
|
| 1441 |
+
audio_phs.extend(
|
| 1442 |
+
self._get_merged_audio_placeholders(
|
| 1443 |
+
cur_audio,
|
| 1444 |
+
chunk_input=stream_input,
|
| 1445 |
+
chunk_length=chunk_length,
|
| 1446 |
+
)
|
| 1447 |
+
)
|
| 1448 |
else:
|
| 1449 |
merge_audio = audios
|
| 1450 |
+
audio_phs = [
|
| 1451 |
+
self.get_audio_placeholder(len(a), chunk_input=stream_input, chunk_length=chunk_length)
|
| 1452 |
+
for a in audios
|
| 1453 |
+
]
|
| 1454 |
+
|
| 1455 |
+
audio_ph_list[idx] = audio_phs
|
| 1456 |
|
| 1457 |
# If the audio exceeds 30 seconds, split it into chunks every 30 seconds.
|
| 1458 |
final_merge_audio = []
|
|
|
|
| 1500 |
audio_feature_lens = torch.hstack(audio_feature_lens)
|
| 1501 |
audio_feature_lens_list.append(audio_feature_lens)
|
| 1502 |
else:
|
| 1503 |
+
audio_feature_lens_list.append(torch.tensor([], dtype=torch.long))
|
| 1504 |
|
| 1505 |
if audio_features_all:
|
| 1506 |
audio_features = [i.permute(1, 0) for i in audio_features_all]
|