督情感分析實(shí)戰(zhàn):Stacking框架與弱標(biāo)簽生成全流程)
簡(jiǎn)介這是一份基于Stacking框架的弱監(jiān)督深度學(xué)習(xí)情感分析研究算法項(xiàng)目面向計(jì)算機(jī)相關(guān)專業(yè)學(xué)生及算法研究人員。項(xiàng)目以Python完整源碼為主體涵蓋LSTM、CNN、RNN、樸素貝葉斯、SVM等多種模型的獨(dú)立實(shí)現(xiàn)并在此基礎(chǔ)上結(jié)合Stacking集成策略完成弱監(jiān)督情感分類實(shí)驗(yàn)適合用作課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或算法對(duì)比研究的參考范本。資源共包含9個(gè)文件主要由6個(gè)Python源碼腳本、2個(gè)情感語(yǔ)料Excel數(shù)據(jù)表和1個(gè)Markdown說(shuō)明文檔構(gòu)成多個(gè)模型腳本可單獨(dú)運(yùn)行與對(duì)比正負(fù)情感樣本數(shù)據(jù)便于直接開展實(shí)驗(yàn)驗(yàn)證README文檔提供項(xiàng)目結(jié)構(gòu)與使用方法說(shuō)明整體包體積約994KB結(jié)構(gòu)清晰易上手。目前已有73人學(xué)習(xí)下載通過(guò)該資源可獲取完整可運(yùn)行的情感分析模型代碼、Stacking集成學(xué)習(xí)實(shí)現(xiàn)思路、數(shù)據(jù)預(yù)處理與實(shí)驗(yàn)對(duì)照方法對(duì)理解弱監(jiān)督學(xué)習(xí)與多模型融合具有不錯(cuò)的實(shí)戰(zhàn)參考價(jià)值。1. 弱監(jiān)督深度學(xué)習(xí)情感分析為什么 Stacking 框架值得先試情感分析在實(shí)際業(yè)務(wù)里最缺的從來(lái)不是模型而是標(biāo)注數(shù)據(jù)。一個(gè)電商評(píng)論項(xiàng)目從立項(xiàng)到能用往往一半時(shí)間耗在讓人工標(biāo) 3 萬(wàn)條正負(fù)樣本上標(biāo)完還常發(fā)現(xiàn)標(biāo)注員之間對(duì)“中評(píng)算正還是算負(fù)”吵了半個(gè)月。弱監(jiān)督深度學(xué)習(xí)的思路是先不急著雇人用情感詞典、規(guī)則模板、平臺(tái)自帶的點(diǎn)贊踩數(shù)這類廉價(jià)信號(hào)把訓(xùn)練集“粗標(biāo)”出來(lái)再用模型去擬合。代價(jià)是標(biāo)簽噪聲大單模型訓(xùn)練到后期幾乎必然過(guò)擬合噪聲表現(xiàn)為驗(yàn)證集震蕩、類別偏斜。Stacking 框架在這條路上恰好能補(bǔ)位它把多個(gè)基學(xué)習(xí)器的輸出拿去做第二層訓(xùn)練讓元學(xué)習(xí)器學(xué)會(huì)“誰(shuí)的話在哪個(gè)區(qū)間更可信”。這套方案適合手里有大量無(wú)標(biāo)注文本、預(yù)算有限、又想盡快跑通情感分類基準(zhǔn)線的團(tuán)隊(duì)。下面按一條完整可復(fù)現(xiàn)的路徑展開從基學(xué)習(xí)器選型講到弱標(biāo)簽生成再到 Stacking 元特征構(gòu)造和避坑。2. 基學(xué)習(xí)器搭建TextCNN 與 BiLSTM 為什么是弱監(jiān)督下的主力2.1 弱監(jiān)督下選基學(xué)習(xí)器先看穩(wěn)定性和訓(xùn)練速度不少人在弱監(jiān)督場(chǎng)景里上來(lái)就上 BERT理由是準(zhǔn)確率高。但弱標(biāo)簽訓(xùn)練的實(shí)踐中BERT 這類超大模型擬合噪聲的速度比小模型快得多訓(xùn)練成本高還容易讓模型記住錯(cuò)誤標(biāo)簽。而情感分析任務(wù)里真正穩(wěn)定的提升來(lái)源往往是詞序、否定結(jié)構(gòu)、程度副詞這些局部特征。TextCNN 用多尺寸卷積核抓局部短語(yǔ)BiLSTM 保留詞序信息兩個(gè)模型行為差異大恰好能讓第二層 Stacking 獲得互補(bǔ)的預(yù)測(cè)分布。何況文本長(zhǎng)度通常被截?cái)嘣?128 到 256 之間兩個(gè)模型在一張消費(fèi)級(jí) GPU 上訓(xùn)練都只需要分鐘級(jí)迭代快適合弱監(jiān)督這種“多發(fā)實(shí)驗(yàn)”的場(chǎng)景。2.2 先搭 TextCNN輕量、穩(wěn)、適合第一批弱標(biāo)簽樣本第一個(gè)基學(xué)習(xí)器我一般用 TextCNN因?yàn)樗?xùn)練快、收斂穩(wěn)在短文本情感分析里即使面對(duì)弱標(biāo)簽也能抓住“難吃”“太慢”“差評(píng)”這類局部短語(yǔ)。PyTorch 實(shí)現(xiàn)如下import torch import torch.nn as nn class TextCNN(nn.Module): def __init__(self, vocab_size, embed_dim100, num_filters128, kernel_sizes(2, 3, 4), num_labels3, dropout0.3): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim, padding_idx0) # 多尺寸卷積核并行提取 2-gram、3-gram、4-gram 局部特征 self.convs nn.ModuleList([ nn.Conv1d(embed_dim, num_filters, k, paddingk // 2) for k in kernel_sizes ]) self.dropout nn.Dropout(dropout) self.classifier nn.Linear(num_filters * len(kernel_sizes), num_labels) def forward(self, tokens): emb self.embedding(tokens).permute(0, 2, 1) # B, embed_dim, L feats [] for conv in self.convs: h torch.relu(conv(emb)) h torch.max_pool1d(h, h.size(2)).squeeze(2) feats.append(h) return self.classifier(self.dropout(torch.cat(feats, dim1)))這段代碼里有三個(gè)參數(shù)值得重點(diǎn)說(shuō)明。kernel_sizes(2, 3, 4)是短文本情感分析最常見(jiàn)的配置覆蓋二字詞、三字短語(yǔ)到四字固定搭配num_filters128在弱標(biāo)簽場(chǎng)景下不需要調(diào)得太大過(guò)大反而更容易記住噪聲padding_idx0配合輸入序列統(tǒng)一補(bǔ)零讓 padding 位置不參與訓(xùn)練。訓(xùn)練時(shí)交叉熵配合weight_decay加到 Adam 優(yōu)化器里常用配置是lr1e-3, weight_decay1e-4每輪結(jié)束看驗(yàn)證集準(zhǔn)確率連續(xù)兩輪不升就把學(xué)習(xí)率降一半。2.3 再搭 BiLSTM補(bǔ)上順序和長(zhǎng)距離依賴TextCNN 對(duì)詞序不敏感“我喜歡這個(gè)產(chǎn)品但不會(huì)復(fù)購(gòu)”這類句子在 CNN 眼里可能是兩個(gè)獨(dú)立短語(yǔ)的簡(jiǎn)單拼接而 BiLSTM 能按順序建模轉(zhuǎn)折結(jié)構(gòu)。實(shí)際落地時(shí)不要單獨(dú)用 LSTM 當(dāng)主力訓(xùn)練速度慢且容易漂移但作為 Stacking 的第二個(gè)基學(xué)習(xí)器效果很好class BiLSTMAtt(nn.Module): def __init__(self, vocab_size, embed_dim100, hidden_dim128, num_labels3, dropout0.3): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim, padding_idx0) self.lstm nn.LSTM(embed_dim, hidden_dim, batch_firstTrue, bidirectionalTrue) self.att nn.Linear(hidden_dim * 2, 1) # 注意力打分 self.dropout nn.Dropout(dropout) self.classifier nn.Linear(hidden_dim * 2, num_labels) def forward(self, tokens): out, _ self.lstm(self.embedding(tokens)) # B, L, 2H att_w torch.softmax(self.att(out).squeeze(-1), dim1) # 注意力加權(quán)求和把整句壓縮成一個(gè)向量 ctx torch.bmm(out.transpose(1, 2), att_w.unsqueeze(-1)).squeeze(-1) return self.classifier(self.dropout(ctx))注意這里hidden_dim128指的是單向隱藏維度雙向拼接后是 256。注意力機(jī)制的作用不是提升弱標(biāo)簽下的絕對(duì)準(zhǔn)確率而是讓模型在長(zhǎng)句里不容易被某個(gè)強(qiáng)情感詞帶偏這一點(diǎn)在 Stacking 里面表現(xiàn)為預(yù)測(cè)概率分布更平滑。訓(xùn)練時(shí) LSTM 收斂比 CNN 慢通常需要多跑 3 到 5 個(gè) epoch 才能穩(wěn)定所以弱監(jiān)督訓(xùn)練中我會(huì)先跑完 TextCNN再用它的預(yù)測(cè)結(jié)果作為 LSTM 的初始偽標(biāo)簽輔助。BiLSTM 對(duì)學(xué)習(xí)率更敏感常見(jiàn)做法是把學(xué)習(xí)率降到 CNN 的一半即lr5e-4。2.4 第三個(gè)視角加一個(gè)“非深度”基學(xué)習(xí)器提升堆疊多樣性Stacking 的收益來(lái)源不是單個(gè)模型有多準(zhǔn)而是元學(xué)習(xí)器能看到不同模型的“分歧”。很多實(shí)踐里只堆兩個(gè)深度模型效果和直接平均差不多。我一般會(huì)加入第三個(gè)基學(xué)習(xí)器邏輯回歸配合 TF-IDF 特征。這類線性模型在短文本上往往不比深度模型差多少而且它對(duì)詞頻的感知方式完全不同深度模型學(xué)的是分布式表征線性模型學(xué)的是稀疏命中。第三路預(yù)測(cè)概率進(jìn)入 Stacking 后元學(xué)習(xí)器能學(xué)到“當(dāng) CNN 和 LSTM 都猶豫時(shí)樸素線性模型的判斷更可信”這樣的規(guī)則。這個(gè)視角在弱監(jiān)督場(chǎng)景下尤其好用因?yàn)?TF-IDF 不會(huì)被 embedding 層放大噪聲。3. 弱標(biāo)簽生成三個(gè)廉價(jià)信號(hào)來(lái)源與置信度校準(zhǔn)3.1 情感詞典打分是弱監(jiān)督的起點(diǎn)但別直接當(dāng)硬標(biāo)簽弱監(jiān)督的第一步不是訓(xùn)練模型而是造標(biāo)簽。最常見(jiàn)也最可控的來(lái)源是通用情感詞典把帶極性分?jǐn)?shù)的詞表加載進(jìn)來(lái)對(duì)每條文本分詞后累加分?jǐn)?shù)。這一步在開源分詞工具配合下很容易實(shí)現(xiàn)import jieba import torch def weak_label(text_list, lexicon, negation_words(不, 沒(méi), 別)): scores [] for sent in text_list: words jieba.lcut(sent) raw sum(lexicon.get(w, 0.0) for w in words) # 否定詞翻轉(zhuǎn)例如“不難吃”整體極性由負(fù)轉(zhuǎn)正 if any(nw in words for nw in negation_words): raw -raw scores.append(raw) scores torch.tensor(scores) pos scores 0.3 neg scores -0.3 neutral ~(pos | neg) labels torch.where(pos, 1, torch.where(neg, -1, 0)).numpy() return labels, scores.numpy()這里有個(gè)新手最容易翻車的點(diǎn)把詞典得分直接當(dāng)作硬標(biāo)簽使用。實(shí)際情感詞在語(yǔ)境里有程度差異“還不錯(cuò)”和“太好了”得分可能一樣但置信度差很遠(yuǎn)。代碼里的labels只是輔助信號(hào)真正訓(xùn)練時(shí)要額外把scores歸一化后作為樣本權(quán)重傳進(jìn)損失函數(shù)讓得分高的樣本對(duì)梯度影響更大。閾值 0.3 是經(jīng)驗(yàn)初值后續(xù)要用小規(guī)模人工標(biāo)注校準(zhǔn)。3.2 表情符號(hào)和點(diǎn)贊數(shù)據(jù)是第二個(gè)信號(hào)源召回勝過(guò)精度詞典覆蓋不了口語(yǔ)化表達(dá)比如“哈哈哈哈”和“裂開”在詞典里可能完全沒(méi)有。這時(shí)可以用平臺(tái)側(cè)的弱信號(hào)帶正面表情符號(hào)的評(píng)論推定為正負(fù)面表情符號(hào)推定為負(fù)有大量點(diǎn)踩的負(fù)面行為數(shù)據(jù)也可以用但這類信號(hào)偏斜嚴(yán)重更適合做召回而不是精標(biāo)注。做法是把這批樣本單獨(dú)放在一個(gè) DataFrame 里不并入詞典標(biāo)出的樣本而是作為“高置信候選集”的一部分等 embedding 模型訓(xùn)完第一輪后再通過(guò)預(yù)測(cè)概率篩選加入。這個(gè)做法本質(zhì)上是從弱監(jiān)督平滑過(guò)渡到偽標(biāo)簽自訓(xùn)練。3.3 用 200 條人工標(biāo)注做閾值校準(zhǔn)讓弱標(biāo)簽分布和真實(shí)分布對(duì)齊弱監(jiān)督方案能不能用取決于生成的標(biāo)簽分布和真實(shí)標(biāo)簽分布有多接近。常見(jiàn)做法是人工標(biāo)注 200 條樣本畫一條閾值 vs 精確率的曲線閾值調(diào)大保留的樣本更準(zhǔn)但更少閾值調(diào)小樣本多了但噪聲變大。實(shí)操中我通常標(biāo)三份各 200 條一份來(lái)自純?cè)~典規(guī)則一份來(lái)自表情符來(lái)源一份是隨機(jī)抽樣跑通流程后的預(yù)測(cè)結(jié)果分別觀察它們?cè)诓煌撝迪碌木_率和召回率。多數(shù)時(shí)候 0.3 到 0.5 之間是甜區(qū)低于 0.2 的弱標(biāo)簽噪聲會(huì)讓 Stacking 上層的元學(xué)習(xí)器學(xué)到虛假模式高于 0.8 則樣本量不夠基學(xué)習(xí)器欠擬合。3.4 弱標(biāo)簽生成后必須檢查類別分布穩(wěn)定性弱監(jiān)督信號(hào)常常自帶分布偏差電商評(píng)論里純粹的中性句很少但規(guī)則引擎會(huì)把大量“發(fā)貨很快但質(zhì)量一般”判成中性因?yàn)檎?fù)分?jǐn)?shù)抵消。這時(shí)候類別比例看起來(lái)合理實(shí)際是錯(cuò)誤抵消的假象。我的習(xí)慣是每輪生成弱標(biāo)簽后打印三件事類別占比、每類平均得分方差、詞典未命中率。未命中率超過(guò) 40% 說(shuō)明當(dāng)前詞典已經(jīng)撐不住這個(gè)領(lǐng)域的表達(dá)需要補(bǔ)充領(lǐng)域詞或增加新信號(hào)源。4. Stacking 框架實(shí)操用交叉驗(yàn)證生成 OOF 特征避免自樣本泄漏4.1 Stacking 在弱監(jiān)督里的定位不是堆模型而是學(xué)分歧很多人對(duì) Stacking 的理解停留在“把多個(gè)模型的預(yù)測(cè)結(jié)果平均一下”這其實(shí)是 Bagging 的思路。Stacking 的核心差異是第二層有一個(gè)可訓(xùn)練模型它學(xué)習(xí)的輸入是基學(xué)習(xí)器在樣本上的預(yù)測(cè)概率輸出是最終標(biāo)簽。弱監(jiān)督場(chǎng)景下基學(xué)習(xí)器各自學(xué)到不同的錯(cuò)誤模式元學(xué)習(xí)器如果能把“模型 A 給 0.7、模型 B 給 0.2 時(shí)更可能是噪聲”這樣的條件概率學(xué)出來(lái)整體效果就會(huì)比任何單一模型都穩(wěn)。但這一切的前提是元學(xué)習(xí)器的輸入特征必須來(lái)自交叉驗(yàn)證否則基學(xué)習(xí)器看過(guò)訓(xùn)練標(biāo)簽后給出的概率完全失真。4.2 五折 OOF 特征生成Stacking 的嫡系飯票每個(gè)基學(xué)習(xí)器都要先在自己的訓(xùn)練折上訓(xùn)練再對(duì)驗(yàn)證折預(yù)測(cè)。這樣每個(gè)樣本獲得的預(yù)測(cè)概率都來(lái)自一個(gè)從未見(jiàn)過(guò)它的模型元學(xué)習(xí)器看到的就不帶自樣本樂(lè)觀偏差。代碼如下import numpy as np from sklearn.model_selection import StratifiedKFold from sklearn.linear_model import LogisticRegression def build_oof(estimator, X, y, n_fold5, seed42): skf StratifiedKFold(n_splitsn_fold, shuffleTrue, random_stateseed) oof np.zeros((len(X), 3)) for tr_idx, va_idx in skf.split(X, y): model estimator # 每個(gè) fold 需要重新初始化 fold_model clone(estimator) fold_model.fit(X.iloc[tr_idx], y[tr_idx]) oof[va_idx] fold_model.predict_proba(X.iloc[va_idx]) return oof注意代碼里有兩個(gè)隱藏細(xì)節(jié)。第一clone(estimator)不是裝飾品如果直接把同一個(gè)模型對(duì)象放到循環(huán)里前面折訓(xùn)練的權(quán)重會(huì)被后面折覆蓋最終五折預(yù)測(cè)全部來(lái)自最后一次訓(xùn)練結(jié)果OOF 徹底失效。第二分層五折的前提是弱標(biāo)簽三類都有足夠樣本如果某一類少于 50 條不要強(qiáng)行分層改用StratifiedKFold會(huì)報(bào)錯(cuò)或產(chǎn)生空折這時(shí)先做下采樣或過(guò)采樣再進(jìn) OOF 流程。4.3 元特征不止預(yù)測(cè)概率加入置信度和文本統(tǒng)計(jì)特征元學(xué)習(xí)器的輸入不局限于基學(xué)習(xí)器的三分類概率。我常用的元特征分三組第一組是 CNN、LSTM、線性模型的預(yù)測(cè)概率向量共 9 維第二組是當(dāng)前樣本弱標(biāo)簽置信度得分和詞典得分這兩個(gè)數(shù)字告訴元學(xué)習(xí)器原始信號(hào)的可信度第三組是文本長(zhǎng)度、否定詞個(gè)數(shù)、情感詞命中數(shù)。這些特征組合起來(lái)后元學(xué)習(xí)器能學(xué)到“文本很短且情感詞密集時(shí)深度模型更準(zhǔn)文本很長(zhǎng)時(shí)注意力 LSTM 的輸出更值得參考”這類規(guī)則。把特征拼好后第二層模型我一般選帶 L2 正則的邏輯回歸因?yàn)樵卣骶S度低、噪聲標(biāo)簽仍然存在過(guò)于復(fù)雜的 GBDT 反而容易過(guò)擬合meta_features np.hstack([ oof_cnn, # 3 列 oof_lstm, # 3 列 oof_lr, # 3 列 senti_score.reshape(-1, 1), # 詞典置信度 neg_count.reshape(-1, 1), # 否定詞數(shù)量 text_len.reshape(-1, 1), # 文本長(zhǎng)度 ]) meta_clf LogisticRegression(C0.5, max_iter1000) meta_clf.fit(meta_features, y)C0.5的意思是正則強(qiáng)度適中。弱標(biāo)簽場(chǎng)景下元學(xué)習(xí)器面對(duì)的特征本身已經(jīng)是從帶噪標(biāo)簽里提煉出來(lái)的正則太弱會(huì)把基學(xué)習(xí)器的系統(tǒng)性偏差學(xué)進(jìn)最終預(yù)測(cè)正則太強(qiáng)又退化成簡(jiǎn)單平均。max_iter1000沒(méi)有必要改邏輯回歸在這個(gè)特征維度下幾百輪就能收斂。上線階段直接調(diào)用meta_clf.predict_proba即可基學(xué)習(xí)器的預(yù)測(cè)也要走完全相同的預(yù)處理流程這一步在工程上最容易漏。4.4 訓(xùn)練一個(gè)強(qiáng)基學(xué)習(xí)器和弱基學(xué)習(xí)器不如五個(gè)中等模型歧見(jiàn)是 Stacking 的核心但實(shí)踐里有個(gè)誤區(qū)把五個(gè)結(jié)構(gòu)幾乎相同的模型當(dāng)五個(gè)基學(xué)習(xí)器只是改了隨機(jī)種子結(jié)果差別極小。真正有效的是結(jié)構(gòu)差異大的組合比如 TextCNN、BiLSTM、TF-IDF 線性模型之外再加一個(gè)基于詞向量的平均池化模型它計(jì)算的是整句語(yǔ)義的“重心”和 CNN、LSTM 的行為模式完全不同。五個(gè)中等準(zhǔn)確率模型堆出來(lái)的 Stacking在弱標(biāo)簽上往往超過(guò)兩個(gè) 90 分模型的簡(jiǎn)單集成這個(gè)結(jié)論在多次實(shí)驗(yàn)里都很穩(wěn)定。5. 避坑清單弱監(jiān)督 Stacking 最容易翻車的四個(gè)細(xì)節(jié)5.1 模型記住了噪聲表現(xiàn)為訓(xùn)練集準(zhǔn)確率 97%驗(yàn)證集跌回 70%這是弱監(jiān)督任務(wù)里最常見(jiàn)的現(xiàn)象。原因是弱標(biāo)簽本身有系統(tǒng)性偏差比如詞典把“質(zhì)量堪憂”判為負(fù)、模型確實(shí)學(xué)到了這個(gè)規(guī)則但在真實(shí)驗(yàn)證集上“質(zhì)量堪憂”可能被人工標(biāo)成了中性。解決辦法是先別急著換模型結(jié)構(gòu)回到弱標(biāo)簽生成環(huán)節(jié)看置信度分布。把低置信度樣本篩掉一部分再訓(xùn)比任何正則化都有效。另一個(gè)補(bǔ)救是給低置信度樣本降低損失權(quán)重我用過(guò)sample_weight 0.5 abs(senti_score) / max_score效果比單純刪樣本平滑。5.2 五折 OOF 之后直接復(fù)用了全部數(shù)據(jù)訓(xùn)練基學(xué)習(xí)器Stacker 驗(yàn)證分?jǐn)?shù)虛高現(xiàn)象是 Stacking 的驗(yàn)證分?jǐn)?shù)很高上線后立刻掉幾個(gè)百分點(diǎn)。原因是 OOF 只是元特征生成階段用了五折拿到 OOF 后有人順手用全量數(shù)據(jù)重新訓(xùn)練了一份基學(xué)習(xí)器再用這份全量模型去生成測(cè)試集特征。這不影響 OOF 自身但會(huì)讓 Stacker 見(jiàn)到的訓(xùn)練特征和生成特征的方式不一致。規(guī)范做法是保留五折模型測(cè)試集推理時(shí)把五個(gè)模型的結(jié)果取平均或直接做第五折預(yù)測(cè)這兩種方法都行但千萬(wàn)別混合使用。5.3 弱標(biāo)簽里正負(fù)樣本比例嚴(yán)重失調(diào)Stacker 輸出了“永遠(yuǎn)預(yù)測(cè)多數(shù)類”弱監(jiān)督生成階段經(jīng)常出現(xiàn)正類樣本占比 80% 以上?;鶎W(xué)習(xí)器對(duì)這種分布學(xué)到的概率本身就偏向正類三個(gè)模型概率疊加后元學(xué)習(xí)器即使什么都不學(xué)預(yù)測(cè)正類也能拿高準(zhǔn)確率。解決方式是做兩層校準(zhǔn)。第一層是在基學(xué)習(xí)器階段用類別加權(quán)損失torch.nn.CrossEntropyLoss(weighttorch.tensor([1.0, 1.5, 2.0]))第二層是在 Stacker 訓(xùn)練前對(duì)元特征做標(biāo)準(zhǔn)化。注意此時(shí)不要在 Stacker 里再放開類別權(quán)重元學(xué)習(xí)器只需要學(xué)到基學(xué)習(xí)器輸出到真實(shí)標(biāo)簽的映射二次加權(quán)反而引入新的偏斜。5.4 把 OOF 特征保存了但丟了歸一化參數(shù)第二天評(píng)估時(shí)整條鏈路報(bào)錯(cuò)又定位不到這是工程踩坑。弱標(biāo)簽方案里元特征里的文本長(zhǎng)度、詞典得分量綱差異大有些實(shí)現(xiàn)會(huì)對(duì)元特征做 StandardScaler。如果只在訓(xùn)練時(shí) fit推理時(shí)沒(méi)保存 scaler 對(duì)象線上接口接收到的特征全是原始量綱Stacker 預(yù)測(cè)結(jié)果直接失真。因?yàn)閳?bào)錯(cuò)不會(huì)出現(xiàn)模型還能跑掩蓋了問(wèn)題。我的習(xí)慣是把 scaler 和 meta_clf 一起存進(jìn)同一個(gè) joblib 文件文件名里標(biāo)注生成日期和弱標(biāo)簽版本確保特征處理鏈路是同一個(gè)版本。這是弱監(jiān)督 Stacking 項(xiàng)目里最不起眼卻又最值得養(yǎng)成習(xí)慣的地方。6. 上線前的最后驗(yàn)證用小樣本人工標(biāo)注把整套系統(tǒng)拽回來(lái)6.1 給整套系統(tǒng)造一批“底火”測(cè)試集弱監(jiān)督項(xiàng)目的驗(yàn)收不能只看 Stacking 在弱標(biāo)簽上的分?jǐn)?shù)因?yàn)槟桥鷺?biāo)簽本身就是系統(tǒng)自己生成的循環(huán)驗(yàn)證沒(méi)有說(shuō)服力。我會(huì)額外人工標(biāo)注 500 條樣本覆蓋正、負(fù)、中性三種分布和線上真實(shí)比例相近。把這 500 條放進(jìn)評(píng)估流程后分別對(duì)三個(gè)基學(xué)習(xí)器和 Stacker 計(jì)算混淆矩陣重點(diǎn)關(guān)注“中性被分到正類”和“負(fù)類被分到中性”這兩類錯(cuò)因?yàn)樗鼈冊(cè)跇I(yè)務(wù)里代價(jià)完全不同。觀察 Stacker 相對(duì)最佳單模型是否真的有提升如果只提升 0.5 個(gè)百分點(diǎn)以內(nèi)說(shuō)明基學(xué)習(xí)器之間的互補(bǔ)性不強(qiáng)這時(shí)候與其堆模型不如回去補(bǔ)弱標(biāo)簽質(zhì)量。6.2 逐條檢查失敗樣本確認(rèn)弱監(jiān)督的收益來(lái)自哪一層我會(huì)從評(píng)估集里挑出真實(shí)標(biāo)簽是負(fù)、但弱標(biāo)簽給成了正的樣本看它們?cè)谀膸讉€(gè)模型上判斷錯(cuò)誤。這類樣本通常包含反諷句比如“真不錯(cuò)三天就壞了”詞典得分會(huì)被“不錯(cuò)”帶成正分三個(gè)基學(xué)習(xí)器可能都被騙Stacker 也沒(méi)有救回來(lái)。這種失敗說(shuō)明當(dāng)前弱信號(hào)里缺少反諷檢測(cè)不是 Stacking 能解決的問(wèn)題考慮加反諷句式模板到弱標(biāo)簽生成階段更有效。反過(guò)來(lái)如果 Stacker 能在某個(gè)模型錯(cuò)、某個(gè)模型對(duì)的樣本上做出正確選擇就說(shuō)明這一層確實(shí)學(xué)到了有用的條件關(guān)系這套方案就值得繼續(xù)投入。我的習(xí)慣是每次調(diào)完參數(shù)都把失敗樣本存成一個(gè) CSV按類型分組。幾輪迭代之后回看往往發(fā)現(xiàn)真正拖后腿的不是模型而是弱標(biāo)簽來(lái)源。這一套流程走下來(lái)弱監(jiān)督加 Stacking 的組合能幫你用很少的人工標(biāo)注把情感分析基線跑到可接受水平后續(xù)再逐步加入更高質(zhì)量的標(biāo)注數(shù)據(jù)替換弱標(biāo)簽?zāi)P瓦€能繼續(xù)漲點(diǎn)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取