MiniCPM-o 4.5 是 MiniCPM-o 系列最新、性能最强的多模态大模型,模型规模约 9B参数。它采用端到端的多模态架构,将视觉、语音等模态的编码器/解码器与大语言模型紧密结合,从而支持图像、视频、文本和音频输入,并生成高质量的文本和语音输出。MiniCPM-o 4.5 基于 SigLip2、Whisper-medium、CosyVoice2 和 Qwen3-8B 等模型构建,融合了多模态感知与生成能力,在同等参数量下性能卓越。
功能亮点: MiniCPM-o 4.5 带来了多项突破性的新特性:
- 领先的视觉理解力:在 OpenCompass 基准(涵盖8个主流视觉任务)上取得平均 77.6 分,超越了 GPT-4o、Gemini 2.0 Pro 等常用闭源模型,并逼近 Gemini 2.5 Flash。仅凭 9B 参数便实现了出色的图像/视频理解和问答能力,在效率和性能之间取得了良好平衡。模型支持 指令模式 和 思考模式(Instruct/Thinking)两种推理形式,以适配不同场景下对响应速度和推理精度的需求。
- 强大的语音对话能力: 支持中英双语的实时语音对话,语音输出更加自然、富有表现力且稳定。MiniCPM-o 4.5 内置了高质量的文本转语音 (TTS) 模块,可在零样本条件下合成语音;同时提供语音克隆功能,只需几秒钟参考音频即可模拟特定声音,实现定制音色的语音回答和角色扮演,其音色还原度超越了一些专用 TTS 工具(如 CosyVoice2)。
- 全新的全双工(Full-Duplex)流式交互: 相较以往“对讲机”式的单工交互,MiniCPM-o 4.5 原生支持全双工多模态实时流功能。这意味着模型可以在生成输出的同时,持续接收实时的视频和音频输入,不再局限于“一问一答”的回合制交互。它能够做到“边看、边听、主动说”:例如一边口述回答用户的问题,一边不间断“观看”摄像头视频画面和“倾听”环境声音,从而不遗漏任何关键信息。得益于全双工和主动交互机制,模型可以自主监控输入流并智能决策何时发言,以最恰当的时机做出提醒或评论,实现更加流畅自然的人机对话体验。
- 卓越的 OCR 与多语言能力: MiniCPM-o 4.5 支持高分辨率图像(可达 180 万像素)和高帧率视频(最高 10FPS)的高效处理。在文档解析任务上表现出色——在 OmniDocBench 基准上达到当前最优水平,超越了包括 Gemini-3 Flash、GPT-5 在内的先进专有模型,以及专业的OCR 工具 DeepSeek-OCR 2。此外,在多模态安全和真实性测试(如 MMHal-Bench)中表现可靠,与 Gemini 2.5 Flash 相当;还支持超过 30 种语言的多语言理解与生成能力,能应对跨语言的多模态应用场景。
- 易用的部署与扩展:MiniCPM-o 4.5 支持本地部署和二次开发,更加方便开发者使用:
- 支持通过 llama.cpp 和 Ollama 在本地 CPU 上高效推理;
- 提供多达 16 种不同量化程度的 int4 和 GGUF 格式模型以适配各类设备;
- 支持利用 vLLM 和 SGLang 框架进行高吞吐、低内存占用的推理服务;
- 集成众智 FlagOS 异构芯片系统栈,实现一键部署到多种国产 AI 芯片平台;
- 提供 LLaMA-Factory 和MS-Swift微调工具,方便在新领域和新任务上对模型进行微调拓展;
- 提供在线 Demo 和 WebRTC 本地演示,用户可直接体验全双工多模态对话。
适用场景: 凭借上述强大功能,MiniCPM-o 4.5 可广泛应用于需要视听联动的智能助手场景。例如:实时视频会议助理(边看演示文稿边提供讲解或提醒)、智能驾驶辅助(通过摄像头画面和语音提示进行交互)、智能安防监控(模型持续观看监控视频并可语音报警)、教育陪伴机器人(看书识字与语音讲解同步进行)等。此外,它在文档分析(例如 PDF 表格解析、票据识别)和多语言翻译场景下也有出色表现。开发者还可利用语音克隆和角色扮演功能,为游戏 NPC 或虚拟形象赋予特定的声音和个性,使人机对话更具沉浸感。
模型效果:
安装和环境配置说明
要使用 MiniCPM-o 4.5,首先需要准备好相应的软件环境并安装必要依赖。官方推荐使用 Python 3.10 环境,且 Transformers 库版本需为 4.51.0 以确保兼容。下面是具体的安装步骤:
- Python 库安装: 使用 pip 安装 Transformers 和 MiniCPM-o 4.5 所需的其它依赖。对于不需要语音(TTS)或流式推理功能的场景,可仅安装基础依赖:
pip install "transformers==4.51.0" accelerate "torch>=2.3.0,<=2.8.0" "torchaudio<=2.8.0" "minicpmo-utils>=1.0.2"
如果需要使用文本转语音 (TTS) 或 实时流式推理功能,请安装带有 [all] 选项的完整版依赖:
pip install "transformers==4.51.0" accelerate "torch>=2.3.0,<=2.8.0" "torchaudio<=2.8.0" "minicpmo-utils[all]>=1.0.2"
上述命令将安装 PyTorch 及音频处理库 Torchaudio、加速推理的 Accelerate 工具,以及 MiniCPM-o 官方提供的 minicpmo-utils 工具包(包含多模态处理辅助函数等)。确保 Transformers 版本是 4.51.0,否则可能出现兼容性问题。
- FFmpeg 安装(可选): 若需处理视频文件,建议安装 FFmpeg 软件用于视频帧提取与音频处理。MiniCPM-o 4.5 的部分工具(如 get_video_frame_audio_segments 和 generate_duplex_video)会调用 FFmpeg 来解析视频帧和生成视频输出。在 macOS 系统上可通过 Homebrew 安装 FFmpeg:
brew install ffmpeg
在 Ubuntu/Debian 上可以用 APT 安装:
sudo apt update && sudo apt install ffmpeg
安装后可运行 ffmpeg -version 检查是否安装成功。
- 硬件和驱动: 建议使用支持 CUDA 的 NVIDIA GPU 来运行模型,以获得较佳的推理性能(9B 参数的模型在 CPU 上推理速度较慢)。请确保已安装相应的 GPU 驱动和 CUDA 工具包。如果没有可用 GPU,可考虑使用后文介绍的量化部署方案(如 llama.cpp、GGUF 等)在 CPU 或移动设备上运行模型。
完成上述步骤后,环境即配置就绪。接下来可以通过 Python 加载 MiniCPM-o 4.5 模型并开始使用。
模型加载与推理实战
配置好环境后,可以通过 Transformers 接口来加载 MiniCPM-o 4.5 模型。由于该模型在实现上使用了自定义组件(如多模态处理工具等),加载时需要设置 trust_remote_code=True 来允许从模型仓库加载自定义代码。以下是加载和初始化模型的示例代码:
import torch from modelscope import AutoModel # 加载 MiniCPM-o 4.5 模型(包含视觉、音频和语音合成功能) model = AutoModel.from_pretrained( "openbmb/MiniCPM-o-4_5", trust_remote_code=True, # 允许加载远程自定义代码 attn_implementation="sdpa", # 注意力实现,可选 "sdpa" 或"flash_attention_2" torch_dtype=torch.bfloat16, # 使用 bfloat16 数据类型节省显存 init_vision=True, # 初始化视觉模态模块 init_audio=True, # 初始化音频模态模块 init_tts=True # 初始化文本转语音模块 ) model.eval().cuda() # 切换到评估模式并将模型移至GPU
上述代码将下载并加载 MiniCPM-o 4.5 的模型权重,并初始化模型的各个模态子模块。其中:
- `init_vision=True`、`init_audio=True`、`init_tts=True` 表示加载包含视觉、听觉和语音合成能力的完整 Omni 模型。如果只需视觉-文本或语音-文本功能,也可以通过将对应参数设为 False 来跳过不需要的模块,以节省内存。例如 `init_tts=False` 将不加载 TTS 模块。
- `attn_implementation` 参数可选择注意力机制实现,`"sdpa"` 为 PyTorch 2.x 内置的Scaled Dot-Product Attention,`"flash_attention_2"` 则利用更高效的 Flash Attention v2 实现。可根据环境中 PyTorch 版本和GPU支持情况选择其中一种(两者在功能上等价)。
- `torch_dtype=torch.bfloat16` 指定模型权重加载为 bfloat16 精度,可显著减少显存占用,同时保持推理准确率。注意 bfloat16 支持需要硬件(如 Ampere架构及以上的N卡)和 PyTorch 版本支持。
模型加载完成后,调用 `model.eval().cuda()` 将模型切换为评估模式(关闭dropout等随机机制)并移动到GPU上,以备推理使用。
接下来,如果要启用语音合成功能,需要进行TTS 初始化。MiniCPM-o 4.5 自带 TTS 模块,但需要在使用前根据是否流式输出进行初始化:
# 初始化文本转语音 (TTS) 模块 model.init_tts(streaming=False) # 若要在流式交互中实时合成语音,可设 streaming=True
上面代码中的 `model.init_tts()` 用于加载 TTS 所需的声学模型、声码器等组件。`streaming=False` 表示将以非流式模式生成整段语音;如果为 `True`,则模型将以流式方式逐步生成语音(适用于全双工对话场景的边说边出声)。一般在对话之前调用一次该初始化函数即可。
至此,模型已经准备就绪。您可以使用 `model.chat()` 等接口与模型进行交互。在进行多模态推理或特殊模式使用前,我们还需要了解 MiniCPM-o 4.5 的单工与全双工模式及其切换方法。
模式说明:单工 (Simplex) 与全双工 (Duplex) 模式
MiniCPM-o 4.5 提供了两种主要的运行模式:单工模式(Simplex)和全双工模式(Duplex)。理解这两种模式的区别并正确切换,有助于在不同应用场景下充分发挥模型能力。
单工模式(Simplex): 单工模式下的模型交互类似于传统的问答式回合制。模型在回答时无法同步感知新的外部输入,即“说完再看、说完再听”。这种模式就像对讲机,一方讲话时另一方必须等待;应用在模型上,就是当模型生成输出时,它暂时停止处理新的图像或音频输入。在大多数常规的多模态任务中(如给定一张图像问答、语音转文字翻译等),单工模式已经足够,而且由于不需要并行处理输入输出,资源开销更低、实现也更简单。MiniCPM-o 4.5 默认以单工模式运行,以提供标准的多轮对话、问答等功能。
全双工模式(Duplex): 全双工模式是 MiniCPM-o 4.5 的一大创新特性。在该模式下,模型可以一边生成回复,一边持续接收和处理新的多模态输入。也就是说,视觉、音频等输入流不会因为模型正在说话(输出)而中断,模型始终“眼观六路、耳听八方”地感知外界。这使人机交互从传统的“对讲机”式升级为更接近人类自然沟通的 “即时自由对话”。例如,在全双工模式下,模型可以在用户的视频直播过程中实时理解画面内容并给予语音反馈,即使模型在说话,它的“眼睛”和“耳朵”仍在工作,不会漏掉直播画面的新变化或用户的追加提问。这种模式非常适合实时互动场景,如实时助理、智能监控等。同时,MiniCPM-o 4.5 的全双工模式还支持主动交互:模型可以不等待用户提问,主动基于连续感知到的环境变化做出提示或评论(例如在视频会议中适时提出提醒)。
模式切换方法: 您可以在代码中通过简单接口在单工和全双工模式之间切换。在加载模型后,调用 `model.as_duplex()` 可将当前模型实例转换为全双工模式;相反,调用 `model.as_simplex()` 则可切换回单工模式。示例:
# 将模型切换为全双工模式 duplex_model = model.as_duplex() # ... (在全双工模式下进行推理交互) # 如需切换回单工模式(可选择重置会话状态) simplex_model = duplex_model.as_simplex(reset_session=True)
调用 `as_duplex()` 后,模型内部会启用全双工机制,包括调整内部缓冲区、启用并行输入处理等。而 `as_simplex(reset_session=True)` 则将模型还原为普通的单工交互模式,并可选地通过参数 `reset_session=True` 清空对话历史和缓存(相当于重置模型状态,避免残留信息干扰后续问答)。请根据应用需求选择模式:对于非实时的多模态问答或逐轮交互,使用默认的单工模式即可;而需要连续流式交互或同步视听输出入的场景,则应切换到全双工模式。
注意:全双工模式在实现上更复杂,对系统资源的要求也更高。例如同时处理音频输入和语音合成输出会占用更多的CPU/GPU资源。请确保设备性能足以支撑实时处理,或适当降低输入数据的分辨率/帧率来满足实时性要求。
多模态输入处理流程(视频、音频、图像)
MiniCPM-o 4.5 能接收多种模态的输入,包括图像、视频帧、音频波形等。在与模型交互时,需要按照特定方式组织多模态数据,以便模型理解并处理。下面介绍常见模态输入的准备和处理流程。
(1)图像输入: 对于单张或多张图像,可直接使用 PIL 图像对象作为输入。MiniCPM-o 4.5 的 `chat` 方法支持将 PIL Image 放入消息内容列表中,模型会自动对其进行视觉特征提取。例如,以下代码将一张图像作为用户问题的一部分输入模型,并得到模型的描述回答:
from PIL import Image # 加载一张示例图像并准备问题 image = Image.open("assets/fossil.png").convert("RGB") question = "图中有什么?" # 将图像和文本一起作为 user 消息的 content 列表 msgs = [{"role": "user", "content": [image, question]}] # 调用 chat 接口获得模型回复 res = model.chat(msgs=msgs, use_tts_template=False, enable_thinking=False) print(res) # 输出例如:"这张图像中是一块化石。"
在上述 `msgs` 列表中,我们构造了一条用户消息,其 `content` 字段是一个列表,包含 PIL 图像对象和字符串(问题文本)两种元素。模型接收到这条消息时,会先处理图像获得视觉语义,再结合提问生成文字答案。注意:如果一次输入多张图像,也可以将多个 PIL Image 依次放入列表,再附加问题文本。例如 `content`: `[image1, image2, "请比较这两张图片有何不同"]`,模型将同时参考 image1 和 image2 来回答。
对于视觉输入,还有几点说明:
- 分片推理 (Slice): 默认情况下,模型会自动处理较大尺寸的图像或长文档(如 PDF 多页图片)输入,可通过参数 `max_slice_nums` 控制切片数量(默认为9)。若处理超高分辨率图像,可适当增大该值。对普通照片无需调整此参数【22†L1081-L1089】。
- 思考模式 (Thinking Mode): 上例中 `enable_thinking=False` 表示关闭“思考链”模式。若设为 True,模型将尝试在回答前给出一段推理过程描述(这一般用于调试或研究,不影响最终答案)。默认情况下我们保持 False 以直接得到精炼答案【22†L1081-L1089】。
(2)音频输入: 音频可作为 numpy 数组(波形数据)输入模型。MiniCPM-o 4.5 支持语音识别(ASR)、音频内容分析等任务。一般流程是使用 librosa 等库读取音频文件为 16kHz 采样率的单声道 waveform(numpy 数组),然后与提示文本一起传入模型。例如,让模型将音频转写成文字的示例:
import librosa # 读取音频文件并获取波形数据 audio_wave, _ = librosa.load("example.wav", sr=16000, mono=True) # 构造用户消息,请求模型将音频转文字 task_prompt = "请将这段音频内容转写为文本。\n" msgs = [{"role": "user", "content": [task_prompt, audio_wave]}] # 调用模型进行语音识别(并生成语音输出,这里演示文本输出即可) res = model.chat(msgs=msgs, use_tts_template=False, generate_audio=False) print(res) # 输出音频中的文字内容
上例中,content 列表包含了一个任务描述文本和一个音频波形数组。模型识别音频后,会返回其中的语音内容。MiniCPM-o 4.5 针对不同音频任务也提供了一些建议的提示词,例如:
- 中文语音识别或英文语音翻译(AST):提示词 “请仔细听这段音频,并将其内容逐字记录。” 或 "Please listen to the audio snippet carefully and transcribe the content.";
- 说话人属性分析:提示词如 “根据说话内容判断其性别、状态、大致年龄和健康情况。”;
- 音频内容总结:“请总结这段音频的主要内容。”;
- 声音场景标签:“用一个关键词概括这段音频的场景或内容。” 等。
通过调整提示词,模型可以完成语音转文字、声音分析、音频分类等多种任务。在使用前,同样需要确保调用过 model.init_tts() 以初始化音频处理和TTS模块。如果需要模型返回语音朗读结果,可以将 generate_audio 参数设为 True(并提供 output_audio_path 保存合成音频),但对于纯转写任务一般不启用语音输出。
(3)视频输入: 视频是一种时间序列数据,MiniCPM-o 4.5 支持对视频进行分析和描述。在单轮推理中,由于模型的输入长度有限,通常需要将视频拆解为若干帧和音频段再输入;在流式推理中则可以逐段 feeding。下面介绍非实时情况下处理视频的流程:
首先,利用 minicpmo-utils 提供的辅助数 get_video_frame_audio_segments 从视频文件中提取画面帧和音频片段。例如:
from minicpmo.utils import get_video_frame_audio_segments video_path = "assets/Skiing.mp4" # 提取视频帧和对应的音频段,stack_frames=1 表示不额外堆叠帧 video_frames, audio_segments, _ = get_video_frame_audio_segments(video_path, stack_frames=1) print(f"视频帧数: {len(video_frames)}, 音频片段数: {len(audio_segments)}")
get_video_frame_audio_segments 会将整个视频按时间顺序切成一系列片段:每个片段含一个视频帧 (video_frames[i] 为 PIL 图像) 和对应的音频数据 (audio_segments[i] 为 numpy waveform)。参数 stack_frames 可用于帧堆叠以提升效果,如 stack_frames=5 将额外在每帧后加入4帧“邻居”帧(提高视觉连续性)。简单起见这里设为1。
接着,我们将这些帧和音频组合打包成一次性的输入内容,并附上一个对视频的提问:
question = "请描述这个视频的内容。"# 将所有帧和音频片段交替加入列表,并在末尾附加问题文本omni_contents = []for i in range(len(video_frames)): omni_contents.append(video_frames[i]) omni_contents.append(audio_segments[i])# 最后再加入问题omni_contents.append(question) msgs = [{"role": "user", "content": omni_contents}] # 调用 chat 接口,启用 omni_mode 以处理多模态序列 res = model.chat(msgs=msgs, omni_mode=True, max_new_tokens=512, use_tts_template=False, enable_thinking=False) print(res) # 模型将输出对视频的文字描述
在上述构造的 omni_contents 列表中,我们按时间顺序加入了视频帧和音频,使模型依次“看到”和“听到”视频发生的场景,最后附加一个要求描述视频的问题。关键是调用 model.chat 时需指定 omni_mode=True,告知模型按 Omni 模式 来处理交织的多模态输入。模型将产出对整个视频的综合描述。例如,对滑雪视频可能回答:“视频中一个人在雪山上滑雪,从山顶快速滑下,周围是白雪皑皑的山景……” 等。
需要注意的是,这种将整段视频一次性输入的方式适用于较短的视频(或仅取关键帧)。对于较长的视频或实时视频流,推荐使用流式推理(见下一节示例),即循环读取视频流,每次处理一个新片段,这样可以边生成边接收新内容,更接近全双工实时体验。
(4)结构化输入格式: 除了直接传入 Python 对象,MiniCPM-o 4.5 也支持类似 OpenAI API 的结构化消息格式来指定多模态输入。例如,可以使用如下字典形式:
msgs = [ { "role": "user", "content": [ {"type": "image_url", "image_url": {"url": "/path/to/image.jpg"}}, {"type": "audio_url", "audio_url": {"url": "/path/to/audio.wav"}}, {"type": "video_url", "video_url": {"url": "/path/to/video.mp4", "use_audio": True}}, {"type": "text", "text": "请描述上述内容。"} ] } ]
这种格式中每个元素通过 `"type"` 字段指明了数据类型及路径,支持本地文件路径或 http(s) URL。模型接收到这种结构化内容时,会自动获取相应资源进行处理。这种方式对于通过 API 或网络接口调用模型时很有用。本手册主要聚焦 Python 本地使用,因此一般直接传入对象即可,必要时也可以混合使用原生对象和结构化字典格式于同一消息中【19†L1199-L1204】。
综上,MiniCPM-o 4.5 在多模态输入方面非常灵活。开发者应根据任务需要,预处理好各模态的数据格式,并合理组织输入列表,使模型准确获取各部分信息。在下一节中,我们将进一步探讨语音生成方面的高级用法,包括语音克隆和角色扮演。
语音克隆与角色扮演使用示例
语音克隆是 MiniCPM-o 4.5 的一项令人瞩目的功能。通过提供一小段参考音频,模型能够模仿其中的说话人声音来生成回答。这使得开发者可以定制模型的说话风格,甚至让模型扮演特定角色,产生更加生动的交互体验。
(1)语音克隆(Voice Cloning)
要让模型学某个人的声音,只需准备几秒长的参考语音音频片段,然后在对话开始时提供给模型作为系统信息。MiniCPM-o 4.5 利用其可配置的语音建模设计,允许通过系统提示的参考音频实现音色克隆。具体步骤如下:
读取参考音频并提取波形数据(确保采样率 16kHz 单声道)。例如,有一段人物说话音频 `ref_voice.wav`:
import librosa ref_audio_path = "ref_voice.wav" ref_audio, _ = librosa.load(ref_audio_path, sr=16000, mono=True
构造系统消息,将参考音频嵌入其中,并附加说明让模型使用该音色回答。例如,我们希望模型模仿此音色帮助用户,并回答时尽量简洁:
sys_msg = { "role": "system", "content": [ "模仿音频样本的音色并生成新的内容。", ref_audio, "请用这种声音风格来为用户提供帮助。直接作答,不要有冗余内容" ] }
上述 `sys_msg` 的 `content` 列表中,首先是一句话提示(指导模型模仿音色),接着是音频波形对象 `ref_audio`,然后是进一步的指示(让模型用该声音风格直接回答用户)。这些文本提示并非必需,但有助于明确告诉模型我们期望它做声音克隆并保持回答简洁。
- 在对话开始时,将此系统消息发送给模型,后续用户提问时模型就会使用参考音色来说话。例如:
user_msg = {"role": "user", "content": "你好,请自我介绍一下。"} msgs = [sys_msg, user_msg] res = model.chat(msgs=msgs, generate_audio=True,output_audio_path="answer.wav")
设置 `generate_audio=True` 后,模型不仅会返回文本答案,还会在 `answer.wav` 文件中输出合成的语音(音色应接近参考音色)。这样,我们就获得了模型用目标声音说出的介绍。
(2)角色扮演(Role-Play)
在语音克隆的基础上,MiniCPM-o 4.5 还支持更进一步的“角色扮演”——即赋予模型特定的人物身份和性格设定。实现方法是在系统消息中同时提供参考音频和人物角色的文字描述。模型会模仿该音色并按照描述扮演角色,说话风格和内容都会贴合设定。
例如,假设我们想让模型扮演科幻小说中的一个 AI 助手角色“艾米”,声音上模仿提供的参考音频,性格上要求温柔、理性并富有诗意。我们可以这样构造系统消息:
sys_msg = { "role": "system", "content": [ "根据输入的音频提示生成相似的语音。", ref_audio, # 上面加载的参考音频 "你将以这个声音风格与用户对话。你的角色是一位心理咨询师兼播客主持人,喜爱创作和深度交流。你性格细腻富有共情,善于从个人经历中提炼哲理,语言风格理性且富有诗意。" ] }
这里,content 列表中第三项是一段较长的中文文字,对角色的身份和语言风格进行了描述。我们尽量详细地描绘了角色背景和说话特点。这样模型在回答时,不仅会用参考音色说话,还会模仿这种人格特质,用词和语气都更符合角色设定。例如,它可能用比较温暖关怀的语调回答用户的问题,遣词造句上也更富有人文色彩。
之后,和前面一样,将 sys_msg 放入对话列表开头,然后添加用户消息进行对话即可。模型将“带入角色”进行语音和文本回答,让用户仿佛在和那个角色对话。
(3)示例:中文语音克隆朗读
以下是一个完整的语音克隆示例,模型模仿参考音色用中文朗读指定文字:
# 初始化模型和TTS模块model = AutoModel.from_pretrained(..., trust_remote_code=True, ...)model.eval().cuda()model.init_tts(streaming=False) # 准备参考音频和系统消息 ref_audio, _ = librosa.load("参考声音.wav", sr=16000, mono=True) sys_msg = {"role": "system", "content": [ "模仿音频样本的音色并生成新的内容。", ref_audio, "请用这种声音风格来为用户提供帮助。直接作答,不要有冗余内容" ]} # 准备用户消息,让模型朗读一段文字 user_text = "你好,欢迎来到我们的AI语音演示。这个声音听起来像不像真人呢?" user_msg = {"role": "user", "content": ["请朗读以下内容:", user_text]} # 发送对话并获取语音输出 res = model.chat(msgs=[sys_msg, user_msg], do_sample=True, generate_audio=True, use_tts_template=True, output_audio_path="result.wav")
在上例中,系统消息要求模型模仿参考音频的音色,用户消息让模型朗读提供的文字。use_tts_template=True 参数可以让模型以朗读的风格输出语音(即忠实读出用户提供的文本)。最终生成的 result.wav 应该在音色上接近参考声音,并读出了给定的文字内容。
提示: 实际测试中,选择清晰、干净的参考音频能获得更好的克隆效果。参考语音时长不需要太长,几秒钟即可,但尽量包含目标说话人典型的声音特点。MiniCPM-o 4.5 在这方面已经相当强大,只需很短的提示就能逼真复现音色。此外,通过不同组合的系统提示,模型还能实现更多趣味应用,例如中英混合的角色扮演、模仿知名人物口吻(只要提供其音频片段和对应风格描述)等。
全双工视频实时交互的完整用例
本节我们以一个全双工视频实时交互的示例,演示如何让 MiniCPM-o 4.5 一边“看”视频一边“对话”。假设我们有一段实时摄像头视频流以及环境麦克风音频输入,模型需要边观看边聆听,同时用语音与用户交流。我们将模拟这种场景,对一段预先录制的视频执行流式推理,实现近似实时的对话。
步骤概述:
1. 加载模型并切换全双工模式。
2. 准备输入源: 打开视频文件,提取逐帧图像和对应音频片段。
3. 初始化对话会话: 提供系统提示(可含参考音色)开启对话。
4. 逐块流式推理: 循环读取视频的每一时间片,将新帧和音频送入模型,并获取模型的连续输出(文本和语音)。
5. 输出结果: 将模型的语音回复与原视频合成,生成带 AI 解说的交互视频。
下面是相应的代码示例:
import torch, librosafrom minicpmo.utils import generate_duplex_video, get_video_frame_audio_segmentsfrom transformers import AutoModel # 1. 加载模型并切换至全双工模式 model = AutoModel.from_pretrained("openbmb/MiniCPM-o_4.5", trust_remote_code=True, attn_implementation="sdpa", torch_dtype=torch.bfloat16) model.eval().cuda() model = model.as_duplex() # 转为全双工模式 # 2. 准备视频和参考音频 video_path = "example_video.mp4" ref_audio_path = "voice_sample.wav" # 可选的参考音色 ref_audio, _ = librosa.load(ref_audio_path, sr=16000, mono=True) # 提取视频帧和音频片段(调整 use_ffmpeg=True 以确保使用FFmpeg精确同步提取) video_frames, audio_segments, stacked_frames = get_video_frame_audio_segments( video_path, stack_frames=1, use_ffmpeg=True, adjust_audio_length=True ) # 3. 初始化全双工会话上下文:设置系统提示和参考音色 model.prepare( prefix_system_prompt="Streaming Omni Conversation.", # 系统前置提示语(可加入指导) ref_audio=ref_audio, # 应用参考音色 prompt_wav_path=ref_audio_path # 提供音频文件路径给模型内部使用 ) results_log = [] # 日志,用于记录每个时间片模型输出的信息 timed_output_audio = [] # 存储每个时间片生成的语音音频 # 4. 逐块执行流式推理 for idx in range(len(audio_segments)): audio_chunk = audio_segments[idx] if idx < len(audio_segments) else None frame = video_frames[idx] if idx < len(video_frames) else None frame_list = [] if frame is not None: frame_list.append(frame) # 如果有堆叠帧(如高刷新模式),也加入 if stacked_frames is not None and idx < len(stacked_frames) and stacked_frames[idx] is not None: frame_list.append(stacked_frames[idx]) # Step A: 预填充 (prefill) —— 提供当前帧和音频片段 model.streaming_prefill( audio_waveform=audio_chunk, frame_list=frame_list, max_slice_nums=1, # 每次输入的帧数(HD模式下可增大,如 [2,1] 表示叠帧用2和1) batch_vision_feed=False # 若为 True 可加速图像处理(非必须) ) # Step B: 生成 (generate) —— 模型给出对当前片段的回复 result = model.streaming_generate( prompt_wav_path=ref_audio_path, # 提供参考音色 max_new_speak_tokens_per_chunk=20, # 每片段最多生成 20 个语音token decode_mode="sampling" # 采样解码(随机性,可换为"greedy"贪心) ) # 收集模型输出的语音(如果有) if result["audio_waveform"] is not None: timed_output_audio.append((idx, result["audio_waveform"])) # 记录输出的文本和状态 results_log.append({ "chunk_idx": idx, "is_listen": result["is_listen"], # 模型当前是在“倾听”还是“说话” "text": result["text"], # 模型生成的文本 "end_of_turn": result["end_of_turn"], # 是否一句话结束 "current_time": result["current_time"], "audio_length": len(result["audio_waveform"]) if result["audio_waveform"] is not None else 0 }) # 打印输出以观察:listen 表示当前模型在等待输入,speak> 表示模型说的话 print("listen..." if result["is_listen"] else f"speak> {result['text']}") # 4. 逐块执行流式推理 for idx in range(len(audio_segments)): audio_chunk = audio_segments[idx] if idx < len(audio_segments) else None frame = video_frames[idx] if idx < len(video_frames) else None frame_list = [] if frame is not None: frame_list.append(frame) # 如果有堆叠帧(如高刷新模式),也加入 if stacked_frames is not None and idx < len(stacked_frames) and stacked_frames[idx] is not None: frame_list.append(stacked_frames[idx]) # Step A: 预填充 (prefill) —— 提供当前帧和音频片段 model.streaming_prefill( audio_waveform=audio_chunk, frame_list=frame_list, max_slice_nums=1, # 每次输入的帧数(HD模式下可增大,如 [2,1] 表示叠帧用2和1) batch_vision_feed=False # 若为 True 可加速图像处理(非必须) ) # Step B: 生成 (generate) —— 模型给出对当前片段的回复 result = model.streaming_generate( prompt_wav_path=ref_audio_path, # 提供参考音色 max_new_speak_tokens_per_chunk=20, # 每片段最多生成 20 个语音token decode_mode="sampling" # 采样解码(随机性,可换为"greedy"贪心) ) # 收集模型输出的语音(如果有) if result["audio_waveform"] is not None: timed_output_audio.append((idx, result["audio_waveform"])) # 记录输出的文本和状态 results_log.append({ "chunk_idx": idx, "is_listen": result["is_listen"], # 模型当前是在“倾听”还是“说话” "text": result["text"], # 模型生成的文本 "end_of_turn": result["end_of_turn"], # 是否一句话结束 "current_time": result["current_time"], "audio_length": len(result["audio_waveform"]) if result["audio_waveform"] is not None else 0 }) # 打印输出以观察:listen 表示当前模型在等待输入,speak> 表示模型说的话 print("listen..." if result["is_listen"] else f"speak> {result['text']}")ransformers import AutoModel
上面循环中,每次迭代模型都会读取新的视频帧和音频片段,通过 streaming_prefill 提供给模型,然后调用 streaming_generate 获取模型的输出。result 包含了模型在该时间片的行为状态和产出:result["is_listen"] 表明此时模型是否在“倾听”(如果为 False 则表示正在“说话”并给出了文本 result["text"]);result["audio_waveform"] 则是对应生成的语音数据。我们把每段语音都保存到 timed_output_audio 列表中,并且收集日志以备后用。max_new_speak_tokens_per_chunk=20 控制模型每个片段最多说多长,以避免一口气说太多错过后续输入;可以根据需要调整。
在打印输出中可以看到模型的实时行为:当打印 "listen..." 时表示模型此刻没有发言,只是在等待更多内容;当打印 speak> ... 时则输出了模型刚才生成的文字内容。这模拟了模型一会儿安静倾听(比如用户或环境在说话),一会儿开口回答的过程。
Step C: 合成输出视频(可选): 完成整个视频流处理后,我们可以调用 generate_duplex_video 函数,将原视频和模型的输出合成为一个带语音讲解的新视频。继续上述代码:
# 5. 合成带有 AI 讲话的新视频输出 # 确保系统已安装中文字体用于渲染字幕(如 Noto Sans CJK 或文泉驿微米黑) # !apt-get install -y fonts-noto-cjk fonts-wqy-microhei && fc-cache -fv generate_duplex_video( video_path=video_path, output_video_path="duplex_output.mp4", results_log=results_log, timed_output_audio=timed_output_audio, output_sample_rate=24000 # 输出语音采样率,可选 24000Hz 以保证质量 ) print("全双工交互视频已生成:duplex_output.mp4")
generate_duplex_video 将读取原始视频文件,用 results_log 中的文本在对应时间点叠加字幕,并用 timed_output_audio 中的音频替换原音轨或混音,从而得到 AI 解说版本的视频。请注意,为正确渲染中文字幕,需要系统安装支持中文的字体(如上述注释所示安装 Noto CJK 字体,并刷新字体缓存。执行完毕后,即可在 duplex_output.mp4 中观看模型“边看边说”的效果。
通过以上完整用例,我们实现了 MiniCPM-o 4.5 在全双工模式下对连续视频的实时理解与语音输出。您可以将此方法拓展到实时摄像头输入(使用 OpenCV 等获取逐帧图像并传递给模型)或其他流式场景中。需要注意全双工模式对系统性能要求较高,实际部署时可根据硬件能力调整帧率、音频切片长度等参数,以达到平衡流畅度和响应速度的最佳效果。
部署方式汇总及设备推荐
MiniCPM-o 4.5 虽功能强大,但要在不同环境下高效运行,往往需要针对性地选择部署方案。下面汇总几种常见的部署方式,并给出适用设备的建议:
本地部署(CPU/GPU)- llama.cpp: 您可以使用 llama.cpp 工具将模型量化后在本地设备CPU上运行。官方已提供 MiniCPM-o 4.5 的 GGUF 格式量化模型,从 2bits 到 8bits 共16种不同大小,以满足从高性能服务器到移动端设备的不同内存需求。例如,在具有 16GB 内存的 MacBook 或普通 PC 上,可选择 4-bit 或 5-bit 的量化模型利用 llama.cpp 推理,实现不错的响应速度。如果是 iPhone/iPad 等移动设备,也可以通过 Core ML 转换或 llama.cpp iOS 移植来运行适当精简的量化模型。总体而言,llama.cpp 提供了一个纯 C/C++ 实现的模型推理方案,具有体积小、无第三方依赖、多平台支持等优点,非常适合在轻量级设备或无法安装完整 Python 环境的场景下使用。
cd build/bin/ # run f16 version ./llama-mtmd-cli -m ../MiniCPM-o-4_5/MiniCPM-o-4_5-F16.gguf --mmproj ../MiniCPM-V-4/mmproj-model-f16.gguf -c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 --image xx.jpg -p "What is in the image?"
本地部署(Mac 优化) - Ollama:Ollama 是针对 macOS 优化的本地大模型运行工具,内置对 M系列芯片的支持和简洁的 CLI 界面。MiniCPM 系列模型可以通过 Ollama 一键部署运行,免去手动配置环境的麻烦[48]。对于 Mac 用户(尤其是 Apple Silicon 芯片,如 M1/M2),建议使用 Ollama 调用 MiniCPM-o 4.5 的 quantized 模型,以获得开箱即用的本地推理体验。由于 Ollama 底层也是基于 llama.cpp 实现,同样适合离线使用和保护隐私的数据在本地处理。
git clone https://github.com/tc-mb/ollama.git cd ollama git checkout MIniCPM-V go build . ./ollama serve ./ollama run openbmb/minicpm-v4
高吞吐部署 - vLLM: 如果希望在服务器端以高并发、高吞吐的方式提供 MiniCPM-o 4.5 服务,可以使用 vLLM。vLLM 是高性能的分布式推理引擎,利用显存高效管理和并行批处理技术,可以在一块或多块 GPU 上以接近极限的速度服务大批量请求。将 MiniCPM-o 4.5 部署在 vLLM 上,可支持企业级的推理性能需求。建议设备:拥有 高端 NVIDIA GPU(如 A100、H100) 的服务器,用 vLLM 可充分挖掘显卡算力,同时降低每个请求的延迟。vLLM 尤其适合需要同时处理多用户多模态请求的云端应用。
VLLM_USE_MODELSCOPE=true vllm serve OpenBMB/MiniCPM-o-4_5 --dtype auto --max-model-len 2048 --api-key token-abc123 --gpu_memory_utilization 0.9 --trust-remote-code --max-num-batched-tokens 2048
工业级部署 - SGLang:SGLang 是另一种高性能模型服务框架,支持大模型和多模态模型的推理服务。它提供类似 OpenAI API 的接口,可以方便地将 MiniCPM-o 4.5 集成为在线服务端点。SGLang 擅长在多GPU集群上高效地部署模型,具有低延迟、高吞吐的特点,还支持高效的批量推理和流水线并行。推荐在需要构建自托管 AI 服务的场景下使用。例如,大型互联网产品希望内置多模态问答功能,可考虑用 SGLang 部署 MiniCPM-o 4.5 模型并通过API提供服务。典型硬件配置为多卡 GPU 服务器集群,以充分利用其并行能力。
SGLANG_USE_MODELSCOPE=true python -m sglang.launch_server OpenBMB/MiniCPM-o-4_5 --port 30000
模型微调与二次开发
若有领域定制需求,可使用MS-Swift提供的微调工具对 MiniCPM-o 4.5 进行再训练。这些工具支持高效地对模型进行增量训练,以适应特定场景。微调后模型仍可用上述各种方案部署。
目前ms-swift支持了对MiniCPM-o-4_5图像和视频模态进行训练。你需要安装main分支的代码:
# pip install git+https://github.com/modelscope/ms-swift.git
训练Demo脚本如下:
# 20GiB CUDA_VISIBLE_DEVICES=0 \ swift sft \ --model OpenBMB/MiniCPM-o-4_5 \ --dataset 'AI-ModelScope/LaTeX_OCR:human_handwrite #20000 ' \ --load_from_cache_file true \ --split_dataset_ratio 0.01 \ --tuner_type lora \ --torch_dtype bfloat16 \ --num_train_epochs 1 \ --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --learning_rate 1e-4 \ --lora_rank 8 \ --lora_alpha 32 \ --target_modules all-linear \ --freeze_vit true \ --freeze_aligner true \ --gradient_accumulation_steps 16 \ --eval_steps 50 \ --save_steps 50 \ --save_total_limit 2 \ --logging_steps 5 \ --max_length 2048 \ --output_dir output \ --warmup_ratio 0.05 \ --dataset_num_proc 4 \ --dataloader_num_workers 4
如果要使用自定义数据集进行训练,你可以参考以下格式,并指定--dataset <dataset_path>。
{"messages": [{"role": "user", "content": "<image><image>两张图片有什么区别"}, {"role": "assistant", "content": "前一张是小猫,后一张是小狗"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
训练完成后,使用以下命令对训练后的权重使用验证集进行推理,这里的--adapters 需要替换成训练生成的last checkpoint文件夹。
CUDA_VISIBLE_DEVICES=0 \ swift infer \ --adapters output/vx-xxx/checkpoint-xxx \ --stream true \ --load_data_args true \ --max_new_tokens 2048
推送模型到ModelScope:
CUDA_VISIBLE_DEVICES=0 \ swift export \ --adapters output/vx-xxx/checkpoint-xxx \ --push_to_hub true \ --hub_model_id '<your-model-id>' \ --hub_token '<your-sdk-token>'
点击即可跳转模型链接