音轉(zhuǎn)文本實(shí)戰(zhàn):從云端API到本地部署的選型與優(yōu)化指南)
1. 中文語(yǔ)音轉(zhuǎn)文本的核心價(jià)值與場(chǎng)景拆解中文語(yǔ)音轉(zhuǎn)文本這件事表面上看就是把一段錄音變成文字但真正動(dòng)過手的人都知道這里面的水比想象中深得多。我最早接觸這個(gè)需求是在三年前當(dāng)時(shí)幫一個(gè)做在線教育的小團(tuán)隊(duì)處理課程錄音他們每周產(chǎn)出幾十個(gè)小時(shí)的講課音頻想轉(zhuǎn)成文字做課程筆記和字幕。一開始覺得找個(gè)工具跑一下就行結(jié)果試了七八個(gè)方案要么識(shí)別率慘不忍睹要么時(shí)間軸對(duì)不上要么遇到中英混說(shuō)的段落直接崩掉。后來(lái)花了將近兩個(gè)月時(shí)間把主流方案從架構(gòu)到參數(shù)全部摸了一遍才算真正把這件事跑通。中文語(yǔ)音轉(zhuǎn)文本英文叫 Speech-to-Text 或者 Automatic Speech RecognitionASR核心目標(biāo)是把連續(xù)的語(yǔ)音信號(hào)轉(zhuǎn)換成對(duì)應(yīng)的文字序列。它解決的問題很明確人說(shuō)話的速度大概是每分鐘 150 到 200 個(gè)字而打字速度平均只有每分鐘 40 到 60 個(gè)字中間有三到四倍的效率差。對(duì)于需要大量文字產(chǎn)出的場(chǎng)景——比如會(huì)議記錄、采訪整理、課程字幕、播客轉(zhuǎn)寫、客服質(zhì)檢——這個(gè)效率差就是實(shí)打?qū)嵉臅r(shí)間成本。適合參考這套內(nèi)容的人大概分三類。第一類是開發(fā)者需要把語(yǔ)音轉(zhuǎn)文本能力集成到自己的產(chǎn)品里關(guān)心的是接口怎么調(diào)、模型怎么選、延遲和準(zhǔn)確率怎么平衡。第二類是內(nèi)容創(chuàng)作者和運(yùn)營(yíng)人員不需要寫代碼但需要一套穩(wěn)定可靠的轉(zhuǎn)寫流程來(lái)處理日常素材。第三類是對(duì)技術(shù)感興趣的學(xué)習(xí)者想搞清楚中文語(yǔ)音識(shí)別到底是怎么工作的為什么有時(shí)候準(zhǔn)有時(shí)候不準(zhǔn)。不管你是哪一類下面這些從實(shí)際項(xiàng)目里摔打出來(lái)的經(jīng)驗(yàn)應(yīng)該都能幫你少走一些彎路。2. 技術(shù)路線選型從云端API到本地部署的完整對(duì)比2.1 三種主流方案的本質(zhì)區(qū)別中文語(yǔ)音轉(zhuǎn)文本目前主要有三條技術(shù)路線每條路線的適用場(chǎng)景和成本結(jié)構(gòu)完全不同選錯(cuò)了后面全是坑。第一條是云端API方案。代表產(chǎn)品包括國(guó)內(nèi)幾家大廠提供的語(yǔ)音識(shí)別服務(wù)以及一些專注語(yǔ)音領(lǐng)域的垂直廠商。你只需要把音頻文件傳上去或者推流過去對(duì)方返回識(shí)別結(jié)果。優(yōu)點(diǎn)是接入快、準(zhǔn)確率高、維護(hù)成本低缺點(diǎn)是按量計(jì)費(fèi)、有網(wǎng)絡(luò)依賴、數(shù)據(jù)要出本地。我實(shí)測(cè)下來(lái)短音頻5分鐘以內(nèi)的識(shí)別準(zhǔn)確率普遍能到 95% 以上長(zhǎng)音頻會(huì)有所下降。第二條是本地開源模型方案。以 Whisper 系列為代表包括各種社區(qū)微調(diào)版本。你需要自己準(zhǔn)備算力模型跑在本地。優(yōu)點(diǎn)是數(shù)據(jù)不出本地、沒有調(diào)用費(fèi)用、可以離線運(yùn)行缺點(diǎn)是部署有門檻、推理速度取決于硬件、中文識(shí)別效果需要針對(duì)場(chǎng)景調(diào)優(yōu)。我拿一段 30 分鐘的會(huì)議錄音做過測(cè)試在帶獨(dú)立顯卡的機(jī)器上中等規(guī)模模型大概需要 3 到 5 分鐘完成轉(zhuǎn)寫準(zhǔn)確率在 90% 到 94% 之間浮動(dòng)。第三條是混合方案。用本地模型做初步轉(zhuǎn)寫再用云端API做校對(duì)和補(bǔ)充或者反過來(lái)。這種方案適合對(duì)準(zhǔn)確率要求極高、同時(shí)又有數(shù)據(jù)隱私顧慮的場(chǎng)景。實(shí)際操作中我會(huì)用本地模型跑第一遍把置信度低的片段標(biāo)記出來(lái)再針對(duì)這些片段調(diào)用云端接口做二次識(shí)別。2.2 選型決策的關(guān)鍵參數(shù)選型的時(shí)候不能只看準(zhǔn)確率一個(gè)指標(biāo)下面這幾個(gè)參數(shù)必須一起考慮。評(píng)估維度云端API本地開源模型混合方案首次接入時(shí)間1到2小時(shí)1到3天3到5天中文準(zhǔn)確率95%到98%90%到95%96%到98%單小時(shí)音頻成本1到5元電費(fèi)硬件折舊0.5到3元數(shù)據(jù)隱私需上傳完全本地部分上傳離線可用否是部分長(zhǎng)音頻支持通常有上限取決于顯存靈活專業(yè)術(shù)語(yǔ)識(shí)別需定制可微調(diào)可微調(diào)這個(gè)表里的數(shù)據(jù)是我在多個(gè)項(xiàng)目中反復(fù)驗(yàn)證過的平均值具體數(shù)字會(huì)因音頻質(zhì)量、說(shuō)話人口音、背景噪聲等因素有較大波動(dòng)。選型的時(shí)候我一般建議先問三個(gè)問題數(shù)據(jù)能不能出本地預(yù)算結(jié)構(gòu)是固定成本還是變動(dòng)成本對(duì)延遲的容忍度是多少這三個(gè)問題的答案基本就能鎖定方案。2.3 為什么中文識(shí)別比英文更難很多人覺得中文語(yǔ)音識(shí)別應(yīng)該比英文簡(jiǎn)單因?yàn)橹形臎]有復(fù)雜的詞形變化。實(shí)際情況恰恰相反中文語(yǔ)音轉(zhuǎn)文本有幾個(gè)特有的難點(diǎn)。首先是同音字問題。中文里同音字和同音詞的比例遠(yuǎn)高于英文一個(gè)讀音可能對(duì)應(yīng)幾十個(gè)不同的字。比如“shi”這個(gè)音可以對(duì)應(yīng)“是、事、時(shí)、使、市、式、試、視、示、士”等等。模型必須依賴上下文才能判斷到底該用哪個(gè)字。英文雖然也有同音詞但比例低得多而且拼寫差異大更容易區(qū)分。其次是分詞和斷句。中文書寫沒有空格一句話里詞和詞的邊界是模糊的。語(yǔ)音識(shí)別輸出的文字需要經(jīng)過分詞處理才能用于后續(xù)的搜索、分析等任務(wù)。而分詞本身就是一個(gè)有歧義的問題不同分詞標(biāo)準(zhǔn)會(huì)得到不同結(jié)果。第三是口音和方言的影響。中文的口音差異非常大同一個(gè)詞在不同地區(qū)的發(fā)音可能完全不同。雖然普通話有標(biāo)準(zhǔn)發(fā)音但實(shí)際說(shuō)話中很少有人完全標(biāo)準(zhǔn)。模型訓(xùn)練時(shí)如果口音覆蓋不夠遇到帶口音的音頻就會(huì)頻繁出錯(cuò)。第四是中英混說(shuō)。這在技術(shù)類、商務(wù)類音頻里特別常見。一句話里夾雜幾個(gè)英文單詞模型需要在兩種語(yǔ)言之間無(wú)縫切換。我處理過一段產(chǎn)品經(jīng)理的會(huì)議錄音里面“這個(gè) feature 的 priority 要重新 align 一下”這種句子比比皆是純中文模型和純英文模型都處理不好。3. 實(shí)操環(huán)境搭建與核心工具鏈配置3.1 音頻預(yù)處理被大多數(shù)人忽略的關(guān)鍵步驟在把音頻送進(jìn)識(shí)別引擎之前預(yù)處理做得好不好直接決定最終準(zhǔn)確率的上限。我見過太多人拿著手機(jī)錄的嘈雜音頻直接往模型里扔然后抱怨識(shí)別率低。其實(shí)很多問題在預(yù)處理階段就能解決。采樣率統(tǒng)一是第一步。大多數(shù)語(yǔ)音識(shí)別模型期望的輸入采樣率是 16000Hz。如果你手頭的音頻是 44100Hz 或 48000Hz需要先做重采樣。用 ffmpeg 一行命令就能搞定ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav這條命令做了三件事把采樣率轉(zhuǎn)成 16000Hz把聲道數(shù)轉(zhuǎn)成單聲道把編碼格式轉(zhuǎn)成 16位 PCM。這三個(gè)參數(shù)是絕大多數(shù)語(yǔ)音識(shí)別模型的標(biāo)準(zhǔn)輸入格式。降噪處理是第二步。如果音頻有明顯的背景噪聲空調(diào)聲、鍵盤聲、風(fēng)扇聲可以用譜減法或者基于深度學(xué)習(xí)的降噪工具先處理一遍。我常用的是一個(gè)叫 noisereduce 的 Python 庫(kù)用法很簡(jiǎn)單import noisereduce as nr import soundfile as sf data, rate sf.read(input.wav) reduced_noise nr.reduce_noise(ydata, srrate) sf.write(output_denoised.wav, reduced_noise, rate)實(shí)測(cè)下來(lái)對(duì)于穩(wěn)態(tài)噪聲比如空調(diào)聲降噪能把識(shí)別準(zhǔn)確率提升 3 到 5 個(gè)百分點(diǎn)。但對(duì)于非穩(wěn)態(tài)噪聲比如突然的咳嗽聲、關(guān)門聲降噪效果有限有時(shí)候反而會(huì)引入失真這種情況需要手動(dòng)裁剪掉噪聲片段。音量歸一化是第三步。錄音音量太小會(huì)導(dǎo)致模型聽不清音量太大又會(huì)產(chǎn)生削波失真。用 ffmpeg 的 loudnorm 濾鏡可以做標(biāo)準(zhǔn)化ffmpeg -i input.wav -af loudnormI-16:TP-1.5:LRA11 -ar 16000 output_normalized.wav這里的參數(shù)含義是目標(biāo)響度 -16 LUFS最大真峰值 -1.5 dBTP響度范圍 11 LU。這套參數(shù)是我在多個(gè)項(xiàng)目中驗(yàn)證過的對(duì)語(yǔ)音識(shí)別比較友好。靜音切除是第四步。長(zhǎng)音頻里往往有大量靜音段這些段落不僅浪費(fèi)計(jì)算資源還可能影響模型對(duì)上下文的理解??梢杂?ffmpeg 的 silenceremove 濾鏡ffmpeg -i input.wav -af silenceremovestart_periods1:start_duration0.5:start_threshold-40dB:stop_periods-1:stop_duration0.5:stop_threshold-40dB output_trimmed.wav注意靜音切除的閾值不要設(shè)得太激進(jìn)-40dB 是一個(gè)比較安全的起點(diǎn)。如果設(shè)到 -30dB可能會(huì)把說(shuō)話人換氣的聲音也切掉導(dǎo)致語(yǔ)句不連貫。3.2 本地模型部署從零跑通 Whisper 系列如果你選擇本地部署路線Whisper 系列是目前中文支持最好的開源選擇之一。下面是我在實(shí)際項(xiàng)目中總結(jié)的部署流程。硬件要求方面如果只是偶爾轉(zhuǎn)寫短音頻CPU 也能跑但速度很慢。一段 10 分鐘的音頻在普通筆記本 CPU 上可能需要 15 到 20 分鐘。如果有獨(dú)立顯卡速度會(huì)快很多。顯存方面中等規(guī)模模型大概需要 4 到 6GB 顯存大規(guī)模模型需要 10GB 以上。如果顯存不夠可以用量化版本代價(jià)是準(zhǔn)確率會(huì)下降 1 到 2 個(gè)百分點(diǎn)。環(huán)境安裝用 pip 就能完成pip install openai-whisper pip install torch torchaudio如果需要 GPU 加速要確保 torch 的 CUDA 版本和顯卡驅(qū)動(dòng)匹配。這一步經(jīng)常出問題建議先用torch.cuda.is_available()確認(rèn) GPU 是否可用。基礎(chǔ)轉(zhuǎn)寫腳本大概長(zhǎng)這樣import whisper model whisper.load_model(medium) result model.transcribe( audio.wav, languagezh, tasktranscribe, initial_prompt以下是普通話的句子。, temperature0.0, compression_ratio_threshold2.4, logprob_threshold-1.0, no_speech_threshold0.6 ) for segment in result[segments]: print(f[{segment[start]:.2f} - {segment[end]:.2f}] {segment[text]})這里有幾個(gè)參數(shù)值得展開說(shuō)。initial_prompt是給模型的提示詞告訴它這是普通話內(nèi)容能顯著提升中文識(shí)別的穩(wěn)定性。temperature0.0表示用確定性解碼避免模型隨機(jī)發(fā)揮。后面三個(gè)閾值參數(shù)控制的是什么情況下模型認(rèn)為“這段沒有語(yǔ)音”或者“這段識(shí)別結(jié)果不可靠”需要根據(jù)實(shí)際音頻質(zhì)量調(diào)整。模型規(guī)模選擇上我一般這樣建議tiny 和 base 適合快速預(yù)覽準(zhǔn)確率勉強(qiáng)能用small 是速度和準(zhǔn)確率的平衡點(diǎn)medium 是我最常用的中文準(zhǔn)確率明顯好于 smalllarge 適合對(duì)準(zhǔn)確率要求極高的場(chǎng)景但速度慢很多。如果音頻里有大量專業(yè)術(shù)語(yǔ)large 的優(yōu)勢(shì)會(huì)更明顯。3.3 云端API接入以通用流程為例云端API的接入流程各家大同小異核心步驟都是注冊(cè)賬號(hào)、獲取密鑰、構(gòu)造請(qǐng)求、處理響應(yīng)。下面是一個(gè)通用的調(diào)用示例import requests import json import base64 def speech_to_text(audio_path, api_key, api_url): with open(audio_path, rb) as f: audio_data base64.b64encode(f.read()).decode(utf-8) headers { Content-Type: application/json, Authorization: fBearer {api_key} } payload { audio: audio_data, format: wav, sample_rate: 16000, language: zh-CN, enable_punctuation: True, enable_itn: True } response requests.post(api_url, headersheaders, jsonpayload) result response.json() return result.get(text, )這里的enable_punctuation控制是否自動(dòng)加標(biāo)點(diǎn)enable_itn控制是否做逆文本歸一化把“一百二十三”轉(zhuǎn)成“123”。這兩個(gè)參數(shù)對(duì)最終輸出的可讀性影響很大建議都打開。提示云端API通常對(duì)單次請(qǐng)求的音頻時(shí)長(zhǎng)有限制常見的是 60 秒或 5 分鐘。處理長(zhǎng)音頻時(shí)需要先做切分切分點(diǎn)最好選在靜音段避免把一句話切成兩半。4. 識(shí)別準(zhǔn)確率優(yōu)化的實(shí)戰(zhàn)技巧4.1 熱詞與自定義詞表通用模型對(duì)專業(yè)術(shù)語(yǔ)、人名、產(chǎn)品名的識(shí)別往往不準(zhǔn)。比如“卷積神經(jīng)網(wǎng)絡(luò)”可能被識(shí)別成“卷機(jī)神經(jīng)網(wǎng)絡(luò)”“Transformer”可能被識(shí)別成“傳絲佛魔”。解決這個(gè)問題最直接的辦法是使用熱詞功能。大多數(shù)云端API都支持傳入熱詞列表格式通常是“詞語(yǔ)權(quán)重”。權(quán)重越高模型越傾向于輸出這個(gè)詞。我一般會(huì)把項(xiàng)目相關(guān)的專業(yè)術(shù)語(yǔ)、產(chǎn)品名、人名整理成一個(gè)列表權(quán)重設(shè)置在 5 到 10 之間。權(quán)重太高會(huì)導(dǎo)致模型過度偏向熱詞把發(fā)音相近的普通詞也強(qiáng)行替換成熱詞反而降低準(zhǔn)確率。本地模型的話可以通過initial_prompt參數(shù)傳入熱詞。比如initial_prompt 以下是關(guān)于機(jī)器學(xué)習(xí)的討論涉及卷積神經(jīng)網(wǎng)絡(luò)、Transformer、注意力機(jī)制、梯度下降等術(shù)語(yǔ)。這個(gè)提示詞會(huì)在解碼時(shí)給模型一個(gè)上下文偏向讓它在遇到相似發(fā)音時(shí)更傾向于輸出這些術(shù)語(yǔ)。實(shí)測(cè)下來(lái)對(duì)專業(yè)術(shù)語(yǔ)的識(shí)別準(zhǔn)確率能提升 10 到 20 個(gè)百分點(diǎn)。4.2 標(biāo)點(diǎn)與斷句的后處理語(yǔ)音識(shí)別模型輸出的原始文本往往沒有標(biāo)點(diǎn)或者標(biāo)點(diǎn)位置不準(zhǔn)。后處理階段可以用規(guī)則模型的方式做修正。規(guī)則方面可以根據(jù)停頓時(shí)間來(lái)判斷。如果兩個(gè)詞之間的靜音超過 0.5 秒大概率是一個(gè)句子的邊界可以插入句號(hào)或逗號(hào)。如果靜音超過 1.5 秒可能是段落邊界。模型方面可以用一個(gè)專門的中文標(biāo)點(diǎn)恢復(fù)模型來(lái)處理。這類模型通?;?BERT 架構(gòu)輸入無(wú)標(biāo)點(diǎn)文本輸出帶標(biāo)點(diǎn)的文本。我試過幾個(gè)開源方案效果最好的是在新聞?wù)Z料上微調(diào)過的版本對(duì)正式文本的標(biāo)點(diǎn)恢復(fù)準(zhǔn)確率能到 85% 以上。但對(duì)于口語(yǔ)化內(nèi)容比如“然后那個(gè)就是說(shuō)”標(biāo)點(diǎn)恢復(fù)的效果會(huì)差一些因?yàn)榭谡Z(yǔ)本身就沒有嚴(yán)格的標(biāo)點(diǎn)規(guī)則。4.3 時(shí)間軸對(duì)齊與字幕生成如果你需要生成字幕文件SRT 或 VTT 格式時(shí)間軸的準(zhǔn)確性就很重要了。Whisper 輸出的 segments 自帶時(shí)間戳但粒度比較粗有時(shí)候一個(gè) segment 包含好幾句話。可以用 forced alignment 工具做更精細(xì)的對(duì)齊。我常用的是一個(gè)叫 stable-ts 的庫(kù)它在 Whisper 基礎(chǔ)上做了時(shí)間軸優(yōu)化import stable_whisper model stable_whisper.load_model(medium) result model.transcribe(audio.wav, languagezh) result.to_srt_vtt(output.srt, word_levelTrue)word_levelTrue會(huì)輸出詞級(jí)別的時(shí)間戳生成的字幕更精確。不過詞級(jí)別對(duì)齊會(huì)稍微增加處理時(shí)間大概多 20% 到 30%。注意生成字幕后一定要人工過一遍。模型的時(shí)間軸偶爾會(huì)出現(xiàn)重疊或跳躍比如上一句還沒結(jié)束下一句就開始了或者中間突然空了 10 秒。這些問題在自動(dòng)生成階段很難完全避免人工校對(duì)是最后一道防線。5. 常見問題排查與避坑指南5.1 識(shí)別結(jié)果亂碼或重復(fù)這是最常見的問題之一。表現(xiàn)是輸出的文字里出現(xiàn)大量重復(fù)的短語(yǔ)或者完全無(wú)關(guān)的字符。原因通常有三個(gè)音頻質(zhì)量太差、模型參數(shù)設(shè)置不當(dāng)、音頻格式不兼容。排查步驟是這樣的先檢查音頻能不能正常播放如果播放都有問題那識(shí)別肯定好不了。然后用音頻編輯軟件看一下波形確認(rèn)沒有嚴(yán)重的削波或噪聲。如果音頻沒問題再檢查模型參數(shù)。Whisper 的compression_ratio_threshold參數(shù)控制的就是重復(fù)檢測(cè)默認(rèn)值是 2.4如果經(jīng)常出現(xiàn)重復(fù)可以調(diào)低到 2.0 試試。另外temperature設(shè)成 0 可以減少隨機(jī)性但有時(shí)候適當(dāng)提高溫度比如 0.2反而能打破重復(fù)循環(huán)。5.2 長(zhǎng)音頻處理超時(shí)或內(nèi)存溢出處理超過 30 分鐘的音頻時(shí)很容易遇到內(nèi)存不夠或者處理超時(shí)的問題。解決方案是分而治之先把長(zhǎng)音頻切成 5 到 10 分鐘的片段分別識(shí)別最后再拼接結(jié)果。切分的時(shí)候要注意不能隨便按時(shí)間切否則會(huì)把一句話切成兩半。正確做法是先檢測(cè)靜音段在靜音段中間切??梢杂?pydub 庫(kù)來(lái)實(shí)現(xiàn)from pydub import AudioSegment from pydub.silence import split_on_silence audio AudioSegment.from_wav(long_audio.wav) chunks split_on_silence( audio, min_silence_len500, silence_thresh-40, keep_silence200 ) for i, chunk in enumerate(chunks): chunk.export(fchunk_{i}.wav, formatwav)min_silence_len500表示靜音超過 500 毫秒才認(rèn)為是切分點(diǎn)silence_thresh-40是靜音閾值keep_silence200表示切分后每段保留 200 毫秒的靜音避免切得太生硬。5.3 中英混說(shuō)識(shí)別效果差中英混說(shuō)是中文語(yǔ)音識(shí)別的一個(gè)老大難問題。純中文模型會(huì)把英文單詞強(qiáng)行識(shí)別成發(fā)音相近的中文純英文模型則會(huì)把中文部分識(shí)別成亂碼。解決方案有幾個(gè)。如果用的是云端API看看有沒有專門的中英混說(shuō)模型或者語(yǔ)言自適應(yīng)功能。如果用的是本地模型可以在initial_prompt里明確說(shuō)明“以下內(nèi)容包含中英文混合”給模型一個(gè)預(yù)期。另外Whisper 的 large 模型在中英混說(shuō)上的表現(xiàn)明顯好于 smaller 模型如果這個(gè)場(chǎng)景是剛需建議直接上 large。還有一個(gè)取巧的辦法先用語(yǔ)言檢測(cè)工具判斷每個(gè)片段的語(yǔ)言然后分別用對(duì)應(yīng)的模型識(shí)別最后合并。但這個(gè)方案實(shí)現(xiàn)復(fù)雜而且語(yǔ)言切換點(diǎn)很難精確檢測(cè)實(shí)際效果不一定比直接用 large 模型好。5.4 常見問題速查表問題現(xiàn)象可能原因排查方法解決方案輸出大量重復(fù)文字解碼參數(shù)不當(dāng)檢查 compression_ratio調(diào)低閾值調(diào)整 temperature識(shí)別結(jié)果為空音頻格式不對(duì)用播放器驗(yàn)證轉(zhuǎn)成 16kHz 單聲道 WAV專業(yè)術(shù)語(yǔ)識(shí)別錯(cuò)缺少熱詞對(duì)比原文和輸出添加熱詞或 initial_prompt處理速度極慢硬件不足查看 CPU/GPU 占用換小模型或啟用 GPU時(shí)間軸錯(cuò)亂對(duì)齊粒度粗檢查 SRT 文件用詞級(jí)別對(duì)齊工具中英混說(shuō)出錯(cuò)模型語(yǔ)言限制分段測(cè)試換 large 模型或混合方案標(biāo)點(diǎn)缺失未開啟標(biāo)點(diǎn)功能檢查 API 參數(shù)開啟標(biāo)點(diǎn)或后處理6. 從轉(zhuǎn)寫到應(yīng)用下游任務(wù)的銜接6.1 文本后處理與格式化語(yǔ)音轉(zhuǎn)文本的輸出只是原材料要真正可用還需要后處理。最基本的后處理包括去除多余空格、統(tǒng)一標(biāo)點(diǎn)符號(hào)、修正明顯的識(shí)別錯(cuò)誤、分段和加標(biāo)題。我一般會(huì)寫一個(gè)簡(jiǎn)單的規(guī)則引擎來(lái)處理這些。比如把連續(xù)的多個(gè)句號(hào)合并成一個(gè)把英文標(biāo)點(diǎn)轉(zhuǎn)成中文標(biāo)點(diǎn)把“嗯”“啊”這類填充詞根據(jù)場(chǎng)景決定是否保留。如果是會(huì)議記錄填充詞可以去掉如果是采訪整理填充詞可能包含說(shuō)話人的情緒信息需要保留。6.2 說(shuō)話人分離多人對(duì)話場(chǎng)景下光有文字還不夠還需要知道每句話是誰(shuí)說(shuō)的。說(shuō)話人分離Speaker Diarization是另一個(gè)技術(shù)模塊可以和語(yǔ)音識(shí)別配合使用。開源方案里pyannote-audio 是比較成熟的選擇。基本流程是先做語(yǔ)音活動(dòng)檢測(cè)找出有語(yǔ)音的片段然后提取每個(gè)片段的聲紋特征最后做聚類把相同說(shuō)話人的片段歸為一組。輸出結(jié)果是每個(gè)時(shí)間段對(duì)應(yīng)的說(shuō)話人標(biāo)簽再和識(shí)別文本按時(shí)間軸合并就能得到帶說(shuō)話人標(biāo)記的對(duì)話記錄。實(shí)際操作中說(shuō)話人分離的準(zhǔn)確率受錄音質(zhì)量影響很大。如果是單人麥克風(fēng)錄音不同人聲音差異明顯準(zhǔn)確率能到 90% 以上。如果是遠(yuǎn)場(chǎng)錄音或者多人同時(shí)說(shuō)話準(zhǔn)確率會(huì)大幅下降。我一般建議在錄音階段就盡量保證每個(gè)人用獨(dú)立麥克風(fēng)后期處理會(huì)省很多事。6.3 關(guān)鍵詞提取與摘要生成轉(zhuǎn)寫文本的另一個(gè)常見需求是提取關(guān)鍵詞和生成摘要。關(guān)鍵詞提取可以用 TF-IDF 或者 TextRank 算法也可以直接用大語(yǔ)言模型來(lái)做。摘要生成目前效果最好的是用大語(yǔ)言模型把轉(zhuǎn)寫文本按長(zhǎng)度切分后分段摘要再合并成總摘要。這里有一個(gè)經(jīng)驗(yàn)語(yǔ)音轉(zhuǎn)文本的輸出往往比書面文本更啰嗦重復(fù)內(nèi)容更多。直接拿去做摘要模型可能會(huì)被冗余信息干擾。我通常會(huì)在摘要之前先做一輪文本壓縮把明顯重復(fù)的句子去掉把口語(yǔ)化的表達(dá)轉(zhuǎn)成書面表達(dá)這樣摘要質(zhì)量會(huì)好很多。7. 成本控制與性能優(yōu)化的平衡7.1 云端API的成本優(yōu)化云端API按量計(jì)費(fèi)用量大的時(shí)候成本很可觀。幾個(gè)優(yōu)化方向一是音頻預(yù)處理階段盡量切除靜音段減少實(shí)際需要識(shí)別的時(shí)長(zhǎng)二是根據(jù)場(chǎng)景選擇不同的模型檔次比如內(nèi)部會(huì)議記錄可以用標(biāo)準(zhǔn)版對(duì)外發(fā)布的字幕用高精度版三是利用各家提供的免費(fèi)額度或包年套餐。我算過一筆賬一個(gè)每天產(chǎn)生 10 小時(shí)音頻的團(tuán)隊(duì)如果用高精度API每月成本大概在 1500 到 3000 元之間。如果先做靜音切除通常能減少 20% 到 30% 的時(shí)長(zhǎng)再根據(jù)內(nèi)容重要性分級(jí)處理成本能壓到 800 到 1500 元。7.2 本地部署的硬件選型本地部署的成本主要是硬件。如果只是偶爾用用現(xiàn)有電腦就行。如果需要批量處理建議配一臺(tái)帶獨(dú)立顯卡的機(jī)器。顯卡選擇上顯存比算力更重要因?yàn)轱@存決定了能跑多大的模型。8GB 顯存能跑 medium 模型12GB 以上能跑 large 模型。如果不想買硬件也可以考慮按小時(shí)租用云端 GPU 實(shí)例。這種方式適合處理量波動(dòng)大的場(chǎng)景用的時(shí)候開不用的時(shí)候關(guān)成本比長(zhǎng)期持有硬件低。7.3 批量處理的流水線設(shè)計(jì)當(dāng)需要處理大量音頻時(shí)設(shè)計(jì)一個(gè)高效的流水線很重要。我的做法是把整個(gè)流程拆成獨(dú)立的步驟音頻預(yù)處理、識(shí)別、后處理、格式轉(zhuǎn)換。每個(gè)步驟之間用文件或者消息隊(duì)列傳遞數(shù)據(jù)。這樣做的好處是每個(gè)步驟可以獨(dú)立優(yōu)化和擴(kuò)展比如識(shí)別步驟可以并行跑多個(gè)任務(wù)預(yù)處理步驟可以單獨(dú)調(diào)參。流水線工具方面簡(jiǎn)單的用 shell 腳本就能搞定復(fù)雜的可以用 Airflow 或者 Prefect 這類工作流引擎。我個(gè)人的經(jīng)驗(yàn)是如果每天處理的音頻不超過 100 小時(shí)shell 腳本加一個(gè)任務(wù)隊(duì)列就夠了沒必要上太重型的工具。8. 我踩過的那些坑說(shuō)幾個(gè)印象深刻的教訓(xùn)。第一個(gè)是關(guān)于音頻格式的。有一次客戶給了一批 .m4a 格式的錄音我直接扔進(jìn)模型結(jié)果識(shí)別出來(lái)全是亂碼。查了半天才發(fā)現(xiàn)是采樣率的問題m4a 默認(rèn)是 44100Hz模型期望的是 16000Hz。轉(zhuǎn)格式之后問題解決。這件事之后我養(yǎng)成了一個(gè)習(xí)慣不管什么格式的音頻先統(tǒng)一轉(zhuǎn)成 16kHz 單聲道 WAV再進(jìn)識(shí)別流程。第二個(gè)是關(guān)于熱詞權(quán)重的。有一次為了提升產(chǎn)品名識(shí)別率我把熱詞權(quán)重設(shè)到了 20結(jié)果模型把所有發(fā)音相近的詞都替換成了產(chǎn)品名正常對(duì)話被改得面目全非。后來(lái)把權(quán)重降到 8效果就正常了。熱詞權(quán)重這個(gè)東西不是越高越好找到平衡點(diǎn)很重要。第三個(gè)是關(guān)于長(zhǎng)音頻切分的。早期我按固定時(shí)長(zhǎng)切分每 5 分鐘切一刀。結(jié)果經(jīng)常出現(xiàn)一句話被切成兩半的情況前半句在上一段后半句在下一段拼接后語(yǔ)義完全變了。后來(lái)改成按靜音段切分問題就解決了。雖然實(shí)現(xiàn)起來(lái)麻煩一點(diǎn)但值得。第四個(gè)是關(guān)于模型選擇的。有一段時(shí)間我迷信大模型什么音頻都用 large 跑。后來(lái)發(fā)現(xiàn)對(duì)于清晰的單人錄音medium 和 large 的準(zhǔn)確率差距不到 1 個(gè)百分點(diǎn)但速度差了一倍多?,F(xiàn)在我的策略是先快速跑一遍 small 模型看看整體質(zhì)量如果質(zhì)量好就直接用如果質(zhì)量差再上 large。最后一個(gè)坑是關(guān)于標(biāo)點(diǎn)恢復(fù)的。我一開始用規(guī)則做標(biāo)點(diǎn)根據(jù)停頓時(shí)間加逗號(hào)句號(hào)。結(jié)果發(fā)現(xiàn)說(shuō)話人停頓的地方不一定需要標(biāo)點(diǎn)有時(shí)候停頓只是思考不是句子邊界。后來(lái)改用模型做標(biāo)點(diǎn)恢復(fù)效果好很多。但模型也有模型的問題遇到口語(yǔ)化嚴(yán)重的音頻標(biāo)點(diǎn)恢復(fù)會(huì)過度糾正把口語(yǔ)的節(jié)奏感破壞了。所以現(xiàn)在我的做法是正式內(nèi)容用模型標(biāo)點(diǎn)口語(yǔ)內(nèi)容保留原始停頓只做最基本的斷句。這些經(jīng)驗(yàn)說(shuō)到底就是一句話語(yǔ)音轉(zhuǎn)文本沒有銀彈每個(gè)場(chǎng)景都需要針對(duì)性地調(diào)優(yōu)。通用方案能解決 80% 的問題剩下的 20% 才是真正體現(xiàn)功力的地方。