當前位置:
首頁 > 知識 > 一次LDA的項目實戰

一次LDA的項目實戰

本文原載於知乎專欄「AI的怎怎,歪歪不喜歡」AI研習社經授權轉載發布。歡迎關注鄒佳敏的知乎專欄及AI研習社博客專欄(文末可識別社區名片直達)。

深度學習是一項目標函數的擬合技術,在絕大多數場景中,它要求實踐者擁有一份可靠的標註數據,作為目標函數的採樣,這恰恰是最難的部分。尤其是NLP領域,每個人的受教育水平和對語言的理解均有不同,一份可靠的標註數據更是難上加難。

因此,在缺乏標註數據,無法使用深度學習,甚至是傳統分類演算法的前提上,似乎只能考慮無監督的聚類方法來達成業務目標。

曾經的我非常鄙視聚類演算法,認為它不夠穩定。每一次聚類結果的含義都會發生變化,需要人工確認語義信息,尤其是當目標類型數過多時,非常痛苦。但和標註X萬篇語料數據,同時不確定標註是否可靠的情況相比,相信擁有完美數學邏輯的LDA,就成為了我的唯一選擇。

事實證明,在某些條件下,LDA簡直是NLP領域的聚類神器!

一, 項目背景:

財經類的「宏觀」新聞分類:以市場流動性,政經制度和地緣政治為例。

條件1:要求的目標類型少,數量可控。

二,項目實施:

1,語料確定:放棄通用語料的嘗試,將目光鎖定在,門戶網站財經欄目下的「宏觀」頁簽。

條件2:乾淨純粹的訓練數據集,輸入數據噪音小,便於在訓練前,對K心中有數。

(比如:已知目標3類,K選定為45,人工觀察後將45個topic_id映射至目標3類)

2,目標確定:結合業務背景,明確分類目標的業務含義。

2.1,市場流動性:市場貨幣投放,銀行間利率升降,央行放水,錢荒等;

2.2,政經制度:國改,混改,土改,稅改等政府發布的改革制度等;

2.3,地緣政治:軍事,打仗等。

條件3:分類目標間的內涵獨立。即類間耦合弱,類內耦合強的分類目標最優。

3,工具確定:分詞工具加入業務長詞或通用長詞,保證對聚類結果的可識別,易區分。

條件4:業務詞典或通用長詞詞典。構建通用長詞詞典的小技巧:將騰訊AILab的開源詞嵌入模型的單詞摳出,並篩選長詞,效果不錯。

三,GibbsLDA++代碼解讀

// 代碼截取自:GibbsLDA++ from http://gibbslda.sourceforge.net/

// 核心代碼解讀:LDA演算法代碼

classmodel{

public:

intM;// 語料中的文章數

intV;// 語料中的單詞數(去重)

intK;// LDA的主題數

doublealpha;// 超參數1:文章m屬於主題k的先驗概率

doublebeta;// 超參數2:單詞w屬於主題k的先驗概率

intniters;// LDA訓練迭代次數

double* p;// 臨時變數:每篇文章的每個單詞,在每次採樣時,分配到每個主題下的概率

int** z;// size M x doc.size():語料中第m篇文章中,第n個單詞,所屬的主題id

int** nw;// size V x K: 語料中第v個單詞,屬於第k個主題的單詞計數(在整個語料中,每個單詞在不同的文章出現)

int** nd;// size M x K:語料中第m篇文章,屬於第k個主題的單詞計數(在一篇文章中,每個單詞只屬於一個主題)

int* nwsum;// size K:屬於第k個主題的單詞個數

int* ndsum;// size M:屬於第m篇文章的單詞個數

// 隱層參數:M*V個參數 >> M*K+K*V個參數,降維的本質所在

double** theta;// size M x K:文檔-主題概率分布:語料中第m篇文章,屬於第k個主題的概率

double** phi;// size K x V:主題-單詞概率分布:語料中第v個單詞,屬於第k個主題的概率public:

// train初始化:載入輸入語料,為每個單詞隨機選取一個主題id,並初始化z,nw,nd,nwsum和ndsum變數(統計計數的方式)和其他變數(置零)

intinit_est();

// train核心邏輯:刪除非核心代碼,更清晰

voidestimate(){

// 從第last_iter處,開始訓練,兼容estc方法

// 比如,目標迭代1000次,但在第100次後保存模型,後續可直接載入模型,從第101次開始訓練)

intlast_iter = liter;

// 迭代niters次。每次迭代,遍歷全部語料(M篇文章,每篇文章length個單詞)

for(liter = last_iter +1; liter

// 對第m篇文章的第n個單詞,採樣其所屬的主題id,即z[m][n]

for(intm =; m

for(intn =; n docs[m]->length; n++) {

// 源碼注釋:LDA演算法介紹中,通常使用z_i來代表z[m][n]

// (z_i = z[m][n]) sample from p(z_i|z_-i, w)

// !!! Gibbs採樣的核心邏輯:為每篇文章的每個單詞,迭代採樣其屬於的topic,即主題id

inttopic = sampling(m, n);

// 更新z變數:LDA真正的模型輸出

// 因為z變數可以將nd,nw,ndsum和nwsum都還原出來,而theta和phi又可以從nd,nw,ndsum和nwsum還原

z[m][n] = topic;

}

}

}

// 根據nd,ndsum和alpha,計算theta變數:文檔-主題概率分布,無普適性,用於展示每篇文檔的主題概率

compute_theta();

// 根據nw,nwsum和beta,計算phi變數:主題-單詞概率分布,語料中每個單詞所屬的主題概率,有普適性,也可作為LDA模型輸出

compute_phi();

// 保存模型:在GibbsLDA++代碼中,最核心的是z變數,即*.tassign文件

save_model(utils::generate_model_name(-1));

}

// Gibbs採樣核心邏輯

intsampling(intm,intn){

// remove z_i from the count variables

inttopic = z[m][n];

intw = ptrndata->docs[m]->words[n];

// 新的一輪採樣前,自減上一次採樣的計數

nw[w][topic] -=1;

nd[m][topic] -=1;

nwsum[topic] -=1;

ndsum[m] -=1;

// 真正的採樣邏輯

doubleVbeta = V * beta;

doubleKalpha = K * alpha;

// 基於狄利克雷-多項分布的Gibbs採樣,千言萬語就化作這個簡單的公式,數學真是神奇!

// 建議參考資料:有先後順序

// 1,https://www.cnblogs.com/pinard/p/6831308.html

// 2,LDA數學八卦.pdf

for(intk =; k

// 神奇,神奇,神奇,神奇!

p[k] = (nw[w][k] + beta) / (nwsum[k] + Vbeta) *

(nd[m][k] + alpha) / (ndsum[m] + Kalpha);

}

// 根據已計算出的p,隨機挑出一個最優可能的主題id

// 一種常見的方法,在word2vec的負採樣中也有使用

for(intk =1; k

p[k] += p[k -1];

}

// 通過畫線段的方式,很容易理解:概率越大,所屬的線段越長,越有可能被隨機選中,但不絕對

doubleu = ((double)random() / RAND_MAX) * p[K -1];

for(topic =; topic

if(p[topic] > u) {

break;

}

}

// 基於最新一輪採樣的結果,更新計數

nw[w][topic] +=1;

nd[m][topic] +=1;

nwsum[topic] +=1;

ndsum[m] +=1;

returntopic;

}

};


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 AI研習社 的精彩文章:

5G來了!如何看待高通發布的全新旗艦驍龍 855?

TAG:AI研習社 |