這裏介紹我最近做的一個嘗試:利用 python-pinyin 和大語言模型(LLM)給多音字標註拼音。
想要回答的是一個很簡單的問題:對於漢字(多音字)拼音的自動標註,現有技術能達到怎樣的準確度?
首先經過簡單的查找,找到了 python-pinyin 這個很不錯的漢字拼音轉換工具(PyPI 上的包名爲 pypinyin)。python-pinyin 預置了一些詞語讀音數據,如果是已知的詞語,可以直接給出預置的讀音;對於不在預置數據中的詞,則在啓用 heteronym=True 選項時給出所有可能的讀音。例如,假設預置數據不包含短語「中心」的讀音,那麼對於多音字「中」,python-pinyin 會給出所有可能的讀音 ['zhōng', 'zhòng']:
>>> from pypinyin import pinyin
>>> pinyin('中心', heteronym=True)
[['zhōng', 'zhòng'], ['xīn']]再舉一例,假設預置數據中包含短語「目的」,且唯一讀音爲 mù dì,則無論是否啓用 heteronym=True,都只會得到唯一讀音。
>>> from pypinyin import pinyin
>>> pinyin('目的', heteronym=True)
[['mù'], ['dì']]不妨就將 python-pinyin 作爲本次實驗的起點。對於預置數據尚未涵蓋的短語中的多音字,常見有「取最常用的讀音,容許錯誤」和「人工校對」兩種處理方法。近年來,也有新穎的基於各類算法的方法,例如 g2pW(基於 BERT),已經獲得了非常好的準確率。但是这些方法的技術門檻較高(我的主觀感受),而現在有了具有對話能力的生成式語言模型,一個自然的想法是嘗試讓這樣的生成式模型根據指令選擇合適的讀音。本次實驗的內容就是驗證這個想法是否可行。
朙月拼音 是一個詞庫基於傳統字形的拼音輸入方案。我們從其詞庫中選取一些含有多音字的短語,使用人工智能進行標註;假設「詞庫中的讀音」近乎等同於「這些短語的全部正確讀音」,那麼通過將標註結果和原有讀音對比,就可以很方便地評估標註的準確程度。(本次隨緣選了「乾」、「彈」、「惡」、「樂」、「率」五個字,總共一千多個短語。)爲了方便讀者重複實驗,在 pinyin-annotation 倉庫的 README 裏有這一步的示例腳本,可自行修改取用。
由於 python-pinyin 內置的詞語讀音以簡體字爲主,在實際應用中,通常會將待處理內容先轉換爲簡體(例如用 OpenCC 等工具),再標註拼音,以充分利用其預置讀音數據。然而本實驗旨在多獲取數據來評估 LLM 的能力,故反其道而行之:有意不轉換爲簡體,以儘量少用 python-pinyin 的預置讀音數據,而多讓 LLM 根據上下文來選擇讀音。
實驗中測試的部分模型,例如 QwQ、OpenThinker 和 DeepSeek-R1-Distill-Qwen 爲具有推理能力的模型(reasoning model)。爲了充分利用各模型的能力,經過一些前期的嘗試後,選定了 2-pass 方法,亦即先讓模型自由進行推理,輸出非結構化的文本,再讓模型總結先前的推理,以 JSON 格式輸出結構化的結果。
詳細的代碼實現,歡迎參閱 https://github.com/sncix/pinyin-annotation/tree/v0.2.0。如果你有不同的方法,也非常歡迎介紹。
本次實驗使用 ollama(0.7.1 版本)運行大語言模型。涉及的模型如下所示:
- Qwen3 32B
- Qwen3 30B-A3B
- QwQ 32B
- OpenThinker 32B
- DeepSeek-R1-Distill-Qwen 32B
- Qwen2.5 32B
- Mistral Small 3.1 24B
- Phi-4-reasoning-plus 14B
所有模型均使用由 ollama 官方分發的量化版本。其中 Phi-4-reasoning-plus 因參數量較小,選用 Q8_0 量化版本,其餘模型均選用 Q4_K_M 量化版本1。
各模型與現有詞庫讀音不一致數見下表所示(左欄括號內爲含有該字的短語總數)。數字越小,表示和現有詞庫符合度越好。
| qwq:32b | qwen3:32b | openthinker:32b | deepseek-r1:32b | qwen2.5:32b | qwen3:30b-a3b | mistral-small3.1:24b | phi4-reasoning:14b-plus-q8_0 | |
|---|---|---|---|---|---|---|---|---|
| 乾 (2252) | 42 | 68 | 68 | 73 | 44 | 78 | 177 | 89 |
| 彈 (207) | 40 | 44 | 70 | 69 | 71 | 74 | 74 | 102 |
| 惡 (66) | 28 | 23 | 35 | 38 | 30 | 35 | 30 | 47 |
| 樂 (479) | 126 | 119 | 1833 | 106 | 126 | 157 | 249 | 159 |
| 率 (20045) | 14 | 22 | 29 | 62 | 27 | 33 | 68 | 100 |
詳細實驗結果可在 collected_results_20250524/ 路徑下查閱,其中 log 文件爲程序的運行日誌(包含 LLM 生成的輸出),txt 文件爲各短語標註後的讀音。
本次實驗共測試了八種 32B(Q4_K_M)及以下級別的 LLM,在拼音標註方面都未達能夠實用的水準,但不知是模型能力如此,還是使用方法未能發揮其潛力。相對來說,QwQ 的表現最好。
最後一節中,我們簡略探討一些本實驗涉及到的倫理問題。注意 AI 領域的法律與政策仍然處於較快變化之中,各地域間也不同,更何況我知之甚少,因此這裏將會側重於一般原理,而非實際的法律規定。提及的概念除非明記,都不應視爲法律上的嚴格概念。
首先是權利的歸屬問題。生成式 AI 通常會涉及到三種權利對象:訓練所使用的數據集、訓練完成後的模型、及使用模型生成的輸出。其中前兩者常常能通過既有的事物類推加以理解(這並不意味着有關它們的問題都有確定的回答),而有關運行輸出的問題則很大程度上是嶄新的。
以下舉幾種簡化場景爲例:
- 訓練數據均屬於 public domain6,或以寬鬆(permissive)自由許可證7授權的作品
- 訓練數據除了上述來源以外,還含有以 copyleft 自由許可證授權的作品
- 訓練數據含有其他類型的許可,但在訓練及分發模型過程中遵守了所有的授權條件
- 訓練或分發模型的過程本身就違反了源數據的授權條件
第一種情形下通常爭議最少。假設採取「訓練後的模型是訓練數據的衍生作品」的觀點,需要做的也只是遵守對應的寬鬆許可證,並不困難。但即使這種最簡單的情形,關於運行輸出的問題也並非顯然。當訓練數據的授權條件包含「署名/姓名標示」時,假設採取「模型的輸出也是訓練數據的衍生作品」的觀點,則要想分享任何模型輸出,就可能需要爲其標示來源。但來自源數據的信息早已在訓練階段「混合」,因此對輸出的標示只能和模型本體一樣,羅列全部數據的來源。有些觀點可能認爲這仍不滿足署名/姓名標示要求。8
接下來看第二種情形。與第一種情形的不同在於,不同 copyleft 許可證的作品常常是無法混合的。也就是說,要想在遵守所有許可證的前提下分享訓練後的模型,訓練數據中最多只能加入以一種 copyleft 許可證授權的作品(例如只加入以 GPLv3 授權的作品),除非許可證中有明確的兼容性條款9。當然,到模型輸出的署名/姓名標示方面,也面臨着一樣的問題。
第三種其實包括了無數複雜情形,惟和本篇主題關聯不大,略過不作討論。(打賭沒人會讀到這裏……)
關於第四種情形,這裏只取一個很小的切入點,即問:從模型的利用者的角度出發,我們可以藉助哪些做法,減少使用這些並非基於同意或授權而煉成的模型。經驗上,當我們不確定一件工具是否足夠可靠時,容易想到這樣幾個方向:保留備選項,避免依賴單一工具;繼續獲取信息,變未知爲已知;乃至參與製造工具,自助互助。這些策略所需資源的種類與數量各不相同,並不一定都可行。就目前的 LLM 領域而言,完全公開訓練數據的模型相當少見,而自行訓練亦非大多數人所可及。只好坦承,具體可執行的方案既超出了本文的範疇,也超出了我的能力,也許熟悉這一塊的讀者可以補充。
TODO
TODO
Footnotes
-
使用的各模型在 ollama 內的 ID(實質上是 manifest 文件的 sha256 摘要值的前十二位,雖然 ollama 官方文檔未見記載這一點)爲:qwen3:32b e1c9f234c6eb;qwen3:30b-a3b 2ee832bc15b5;qwq:32b 009cb3f08d74;openthinker:32b 04b5937dcb16;deepseek-r1:32b 38056bbcbb2d;qwen2.5:32b 9f13ba1299af;mistral-small3.1:24b b9aaf0c2586a;phi4-reasoning:14b-plus-q8_0 ecd8f64ff877。 ↩
-
在實驗所用的 pypinyin 0.54.0 中,「沒」只有
méi這一個讀音,因此無法爲詞語「乾沒」(正確的讀音爲gān mò)選擇正確的讀音,故從計算中排除。(已在 https://github.com/mozillazg/pinyin-data/issues/55 反饋。) ↩ -
在本次運行途中,遇到了一個不常見的 bug:模型不知爲何開始輸出同一個字符「聽」,繼續約三十個後被 ollama 強制中止。由於內容被中途截斷,不符合 JSON 格式,目前的程序暫未攷慮這一情形,因而報異常並退出,故
openthinker:32b在處理含有樂的詞語時分了兩次跑完。該例當作標註錯誤來計算。 ↩ -
在實驗所用的 pypinyin 0.54.0 中,「放大率」會被錯誤轉換爲
fàng dà shuài,因此從計算中排除。(此爲 pypinyin 內置數據的 bug,已通過 https://github.com/mozillazg/phrase-pinyin-data/pull/56 修復。) ↩ -
關於「率更」之「率」,儘管《康熙字典》將其記於「劣戌切,音律」之下(對應現代讀音
lǜ),但從字義上似乎讀作shuài更爲合理。因此也於計算中排除該詞。 ↩ -
中文常譯爲「公有領域」或「公衆領域」。 ↩
-
自由許可證通常定義爲在使用、修改、複製分發原作、分享經過修改或衍生的作品這四個方面授予使用者自由的許可證。自由許可證可以附加一些與上述自由不衝突的條件或聲明,例如署名/姓名標示(attribution)要求等。特別地,有些自由許可證要求在分享經過修改或衍生的作品時,也必須以同樣或類似的許可證進行,從而使得這些自由可以傳遞下去,這樣的自由許可證稱爲 copyleft 許可證;而另一些則無此附加要求,稱爲寬鬆許可證。 ↩
-
https://jillianbommarito.com/train-llm-cc-by-sa/ 這篇雖然主要分析 CC BY-SA(屬於 copyleft 許可證),但關於署名/姓名標示條款的討論同樣適用於寬鬆許可證。其中提到此問題的一種可能的解決思路:有署名要求的作品不用作訓練數據,只作爲 RAG 數據庫使用。 ↩
-
有名的兼容性條款例子:CC BY-SA 4.0 允許衍生作品在 GPLv3 下發佈,因此,可以將以 CC BY-SA 4.0 授權的作品 A 和以 GPLv3 授權的作品 B 整合爲一件新作品,並在 GPLv3 下發佈。 ↩