週末這兩天在家用LDA做個小實驗。在LDA的衆多實現的工具包中,GibbsLDA 是應用最廣泛的,包括c++版本、java版本等。GibbsLDA++ 是它的C++版本的實現,目前最新版本是0.2版。在實際使用過程中,發現這個實現版本有內存使用問題。我花了一些時間定位到了問題,貼出來供大家參考。
問題1:數組內存訪問越界
在model.cpp中,用到了兩個矩陣nw和nd,分別存儲word-topic關係和document-topic關係。這兩個矩陣的大小分別是V * K和 M * K,其中,V是詞表大小,M是文檔個數,K是topic的個數。在sampling的過程中,用隨機數產生器來隨機產生topic對應的索引。源程序如下:
int topic = (int)(((double)random() / RAND_MAX) * K);
原則上,topic的索引的取值範圍是[0,K-1],不過,上面那行程序,函數random()的取值可以是RAND_MAX,也就是說上述語句產生的topic索引的範圍是[0,K],當產生的索引是K的時候,在接下來的運算中,發生數組越界訪問。
所以應該把上面的代碼修正爲:
int topic = (int)(((double)random() / (RAND_MAX+1)) * K);
我實際上是在windows上面用的,windows不支持random()函數,所以改成rand()函數,如下:
int topic = (int)(((double)rand() / (RAND_MAX+1)) * K);
當然,srandom()也要改成srand()。
問題2:內存泄露
內存泄露主要發生在class model的析構函數中,即model::~model()中。產生的原因很簡單,作者對於向量的內存釋放,用的是delete,而正確的應該用delete []。
例如,原始代碼:
if (nw) {
for (int w = 0; w < V; w++) {
if (nw[w]) {
delete nw[w];
}
}
}
如之前所述,nw是一個矩陣。正確代碼是:
if (nw) {
for (int w = 0; w < V; w++) {
if (nw[w]) {
delete [] nw[w]; //!!!
}
}
}
delete [] nw; //!!!
修改了上面兩個問題之後,GibbsLDA++-0.2在機器上跑的就很順暢了。——其實不修正也能跑出結果來:對於內存訪問越界,次數並不多,所以影響不大;對於內存泄露,進程退出的時候OS會自動清理改進程所用的內存空間,所以也影響不大。這可能也是這個工具包被這麼多人(主要是研究人員)使用,而沒人去修正這個問題的原因吧。
完。
轉載請註明出處:http://blog.csdn.net/xceman1997/article/details/46405597