前期文章

Ubuntu 下搭建 whisper.cpp 本地环境-CSDN博客

前置知识

什么是温度采样?

温度参数的作用

温度(Temperature)控制模型预测的随机性:

  • 温度 = 0:完全确定性,总是选择概率最高的词

  • 温度 > 0:引入随机性,概率低的词也有机会被选中

  • 温度越高:输出越随机、越有创意,但可能不太准确

在温度采样模式下的工作机制

temperature > 0 时:

# 假设 best-of=5,temperature=0.4
1. 模型生成 5 个不同的候选文本序列(引入随机性)
2. 计算每个候选的评分(基于概率、长度等)
3. 选择评分最高的一个作为最终输出

为什么需要"样本池"?

问题:温度采样引入随机性,单次采样可能得到低质量结果 解决:生成多个样本,从中选择最佳的,类似于"抽奖多次选最好的"

实际例子

假设音频中有模糊的词汇,模型不确定:

温度=0.0(确定性): "今天天气很好"
温度=0.4,best-of=1: "今天天气很棒"(单次随机采样)
温度=0.4,best-of=5: 
  候选1: "今天天气很棒"     (评分: -2.1)
  候选2: "今天天气不错"     (评分: -1.8) ← 最佳
  候选3: "今天天气真好"     (评分: -2.3)
  候选4: "今天阳光明媚"     (评分: -2.9)
  候选5: "今天心情很好"     (评分: -3.1)
  
最终选择: "今天天气不错"

在同一次解码过程中,beam-size-bs)和 best-of-bo)只能选择其中一个生效,具体规则如下:

  1. 当温度序列中包含 大于 0 的值(即启用采样模式)时,Whisper 会自动禁用 beam-size,只使用 best-of

  2. 当温度序列全部为 0(即纯确定性模式)时,Whisper 会自动禁用 best-of,只使用 beam-size

特征 贪婪采样 束搜索
搜索空间 最小(每步1个选择) 中等(每步k个选择)
计算复杂度 最低 中等
结果质量 局部最优 通常更优
确定性 完全确定 相对确定

算法策略

模型数据流:

模型加载 -》 音频样本归一化 -》模型参数设置 -》 编码解码  -》 state.tokens文本转化自然语言处理
其中编码解码:
音频分段,滑动窗口输入 -》 特征提取 -》 mel频谱特征 -》 多层次Transformer -》 输出 embeddings(向量化)-》 首次解码后state.tokens=prompt 

-》1. greedy策略贪婪采样:
基于 state 和 embeddings 计算下一个 token的 logits(信誉分)
抑制与重置计算 logits 相关策略
最终选择最高概率的tokens,加入state->tokens序列末端
-》

-》2. Beam Search 并行解码策略:
初始化beam次数,只有一个活跃的beam
在每个时间步 t,对每条当前 beam(共有 B 条)分别计算一次 logits,此时总共会产生 B×V 个候选 token。
迭代扩展与剪枝,维护多个候选序列(beam)logits
扩展所有候选
剪枝并保留
-》

源码分析

whisper/whisper.cpp/src/whisper.cpp 默认决策,二选一

switch (strategy) {
        case WHISPER_SAMPLING_GREEDY:
            {
                result.greedy = {
                    /*.best_of   =*/ 5,
                };
            } break;
        case WHISPER_SAMPLING_BEAM_SEARCH:
            {
                result.beam_search = {
                    /*.beam_size =*/ 5,

                    /*.patience  =*/ -1.0f,
                };
            } break;
    }

正确使用代码

whisper_full_params WhisperASR::configureWhisperParams() {
    std::cout << "配置 Whisper 参数..." << std::endl;
    
    // 自动选择搜索策略
    WhisperConfig::SearchStrategy actual_strategy = determineOptimalSearchStrategy();
    
    whisper_full_params wparams;
    
    switch (actual_strategy) {
        case WhisperConfig::GREEDY: {
            std::cout << "使用贪婪搜索策略(快速模式)" << std::endl;
            wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
            
            // 贪婪模式核心设置
            wparams.greedy.best_of = config_.best_of;
            wparams.temperature = 0.0f;  // 贪婪模式使用零温度
            wparams.temperature_inc = 0.0f;  // 不增加温度
            
            // 贪婪模式优化设置
            wparams.entropy_thold = 2.4f;     // 放宽熵阈值以提高速度
            wparams.logprob_thold = -1.0f;    // 放宽对数概率阈值
            break;
        }
        
        case WhisperConfig::BEAM_SEARCH: {
            std::cout << "使用束搜索策略(高质量模式)" << std::endl;
            wparams = whisper_full_default_params(WHISPER_SAMPLING_BEAM_SEARCH);
            
            // 束搜索核心设置
            wparams.beam_search.beam_size = config_.beam_size;
            wparams.beam_search.patience = config_.beam_search_patience;
            
            // 束搜索质量优化
            wparams.temperature = config_.temperature_start;
            wparams.temperature_inc = config_.temperature_inc;
            wparams.entropy_thold = config_.entropy_threshold;
            wparams.logprob_thold = config_.logprob_threshold;
            break;
        }
        
        default: // AUTO 已经在 determineOptimalSearchStrategy 中处理
            break;
    }
    
    // 通用基本设置
    wparams.language = config_.language.c_str();
    wparams.n_threads = config_.n_threads;
    wparams.translate = false;              // 转录,不翻译
    wparams.detect_language = false;        // 语言已明确设置
    wparams.print_progress = false;         // 不输出处理进度
    // 移除initial_prompt相关代码,统一设置为false
    wparams.prompt_tokens = nullptr;
    wparams.prompt_n_tokens = 0;
    wparams.initial_prompt = nullptr;
    
    // 质量和性能平衡
    wparams.n_max_text_ctx = config_.mc;
    wparams.max_len = config_.ml;
    wparams.no_speech_thold = config_.no_speech_thold_min;

    // 输出和分割设置
    wparams.split_on_word = config_.split_on_word;
    wparams.no_context = false;             // 允许使用初始提示作为上下文!
    wparams.print_special = false;          // 不输出特殊字符
    
    // 语言相关的关键设置,确保简体中文输出
    wparams.suppress_blank = false;          // 抑制空白标记
    wparams.suppress_nst = true;           // 不抑制非语音标记

    // 时间戳相关设置
    wparams.no_timestamps = false;
    wparams.print_timestamps = config_.print_timestamps;
    wparams.token_timestamps = config_.token_timestamps;
    wparams.thold_pt = config_.thold_pt;
    
    if (wparams.token_timestamps) {
        wparams.thold_ptsum = config_.thold_ptsum;
    }

    // 设置实时回调
    if (config_.real_time_output) {
        wparams.new_segment_callback = [](struct whisper_context* ctx, struct whisper_state* state, int n_new, void* user_data) {
            WhisperASR* asr = static_cast<WhisperASR*>(user_data);
            asr->onNewSegment(ctx, state, n_new);
        };
        wparams.new_segment_callback_user_data = this;
    }

    std::cout << "✓ Whisper 参数配置完成" << std::endl;
    return wparams;
}

质量过滤参数(阈值控制)

-et N (--entropy-thold)

概念:基于词汇重复度的"卡顿检测器"

  • 作用:计算最近32个token的香农熵,低于阈值时认为模型"卡住了"(重复生成相同词汇)

  • 默认值:2.40

  • 调优思路

    • 降低(如1.8-2.0):对重复更敏感,更容易触发重试,适合处理"优优独播剧场"这类循环输出

    • 提高(如2.8-3.2):容忍更多重复,减少重试次数,提升速度但可能保留重复文本

-lpt N (--logprob-thold)

概念:模型"自信度检测器"

  • 作用:检查平均对数概率,低于阈值说明模型对输出不够自信

  • 默认值:-1.00

  • 调优思路

    • 提高(如-0.5到-0.8):只接受高自信度输出,质量更好但可能丢失弱音频片段

    • 降低(如-1.5到-2.0):接受更多不确定输出,召回率高但可能包含幻听

-wt N (--word-thold)

概念:词级时间戳"置信度门槛"

  • 作用:控制生成词级时间戳的概率阈值

  • 默认值:0.01

  • 调优思路

    • 提高(如0.05-0.1):只为高置信度词汇生成时间戳,时间戳更准确

    • 降低(如0.001):为更多词汇生成时间戳,覆盖率高但可能不准确

搜索策略参数(解码控制)

-bs N (--beam-size)

概念:解码时的"候选路径数量"

  • 作用:同时维护N条最优解码路径,最终选择最好的一条

  • 默认值:5(-1表示禁用束搜索)

  • 调优思路

    • 增大(如8-10):探索更多可能性,质量更好但计算量大幅增加

    • 减小(如1-3):速度优先,适合实时场景但可能错过最优解

    • 设为1:等价于贪心搜索,最快但质量一般

-bo N (--best-of)

概念:温度采样时的"样本池大小"

  • 作用:在温度>0时,生成N个候选样本并选择最佳的

  • 默认值:5

  • 调优思路

    • 增大(如8-10):更充分的随机探索,可能找到更好结果

    • 减小(如1-3):减少计算开销,适合对速度敏感的场景

-sow (--split-on-word)

概念:文本分割的"边界对齐器"

  • 作用:确保音频分段在词边界处切分,避免截断单词

  • 调优思路

    • 开启:文本更自然,适合长音频和需要高质量输出的场景

    • 关闭:处理速度稍快,但可能在分段边界出现断词

采样温度参数

-tp N (--temperature)

概念:采样随机性控制器

  • 作用:控制模型预测的确定性程度

  • 默认值:渐进序列 [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]

  • 工作机制

温度 = 0.0:完全确定性,总是选概率最高的词
温度 = 0.2-0.8:引入适量随机性,可能选择概率较低但合理的词
温度 = 1.0:最大随机性,输出更有创造性但可能不准确
  • 调优策略

    • 低温度(0.0-0.2):适合技术文档、会议纪要等需要准确性的场景

    • 中温度(0.4-0.6):平衡准确性与灵活性,适合一般对话

    • 高温度(0.8-1.0):处理困难音频时增加探索性,但可能产生幻听

-tpi N (--temperature-inc)

概念:温度递增策略

  • 作用:当前温度解码失败时,自动递增的步长

  • 默认值:通常 0.2

  • 工作流程

  • 调优思路

    • 小步长(0.1-0.15):更细致的温度探索,质量更稳定但计算量大

    • 大步长(0.3-0.5):快速跳到高温度,适合处理很困难的音频

优化示例

./bin/whisper-cli \
  -m /home/jbj/openai/whisper/whisper_modle/ggml-tiny.bin \
  -f /home/jbj/openai/whisper/test/out3.wav \
  --prompt "以下是普通话的句子,使用简体中文输出。" \
  -l zh \
  -t $(nproc) \
  --processors 1 \
  -l zh -et 1.8 -lpt -0.8 -bs 1 -bo 0 -tp 0.0,0.2 -tpi 0.1 \
  -ml 80 -mc -1   -nth 0,10 -sow \
   --no-timestamps --no-real-time \

./bin/whisper_asr \
  -m /home/jbj/openai/whisper/whisper_modle/ggml-tiny.bin \
  -f /home/jbj/openai/whisper/test/out3.wav \
  --prompt "以下是普通话的句子,使用简体中文输出。" \
  -l zh \
  -t $(nproc) \
  --processors 1 \
  --et 1.8 \
  --lpt -0.8 \
  --bs 0 \
  --bo 5 \
  --tp 0.0,0.2 \
  --tpi 0.1 \
  --nth 0,10 \
  --sow \
  --no-timestamps \
  --no-real-time  

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐