Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
189 lines
10 KiB
Markdown
189 lines
10 KiB
Markdown
# 方法細節
|
||
|
||
(全文方法節底稿。演算法在執行前寫定;任何修訂記入
|
||
`decision-log.md`。定義檔全文見 `prompts/`,執行紀錄見
|
||
`runs/`。)
|
||
|
||
## 自然編碼管線總覽
|
||
|
||
三個步驟:步驟 1 自由標註(兩次執行進池)→ 步驟 2 詞彙表
|
||
建構(詞向量分群,確定性)→ 步驟 3 全量編碼(三次執行+
|
||
多數決)。歌詞只出現在步驟 1 與步驟 3;步驟 2 完全不接觸
|
||
歌詞,也不呼叫 LLM。設計原則見 `research-plan.md`;本檔
|
||
記載可重現的演算法細節。
|
||
|
||
編號的所指為**研究程序的工序**,不是定義檔:步驟 1 與
|
||
步驟 3 有定義檔(`prompts/`),步驟 2 沒有——它是單一
|
||
確定性計算,由 `cluster-keywords` 一個子命令完成。有無
|
||
定義檔的區別即「該步是否為 LLM 判斷」,由 `prompts/` 是
|
||
否存在同號檔案直接可見。
|
||
|
||
## 步驟 2 詞彙表建構——詞向量分群
|
||
|
||
詞彙表由確定性程序產生,不經 LLM。完整分割(每個關鍵字
|
||
恰屬一組、不遺漏、不新增)由演算法結構保證,無須事後
|
||
驗證。
|
||
|
||
### 進池
|
||
|
||
兩次標註執行的全部關鍵字取聯集、逐字串精確去重、字典序
|
||
排列。失敗與拒答的記錄跳過(其歌曲不貢獻關鍵字);解析
|
||
時偵測重複鍵,違規即失敗。
|
||
|
||
### 分群
|
||
|
||
- **嵌入**:`sentence-transformers/all-mpnet-base-v2`
|
||
(釘定 revision),關鍵字的連字號先還原為空格再編碼,
|
||
輸出 768 維向量並 L2 正規化。
|
||
- **分群**:階層式聚合分群(Ward linkage),k=100。
|
||
向量既已正規化,歐氏距離與餘弦相似度單調對應;三種
|
||
linkage 實測比較,Ward 於各個 k 的組內一致性均最高
|
||
(average 與 complete 皆產生吞噬半數語料的巨大異質
|
||
組)。
|
||
- **組數的取捨**:k 太小則壓縮比過高,樹上層被迫併入
|
||
不相干的詞,組雖大而無主題(k=30 最大組 491 詞、
|
||
組內一致性 0.41,成員橫跨籃球、海灘、外星人綁架);
|
||
k 太大則人工難以通覽。定於 100,理由是實測顯示雜物櫃
|
||
組於此始裂解為有主題的組,且編碼實測未見碼數過多的
|
||
副作用(詞彙表外的碼歸零、僅一個碼零使用)。
|
||
- **組名**:取 medoid——與該組中心(成員向量均值後
|
||
正規化)餘弦相似度最高的成員詞。組名因此必為模型
|
||
自己產出過的關鍵字,非任何人事後撰寫。已知限制:
|
||
組越大越異質時,medoid 只是折衷詞,可能代表不了組內
|
||
內容(實測 `mutual-individuality` 組內一致 0.70 而
|
||
編碼從未使用);此類碼於結果中呈現為零使用,據實
|
||
報告,不事後改名。
|
||
- **取捨紀錄**:曾以 LLM 單發收斂(merge/cap 兩步)
|
||
實作本步,四種模型六次執行全部無法維持完整分割,
|
||
已棄用(詳見 `decision-log.md` 2026-08-05;棄用的
|
||
定義檔止於 git 歷史,見 `git log -- prompts/`)。
|
||
- **產物**:五份,前綴分別標示來源與結果。
|
||
`source-keywords.txt`(進池後的關鍵字,一行一個)
|
||
記錄進來的是什麼;`result-keywords.txt`(組名,一行
|
||
一個)與 `groups.csv`(欄位 Group、Keyword,一列一個
|
||
成員)記錄算出來的分割;`keywords-to-merge.json`
|
||
(`{"keywords": [...]}`)是實際交給模型的碼,即組名
|
||
加上先驗主題詞——五份中只有這一份含研究者的介入。
|
||
`meta.json` 記錄執行本身:進池的兩份執行歸檔與其有效
|
||
筆數、嵌入模型與釘定 revision、分群參數與組數、外加
|
||
的先驗詞、關鍵字總數,以及產生數字的套件版本。凡命令
|
||
列上的選擇與環境事實皆在此,不記時間戳與輸入雜湊
|
||
——前者使同環境重跑逐位元組可再生,後者只會重述 git
|
||
已保證的事。
|
||
- **可重現性**:同一輸入、同一釘定模型、同一參數逐次
|
||
重現。不同 CPU/BLAS 實作的浮點尾數差異可能使邊界
|
||
詞的歸屬翻動,屬已揭露的限制;論文所用碼表逐字
|
||
commit,引用單位為該份定案檔案。
|
||
|
||
### women-power 的注入
|
||
|
||
定案詞彙表為 100 個分群組名再加上 `women-power` 一詞,
|
||
共 101 個碼。`women-power` 是研究者任意決定的先驗主題(即本
|
||
論文的主題本身),不由資料產生,屬揭露的儀器介入。該詞
|
||
於執行時以 `--extra-keyword` 明示加入,不寫死在程式裏
|
||
——研究者的介入因此每次都出現在重現命令上,而非無聲
|
||
發生;分群結果的兩份產物不含它,只有交給模型的碼表含
|
||
它。
|
||
|
||
注入而非另設篩選軌的理由:讓研究者的主題詞與模型自己
|
||
收斂出的類別(分群已自行長出 `female-empowerment` 等組)
|
||
在同一份提示詞、同一個判斷體制下受檢,避免單目標提問
|
||
把該主題的顯著性人為抬高。兩者的落點差異本身即可報告
|
||
的結果。
|
||
|
||
## 步驟 3 編碼的三次執行與多數決
|
||
|
||
- **三次執行**:同一份定義檔、同一份輸入檔,獨立執行
|
||
三次,三份歸檔並列(`runs/03-code/run1`、`run2`、
|
||
`run3`),彼此無先後主從之別。
|
||
- **多數決**:一首歌的一個標籤,三次執行中至少兩次標出
|
||
即收入定案編碼。三票不平手,裁決規則因此無例外條款,
|
||
計票由確定性子命令完成(見交接契約)。
|
||
- **第三票取全量**:只對前兩次分歧的標籤補問第三票,
|
||
計票結果相同;仍採全量執行——全部歌曲、全部關鍵字
|
||
——使三票在同一條件下取得。
|
||
- **對邊緣標籤的作用**:兩次執行只分得出「兩次皆標」與
|
||
「僅一次標」;三次執行還分得出 3-0 與 2-1,故「定案
|
||
編碼中有多少比例僅以一票之差成立」成為可報告的量。
|
||
至於判定本身,兩次執行相左的標籤在何種協定下都由第三
|
||
個判斷定奪,票數不使不確定性消失:某標籤於單次執行被
|
||
標出的傾向若恰為一半,任何票數皆為擲幣。三票之效在
|
||
傾向偏離一半處——多數決將判定推向該傾向本身(單次
|
||
0.7 者為 0.78,0.9 者為 0.97),程序重跑的一致性因而
|
||
高於單次執行,唯獨恰半處無從改善。
|
||
|
||
## 女性力量候選集
|
||
|
||
候選集為兩類歌曲的合集:定案編碼含 `women-power` 者,
|
||
以及定案編碼含研究者指認之女性力量概念域分群組者。
|
||
指認於詞彙表定案後、黃金標準編碼開始前完成,指認清單
|
||
與理由記入決策日誌。
|
||
|
||
## 軌跡對映(診斷用)
|
||
|
||
沿收斂軌跡的機械對映:原始關鍵字 →(兩份標註執行歸檔的
|
||
`output.jsonl`)歌曲、原始關鍵字 →(分群)組,純程式查表,
|
||
決定性。以其結果與步驟 3 直接編碼的差異率作為「收斂軌跡
|
||
扭曲」的診斷量,不作主結果。
|
||
|
||
## 全管線的交接契約
|
||
|
||
每一步的輸出如何變成下一步的輸入,皆為確定性程序,規則
|
||
明定如下:
|
||
|
||
- **歌詞輸入檔(步驟 1)**:`export-llm-input` 自工作
|
||
儲存產出,每筆 `{"id": "song-<ID>", "content": <歌詞>}`,
|
||
依歌曲 ID 升序。步驟 3 的輸入由同一子命令、同一工作
|
||
儲存產出(見下),兩步的語料同一性由此成立;各步
|
||
輸入檔的 SHA-256 記入該步 meta。
|
||
- **步驟 1 → 2**:`cluster-keywords` 讀兩份執行歸檔的
|
||
`output.jsonl`(一律以換行字元 `\n` 切行——歌詞含
|
||
U+0085 等控制字元時,`str.splitlines()` 類的通用切行
|
||
會截斷 JSON 字串,實測踩中),進池後直接分群,一次
|
||
產出上列五份檔案。
|
||
- **步驟 2 → 3 輸入檔**:`export-llm-input --extras
|
||
<定案碼表>` 自工作儲存產出步驟 3 的輸入,每筆
|
||
`{"id": "song-<ID>", "content": <字串>}`,`content` 為
|
||
固定鍵序序列化的 `{"lyrics": …, "keywords": [...]}`,
|
||
依歌曲 ID 升序。碼表以參數傳入而非填進定義檔——定義
|
||
檔只規定任務形狀,換詞彙表、換演算法都不必改它。
|
||
- **步驟 3 定案**:`tally-codings <執行歸檔 1> <執行歸檔
|
||
2> <執行歸檔 3> <輸出 CSV>` 讀三份執行歸檔的
|
||
`output.jsonl`,逐首取標籤鍵集合(引述不參與計票)。
|
||
某首歌的某個標籤於三份中出現至少兩次即寫出一列,產出
|
||
`results/codings.csv`,欄位 `Song`、`Artist Credit`、
|
||
`Keyword`、`Quote`,一列一個標籤。歌名與演出者名銜
|
||
逐首查工作儲存取得,故本子命令須在 `build-db` 之後
|
||
執行。`Quote` 收該標籤在計票中的各份執行所給的歌詞
|
||
引述:各份的引述串接後逐字去重,按 Unicode 碼位排序,
|
||
以單一 `|` 相接(三份執行彼此無先後主從之別,引述之序
|
||
取決於引述本身)。列序依印出的前三欄依序排:歌名、
|
||
演出者名銜、標籤,一律以 Unicode 碼位比較,換行為
|
||
CRLF(同專案其他 CSV)。
|
||
- **序列化通則**:所有中間檔為 UTF-8,欄序、鍵序與元素
|
||
序皆依上列規則明定,無時間戳、無隨機成分;JSON 解析
|
||
一律偵測重複鍵,違規即失敗。人讀為主的產物採純文字或
|
||
CSV(CSV 依 RFC 4180,標題列字首大寫),機器交接檔採
|
||
JSON。給定相同的 LLM 執行輸出,全部交接產物逐位元組
|
||
可再生。
|
||
|
||
## 執行與稽核
|
||
|
||
- LLM 步驟以 `run-llm <定義檔> <輸入檔> <歸檔目錄>`
|
||
執行;一步的 N 次執行=重現命令清單上的 N 行命令,
|
||
各自歸檔(`runs/<步驟>/run1`、`run2`,編碼步驟另有
|
||
`run3`)。
|
||
- 確定性步驟(進池、分群、計票、對映)為子命令,其
|
||
輸入輸出檔同隨 `runs/` 歸檔;因無執行變異,歸檔目錄
|
||
下不分 `run<N>` 層。
|
||
- Batch API 的每筆請求自含全部脈絡且互不可見(平台
|
||
契約),歌與歌之間的獨立性由此成立;各次執行的獨立
|
||
性由「一次呼叫、一個批次、一份歸檔」的執行結構自明。
|
||
- 每次 `run-llm` 執行的 token 用量與費用記入
|
||
`run-costs.md`,被取代的執行一併保留供總支出核算。
|
||
|
||
## 映射分析方法
|
||
|
||
(依 2026-07-30 決策,於看到結果前寫定;待黃金標準
|
||
編碼展開前補入。)
|