十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MiniCPM-o 4.5 如何用视频帧与音频段交替输入完成半双工 omni 模式对话?

MiniCPM-o 4.5 如何用视频帧与音频段交替输入完成半双工 omni 模式对话? MiniCPM-o 4.5 如何用视频帧与音频段交替输入完成半双工 omni 模式对话【免费下载链接】MiniCPM-VA Pocket-Sized MLLM for Ultra-Efficient Image and Video Understanding on Your Phone项目地址: https://gitcode.com/GitHub_Trending/mi/MiniCPM-V如果你想在本地 GPU 上让 MiniCPM-o 4.5 同时看视频画面、听视频里的声音并用文字加语音回答官方文档给出的做法是先把视频拆成一帧一帧的画面和一段一段的音频把两者按顺序交替拼成一个 omni 输入列表再以半双工Half-Duplexomni 模式送入模型。适用前提NVIDIA GPU、Python 3.10以及固定版本transformers4.51.0文档明确提示其他版本可能存在兼容性问题。MiniCPM-o 4.5 的端到端全双工架构模态编码器/解码器与 LLM 通过 hidden states 直连输入输出流按毫秒级时间片同步。半双工 omni 模式就是在这套架构上以整段视频进、整段回复出的方式工作。准备环境安装固定版本的依赖文档要求transformers4.51.0因为其他版本可能存在兼容性问题文档标注仍在排查中。要生成语音输出TTS或做流式推理需要装带[all]扩展的minicpmo-utils# 不带 TTS 或流式推理 pip install transformers4.51.0 accelerate torch2.3.0,2.8.0 torchaudio2.8.0 minicpmo-utils1.0.5 # 带 TTS 或流式推理 pip install transformers4.51.0 accelerate torch2.3.0,2.8.0 torchaudio2.8.0 minicpmo-utils[all]1.0.5可选只有在你调用get_video_frame_audio_segments(..., use_ffmpegTrue)或需要generate_duplex_video生成输出视频时才需要 FFmpeg。安装方式按平台选一种然后跑ffmpeg -version确认能打印版本号# macOS (Homebrew) brew install ffmpeg # Ubuntu/Debian sudo apt update sudo apt install ffmpeg加载模型并初始化 TTS文档中的初始化代码如下其中init_visionTrue, init_audioTrue, init_ttsTrue是 omni 模式的默认值如果只做视觉或只做音频可分别把init_audio/init_tts或init_vision置为Falseimport torch from transformers import AutoModel model AutoModel.from_pretrained( openbmb/MiniCPM-o-4_5, trust_remote_codeTrue, attn_implementationsdpa, # sdpa 或 flash_attention_2 torch_dtypetorch.bfloat16, init_visionTrue, init_audioTrue, init_ttsTrue, ) model.eval().cuda() # 初始化 TTS 以输出音频 model.init_tts()注意加载后会调用.cuda()这一步要求有可用的 NVIDIA GPU文档给出的模型显存参考是 19 GBgguf 版 10 GB、AWQ 版 11 GB。把视频拆成交替的视频帧与音频段get_video_frame_audio_segments来自minicpmo.utils它返回三元组video_frames视频帧列表、audio_segments音频段列表即 16 kHz 波形、stacked_frames堆叠帧仅当stack_frames大于 1 时非空。交替输入就是按第 i 帧 → 第 i 段音频 →若有第 i 个堆叠帧的顺序把它们追加进同一个 content 列表from minicpmo.utils import get_video_frame_audio_segments video_path assets/Skiing.mp4 # 替换为你的视频文件路径 video_frames, audio_segments, stacked_frames get_video_frame_audio_segments(video_path, stack_frames1) omni_contents [] for i in range(len(video_frames)): omni_contents.append(video_frames[i]) omni_contents.append(audio_segments[i]) if stacked_frames is not None and stacked_frames[i] is not None: omni_contents.append(stacked_frames[i])stack_frames1是默认演示值文档注明高刷新率模式HD mode用stack_frames5此时stacked_frames才有内容并参与交替。视频帧/音频段的拆分节奏由这个函数内部决定文档未展开其参数含义。路径一chat 推理一次完成整个视频对话适合拿到一段完整视频、希望一次性得到文字回答和 TTS 音频的场景。先选一个参考音频做音色克隆可选再调用model.chat其中omni_modeTrue是 omni 推理的必要参数generate_audioTrue并给出output_audio_path才会落盘语音# 可选设置参考音频用于音色克隆 ref_audio_path assets/HT_ref_audio.wav # 替换为你的参考音频路径 sys_msg model.get_sys_prompt(ref_audioref_audio_path, modeomni, languageen) msg {role: user, content: omni_contents} msgs [sys_msg, msg] generate_audio True output_audio_path output.wav res model.chat( msgsmsgs, max_new_tokens4096, do_sampleTrue, temperature0.7, use_tts_templateTrue, enable_thinkingFalse, omni_modeTrue, # omni 推理必须开启 generate_audiogenerate_audio, output_audio_pathoutput_audio_path, max_slice_nums1, # HD 模式下调大 ) print(res)文档给出的示例输出是The person in the picture is skiing down a snowy mountain slope.对应示例视频assets/Skiing.mp4。这只是文档示例你换成自己的视频会得到不同回答。语音结果写在output.wav文档建议用下面的方式播放核对# import IPython # IPython.display.Audio(output.wav)验证方式print(res)打印出对视频内容的文字描述且output.wav被写出并可播放说明这次 omni 对话成功。路径二流式推理按 chunk 喂入边喂边生成流式路径的输入序列构造方式与 chat 路径完全相同同一份交替的omni_contents区别在于喂入和生成被拆开先reset_session()清掉上一轮的 KV cache再逐条streaming_prefill最后统一streaming_generate。import librosa import numpy as np import soundfile as sf import torch from minicpmo.utils import get_video_frame_audio_segments model ... # 使用前面加载模型一节初始化好的 model model.init_tts() # 开始新对话清空 KV cache model.reset_session() # 可选加载参考音频用于音色克隆 ref_audio_path assets/HT_ref_audio.wav # 替换为你的参考音频路径 ref_audio, _ librosa.load(ref_audio_path, sr16000, monoTrue) model.init_token2wav_cache(ref_audio) session_id demo video_path assets/Skiing.mp4 # 替换为你的视频文件路径 video_frames, audio_segments, stacked_frames get_video_frame_audio_segments(video_path, stack_frames1) omni_contents [] for i in range(len(video_frames)): omni_contents.append(video_frames[i]) omni_contents.append(audio_segments[i]) if stacked_frames is not None and stacked_frames[i] is not None: omni_contents.append(stacked_frames[i]) generate_audio False output_audio_path output.wav # Step 1: prefill 系统提示 sys_msg model.get_sys_prompt(ref_audioref_audio, modeomni, languageen) model.streaming_prefill(session_idsession_id, msgs[sys_msg]) # Step 2: 逐条 prefill omni chunk只有最后一个音频chunk 传 is_last_chunkTrue audio_indices [i for i, c in enumerate(omni_contents) if isinstance(c, np.ndarray)] last_audio_idx audio_indices[-1] if audio_indices else -1 for idx, content in enumerate(omni_contents): is_last_audio_chunk idx last_audio_idx msgs [{role: user, content: [content]}] model.streaming_prefill(session_idsession_id, msgsmsgs, omni_modeTrue, is_last_chunkis_last_audio_chunk) # Step 3: 生成回复 iter_gen model.streaming_generate( session_idsession_id, generate_audiogenerate_audio, use_tts_templateTrue, enable_thinkingFalse, do_sampleTrue, ) audios [] text if generate_audio: for wav_chunk, text_chunk in iter_gen: audios.append(wav_chunk) text text_chunk generated_waveform torch.cat(audios, dim-1)[0] sf.write(output_audio_path, generated_waveform.cpu().numpy(), samplerate24000) print(Text:, text) print(Audio saved to output.wav) else: for text_chunk, is_finished in iter_gen: text text_chunk print(Text:, text)几个直接影响能否跑通的条件文档里都有明确标注is_last_chunkTrue只应在最后一个音频 chunk 上出现。上面用isinstance(c, np.ndarray)筛出音频段音频波形是 numpy 数组取其下标作为最后一段音频的位置。generate_audio为True时迭代器产出(wav_chunk, text_chunk)二元组最终音频按24000 Hz采样率写盘为False时产出(text_chunk, is_finished)。输入音频统一按sr16000, monoTrue加载输出音频固定 24000 Hz这两个数值在文档中是固定值。同一session_id上可以继续 prefill 后续用户轮次并生成下一轮回复文档在此注明Now we can prefill the following user turns and generate next turn response半双工对话即由此逐轮推进。验证方式与 chat 路径一致终端打印 Text: ...以及开启音频时的 Audio saved to output.wav并核对output.wav内容。与全双工模式的关系和边界半双工 omni 模式本文两条路径与model.as_duplex()转出的全双工模式是同一模型的两套接口全双工用于实时/录像视频通话式逐 chunk 的streaming_prefillstreaming_generate交互需要ref_audio、prompt_wav_path和get_video_frame_audio_segments(use_ffmpegTrue)如果后续要从半双工切到全双工文档给出的转换方式是在半双工模型上调as_duplex()也可以随时用as_simplex(reset_sessionTrue)转回半双工。需要留意的限制依赖版本固定transformers4.51.0其他版本存在兼容性问题文档标注 under investigation不要随意升级。需要 NVIDIA GPU代码中model.eval().cuda()且torch_dtypetorch.bfloat16模型本身显存参考 19 GB。文档中的assets/Skiing.mp4、assets/HT_ref_audio.wav是官方示例路径本仓库assets/目录下并不包含这些文件需要替换为你自己的视频和参考音频。半双工语音实时通话在 llama.cpp-omni 侧标注为 under development本文路径只覆盖 PyTorch NVIDIA GPU 的 Transformers 用法。更多模式说明与案例可参考仓库 README 中 Half-Duplex Omni Mode 一节、API 指南以及 MiniCPM-o 4.5 技术报告。【免费下载链接】MiniCPM-VA Pocket-Sized MLLM for Ultra-Efficient Image and Video Understanding on Your Phone项目地址: https://gitcode.com/GitHub_Trending/mi/MiniCPM-V创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表