function 將數據點分配到最近的聚類中心

背景

在對大樣本進行聚類時,由於k-means的計算開銷問題,通常隨機選取部分樣本進行聚類,得到聚類中心。然而往往要得到每個樣本最近聚類中心,這常用在檢索索引構建中,eg. OPQ (PAMI 2014)Inverted Multi-Index(PAMI 2014)

算法步驟

設一個特徵向量p(1*2000),2000是特徵維數。聚類中心矩陣爲C(256*2000),256爲中心數,2000爲特徵維數。
1. 數據歸一化
對p各維計算平方和,得到p_norm,是一個浮點數。
2. 聚類中心歸一化
對C的每一行,計算各維平方和,得到c_norm:256*1
3. p_norm 擴展至 1*256
4. 計算p_norm = p_norm+c_norm;
5. 計算點p到256箇中心的距離向量dis=2Cp+p_norm
6. 計算dis中最小的那個數據的index,即爲離點p最近的聚類中心

分析

爲什麼第5步中的算式就得到距離了呢?
答:設C中的一個聚類中心向量爲(c1,c2,...,c2000) , 樣本點p爲(p1,p2,...,p2000) , 則第1步中的歸一化即爲p21+...+p22000 , 第2步中的歸一化即爲c21+...+c22000 , 則5中的算式其實爲:

2(p1c1+...+p2000c2000)+p21+...+p22000+c21+...+c22000

即:
(p1c1)2+...+(pncn)2

C++代碼

要用到blas庫, blas函數的功能解釋請查詢官網document

// 設有一個數據點vector<float> point
//    聚類中心vector<float> vocabs, float* vocabs_matrices
// centroids_norms_爲第2步中的聚類中心norm
float p_norm = cblas_sdot(feature_dim, &(point[0]), 1, &(point[0]), 1);
cblas_saxpy(vocabs_[0].size(), 1, 
    (centroids_norms_[0]), 1, &(p_norms_[0]), 1);
cblas_sgemv(CblasRowMajor, CblasNoTrans,
    vocabs_[0].size(), subspace_dimension, -2.0,
    vocabs_matrices_[0], feature_dim, &(point[0]), 1, 1, &(p_norms_[0]), 1);

Matlab代碼

Matlab for循環的效率低,用矩陣運算。
設數據矩陣P爲10000*2000,其中2000是特徵維數,10000是樣本數聚類中心矩陣爲C爲256*2000,256爲中心數,2000爲特徵維數。
1. 數據歸一化
對P的每一行,計算各維平方和(實際實現中的歸一化一般不做開平方),得到P_norm:10000*1。
2. 聚類中心歸一化
對C的每一行,計算各維平方和,得到C_norm:256*1
3. P_norm 擴展至 10000*256(將原來的10000*1的P_norm複製9999遍,按列填充矩陣), C_norm擴展至256*10000(同上,也是複製填充向量得出)。
4. 其後步驟同上。

% 將數據點分配到附近的聚類中心
% Input:
%    points vocab 都按列組織,eg. points中一列位一個特徵,行數爲特徵維數,列數爲樣本數
% Output:
%    idx_table 爲每個樣本分配到的最近的聚類中心的下標(從0開始!)
function idx_table = calidx(points, vocab)
    disp('Cal coarse ids...');
    n_vocab = size(vocab, 2);
    N = size(points, 2);
    idx_table = zeros(N, 1);

    vocab_norm = sum(vocab .^ 2, 1);   % get a row vector

    p_norm = repmat(sum(points .^ 2, 1), [n_vocab, 1]) + repmat(vocab_norm', [1, N]); % get n_vocab*N

    dis = -2.0 * vocab' * points + p_norm;  % get n_vocab * N dis

    [~, idx_table] = min(dis, [], 1);

    idx_table = idx_table - 1;  % Matlab下標從1開始,轉成從0開始的



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章