如何使用 Keras 實現無監督聚類

2020-12-11 雷鋒網

雷鋒網 AI 研習社按:本文為雷鋒網(公眾號:雷鋒網)字幕組編譯的技術博客,原標題 A、Word2Vec — a baby step in Deep Learning but a giant leap towards Natural Language Processing,作者為機器學習工程師 Suvro Banerjee

翻譯 | 程煒 李昊洋   整理  |  孔令雙

原文連結:

https://medium.com/@chengweizhang2012/how-to-do-unsupervised-clustering-with-keras-9e1284448437

由於深度學習算法在表達非線性表徵上的卓越能力,它非常適合完成輸入到有標籤的數據集輸出的映射。這種任務叫做分類。它需要有人對數據進行標註。無論是對 X 光圖像還是對新聞報導的主題進行標註,在數據集增大的時候,依靠人類進行幹預的做法都是費時費力的。

聚類分析,或者稱作聚類是一種無監督的機器學習技術。它不需要有標籤的數據集。它可以根據數據成員的相似性對它們進行分組。

你為什麼需要關注它呢?讓我來講講幾個理由。

聚類的應用

  • 推薦系統,通過學習用戶的購買歷史,聚類模型可以根據相似性對用戶進行區分。它可以幫助你找到志趣相投的用戶,以及相關商品。

  • 在生物學上,序列聚類算法試圖將相關的生物序列進行分組。它根據胺基酸含量對蛋白進行聚類。

  • 圖像和視頻聚類分析根據相似性對它們進行分組。

  • 在醫療資料庫中,對每個病人來說,真正有價值的測試(比如葡萄糖,膽固醇)都是不同的。首先對病人進行聚類分析可以幫助我們對真正有價值的特徵進行分類,從而減少特徵分散。它可以增加分類任務的準確性,比如在癌症病人生存預測上。

  • 在一般用途上,它可以生成一個數據的匯總信息用於分類,模式發現,假設生成,以及測試。

無論如何,對於數據科學家來說,聚類都是非常有價值的工具。

如何才是好的聚類

一個好的聚類方法應該生成高質量的分類,它有如下特點:

  1. 群組內部的高相似性:群組內的緊密聚合

  2. 群組之間的低相似性:群組之間各不相同

為 K-Means 算法設置一個基線

傳統的 K-Means 算法速度快,並且可以廣泛應用於解決各種問題。但是,它的距離度量受限於原始的數據空間。因此在輸入數據維度較高時,它的效率就會降低,比如說圖像集。

讓我們來訓練一個 K-Means 模型對 MNIST 手寫字體進行聚類分析到 10 個群組中。

from sklearn.cluster import KMeans

from keras.datasets import mnist


(x_train, y_train), (x_test, y_test) = mnist.load_data()

x = np.concatenate((x_train, x_test))

y = np.concatenate((y_train, y_test))

x = x.reshape((x.shape[0], -1))

x = np.divide(x, 255.)

# 10 clusters

n_clusters = len(np.unique(y))

# Runs in parallel 4 CPUs

kmeans = KMeans(n_clusters=n_clusters, n_init=20, n_jobs=4)

# Train K-Means.

y_pred_kmeans = kmeans.fit_predict(x)

# Evaluate the K-Means clustering accuracy.

metrics.acc(y, y_pred_kmeans)

評估得到 K-Means 聚類算法的準確度在 53.2%。後面我們會將它與深度嵌入聚類模型進行比較。

在找原始碼嗎?到我的 Github 上看看。

前訓練自動編碼器

自動編碼器是一個數據壓縮算法。它由編碼器和解碼器兩個主要部分構成。編碼器的工作是將輸入數據壓縮成較低維度的特徵。比如,一個 28x28 的 MNIST 圖像總共有 784 個像素。編碼器可以將它壓縮成 10 個浮點數組成的數組。我們將這些浮點數作為圖像的特徵。另一方面,解碼器將壓縮後的特徵作為輸入,通過它重建出與原始圖像儘可能相近似的圖像。實際上,自動編碼器是一個無監督學習算法。在訓練過程中,它只需要圖像本身,而不需要標籤。

自動編碼器

自動編碼器是一個全連接對稱模型。之所以是對稱的,是因為圖像的壓縮和解壓過程是一組完全相反的對應過程。

全連接自動編碼器

我們將會對自動編碼器進行 300 輪訓練,並保存下模型權重值。

autoencoder.fit(x, x, batch_size=256, epochs=300) #, callbacks=cb)

autoencoder.save_weights('./results/ae_weights.h5')

聚類模型

通過訓練自動編碼器,我們已經使編碼器學會了將每幅圖像壓縮成 10 個浮點數。你可能會想,因為輸入維度減少到 10, K-Means 算法應該可以以此開始聚類?是的,我們將會使用 K-Means 算法生成聚類中心。它是 10 維特徵向量空間的 10 個群組的中心。但是我們還要建立我們的自定義聚類層,將輸入特徵轉化為群組標籤概率。

這個概率是由 t-分布計算得來。 T-分布,和t-分布鄰域嵌入算法一樣,測度了內含點和中心點之間的相似度。正如你所猜測的那樣,聚類層的作用類似於用於聚類的K-means,並且該層的權重表示可以通過訓練K均值來初始化的聚類質心。

如果您是在 Keras 中創建自定義圖層的新手,那麼您可以實施三種強制方法。

  • build(input_shape),在這裡你定義圖層的權重,在我們的例子中是10-D特徵空間中的10個簇,即10x10個權重變量。

  • call(x),層邏輯所在的地方,即從特徵映射到聚類標籤魔術的地方。

  • compute_output_shape(input_shape),在這裡指定從輸入形狀到輸出形狀的形狀轉換邏輯。

Here is the custom clustering layer code,

class ClusteringLayer(Layer):

    """

    Clustering layer converts input sample (feature) to soft label.


    # Example

    ```

        model.add(ClusteringLayer(n_clusters=10))

    ```

    # Arguments

        n_clusters: number of clusters.

        weights: list of Numpy array with shape `(n_clusters, n_features)` witch represents the initial cluster centers.

        alpha: degrees of freedom parameter in Student's t-distribution. Default to 1.0.

    # Input shape

        2D tensor with shape: `(n_samples, n_features)`.

    # Output shape

        2D tensor with shape: `(n_samples, n_clusters)`.

    """


    def __init__(self, n_clusters, weights=None, alpha=1.0, **kwargs):

        if 'input_shape' not in kwargs and 'input_dim' in kwargs:

            kwargs['input_shape'] = (kwargs.pop('input_dim'),)

        super(ClusteringLayer, self).__init__(**kwargs)

        self.n_clusters = n_clusters

        self.alpha = alpha

        self.initial_weights = weights

        self.input_spec = InputSpec(ndim=2)


    def build(self, input_shape):

        assert len(input_shape) == 2

        input_dim = input_shape[1]

        self.input_spec = InputSpec(dtype=K.floatx(), shape=(None, input_dim))

        self.clusters = self.add_weight((self.n_clusters, input_dim), initializer='glorot_uniform', name='clusters')

        if self.initial_weights is not None:

            self.set_weights(self.initial_weights)

            del self.initial_weights

        self.built = True


    def call(self, inputs, **kwargs):

        """ student t-distribution, as same as used in t-SNE algorithm.        

                 q_ij = 1/(1+dist(x_i, µ_j)^2), then normalize it.

                 q_ij can be interpreted as the probability of assigning sample i to cluster j.

                 (i.e., a soft assignment)

        Arguments:

            inputs: the variable containing data, shape=(n_samples, n_features)

        Return:

            q: student's t-distribution, or soft labels for each sample. shape=(n_samples, n_clusters)

        """

        q = 1.0 / (1.0 + (K.sum(K.square(K.expand_dims(inputs, axis=1) - self.clusters), axis=2) / self.alpha))

        q **= (self.alpha + 1.0) / 2.0

        q = K.transpose(K.transpose(q) / K.sum(q, axis=1)) # Make sure each sample's 10 values add up to 1.

        return q


    def compute_output_shape(self, input_shape):

        assert input_shape and len(input_shape) == 2

        return input_shape[0], self.n_clusters


    def get_config(self):

        config = {'n_clusters': self.n_clusters}

        base_config = super(ClusteringLayer, self).get_config()

        return dict(list(base_config.items()) + list(config.items()))

接下來,我們在預先訓練的編碼器之後堆疊聚類層以形成聚類模型。 對於聚類層,我們初始化它的權重,聚類中心使用k-means對所有圖像的特徵向量進行訓練。

clustering_layer = ClusteringLayer(n_clusters, name='clustering')(encoder.output)

model = Model(inputs=encoder.input, outputs=clustering_layer)

# Initialize cluster centers using k-means.

kmeans = KMeans(n_clusters=n_clusters, n_init=20)

y_pred = kmeans.fit_predict(encoder.predict(x))

model.get_layer(name='clustering').set_weights([kmeans.cluster_centers_])

聚類模型結構

訓練聚類模型

輔助目標分布和KL散度損失

下一步是同時改進聚類分配和特徵表示。 為此,我們將定義一個基於質心的目標概率分布,並根據模型聚類結果將KL偏差最小化。

我們希望目標分配具有以下屬性:

  • 加強預測,即提高群集純度。

  • 更加重視高可信度地分配的數據點。

  • 防止大集群扭曲隱藏的特徵空間。

通過首先將q(編碼特徵向量)提升到第二冪然後按每個簇的頻率進行歸一化來計算目標分布。

def target_distribution(q):

    weight = q ** 2 / q.sum(0)

    return (weight.T / weight.sum(1)).T

有必要通過在輔助目標分布的幫助下從高置信度分配中學習來迭代地細化群集。 在特定次數的迭代之後,更新目標分布,並且訓練聚類模型以最小化目標分布與聚類輸出之間的KL散度損失。 培訓策略可以被看作是一種自我訓練的形式。 就像在自我訓練中一樣,我們採用初始分類器和未標記的數據集,然後用分類器標記數據集以訓練其高置信度的預測。

損失函數,KL散度或Kullback-Leibler散度是衡量兩種不同分布之間行為差異的指標。 我們希望將其最小化,以便目標分布儘可能接近聚類輸出分布。

在以下代碼片段中,目標分布每180次訓練迭代更新一次。

model.compile(optimizer=SGD(0.01, 0.9), loss='kld')


maxiter = 8000

update_interval = 140

for ite in range(int(maxiter)):

    if ite % update_interval == 0:

        q = model.predict(x, verbose=0)

        p = target_distribution(q)  # update the auxiliary target distribution p

        # evaluate the clustering performance

        y_pred = q.argmax(1)

        if y is not None:

            acc = np.round(metrics.acc(y, y_pred), 5)


    idx = index_array[index * batch_size: min((index+1) * batch_size, x.shape[0])]

    model.train_on_batch(x=x[idx], y=p[idx])

    index = index + 1 if (index + 1) * batch_size <= x.shape[0] else 0

每次更新後,您將看到聚類準確度穩步提高。

評估指標

該度量標準表明它已達到96.2%的聚類精度,考慮到輸入是未標記的圖像,這非常好。 讓我們仔細研究它的精確度。

該度量需要從無監督算法和地面實況分配中獲取一個集群分配,然後找到它們之間的最佳匹配。

最好的映射可以通過在scikit學習庫中實現的匈牙利算法有效地計算為linear_assignment。

from sklearn.utils.linear_assignment_ import linear_assignment


y_true = y.astype(np.int64)

D = max(y_pred.max(), y_true.max()) + 1

w = np.zeros((D, D), dtype=np.int64)

# Confusion matrix.

for i in range(y_pred.size):

    w[y_pred[i], y_true[i]] += 1

ind = linear_assignment(-w)

acc = sum([w[i, j] for i, j in ind]) * 1.0 / y_pred.size

查看混淆矩陣更直接。

混亂矩陣

在這裡,您可以手動快速匹配聚類分配,例如,聚類1與真實標籤7或手寫數字「7」和虎鉗籤證相匹配。

下面顯示的混淆矩陣繪製代碼片段。

import seaborn as sns

import sklearn.metrics

import matplotlib.pyplot as plt

sns.set(font_scale=3)

confusion_matrix = sklearn.metrics.confusion_matrix(y, y_pred)


plt.figure(figsize=(16, 14))

sns.heatmap(confusion_matrix, annot=True, fmt="d", annot_kws={"size": 20});

plt.title("Confusion matrix", fontsize=30)

plt.ylabel('True label', fontsize=25)

plt.xlabel('Clustering label', fontsize=25)

plt.show()

應用卷積自動編碼器(實驗)

由於我們正在處理圖像數據集,所以值得一試卷積自動編碼器,而不是僅使用完全連接的圖層構建。

值得一提的是,為了重建圖像,您可以選擇去卷積層(Keras中的Conv2DTranspose)或上採樣(UpSampling2D)層以減少偽像問題。卷積自動編碼器的實驗結果可以在我的GitHub上找到。

結論和進一步閱讀

自動編碼器在降維和參數初始化方面發揮了重要作用,然後針對目標分布對定製的聚類層進行訓練以進一步提高精度。

進一步閱讀

在 Keras 建立自動編碼器 - 官方Keras博客

用於聚類分析的無監督深嵌入 - 激勵我寫這篇文章。

完整的原始碼在我的 GitHub 上,一直讀到筆記本的最後,因為您會發現另一種可以同時減少聚類和自動編碼器丟失的另一種方法,這種方法被證明對於提高卷積聚類模型的聚類準確性非常有用。

雷鋒網字幕組編譯。

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • 【無監督學習】K-means聚類算法原理介紹,以及代碼實現
    「腐敗」生活了這麼久,還是要找到自己一點樂趣吧,於是想了一想,決定把《機器學習》的算法研究過得都重新梳理一遍,於是就從無監督學習——聚類開始了 什麼是無監督學習?無監督學習也是相對於有監督學習來說的,因為現實中遇到的大部分數據都是未標記的樣本,要想通過有監督的學習就需要事先人為標註好樣本標籤,這個成本消耗、過程用時都很巨大,所以無監督學習就是使用無標籤的樣本找尋數據規律的一種方法聚類算法就歸屬於機器學習領域下的無監督學習方法。無監督學習的目的是什麼呢?
  • 無監督機器學習中,最常見的聚類算法有哪些?
    無監督學習分析過程開發無監督學習模型需遵循的整個過程,總結如下:無監督學習的主要應用是:按某些共享屬性對數據集進行分段。這種技術可以濃縮為無監督學習試圖解決的兩種主要類型的問題。這些無監督學習算法具有令人難以置信的廣泛應用,並且對於解決諸如音樂、文檔或電影分組之類的實際問題,以及基於其購買來找到具有共同興趣的客戶非常有用。
  • 【機器學習】無監督學習:PCA和聚類
    在這節課中,我們將討論主成分分析(PCA)和聚類(clustering)這樣的無監督學習方法。你將學習為何以及如何降低原始數據的維度,還有分組類似數據點的主要方法。介紹主成分分析聚類分析作業七相關資源和分類、回歸方法相比,無監督學習算法的主要特性是輸入數據是未標註過的(即沒有給定的標籤或分類),算法在沒有任何鋪助的條件下學習數據的結構。這帶來了兩點主要不同。首先,它讓我們可以處理大量數據,因為數據不需要人工標註。
  • ...分類與聚類:三大方向剖解機器學習算法的優缺點(附Python和R實現)
    而機器之心也在文末給出了這些算法的具體實現細節。對機器學習算法進行分類不是一件容易的事情,總的來看,有如下幾種方式:生成與判別、參數與非參數、監督與非監督等等。然而,就實踐經驗來看,這些都不是實戰過程中最有效的分類算法的方式。因為對於應用機器學習而言,開發者一般會在腦海中有一個最終目標,比如預測一個結果或是對你的觀察進行分類。
  • 聚類分析:無監督算法的理論與實現
    簡而言之,聚類不過是根據某些屬性分離觀察值。用更專業的術語來說,聚類是一種無監督的機器學習算法,是一種過程,通過該過程將觀察值(數據)進行分組,以使相似的觀察值彼此靠近。這是一種「無監督」算法,因為與有監督算法(例如隨機森林)不同,您不必使用標記的數據對其進行訓練,計算機會根據基礎模式和屬性對數據進行聚類。
  • 使用Python進行K均值聚類
    在機器學習中,當我們要處理一個未標記的數據集時,稱為「無監督學習」。有時我們只是想知道我們的數據是如何組織起來的這樣我們就能知道數據是如何組織起來的。聚類意味著對一組對象進行分組。K-means聚類是無監督學習的一部分,我們使用的是未標記的數據集,這個算法會自動為我們將數據分組成聚類。它是目前最流行、應用最廣泛的聚類算法之一。它用於各種應用程式,例如市場細分,圖像細分等。
  • 用Keras復現DCN算法
    可是DCN算法並沒有keras的實現代碼,而我之前也沒有用過keras,導致用keras復現DCN算法耗費了我一周多的時間,不過經過了一周的折騰,也算基本熟悉了keras的使用。keras由於過於的強調易用性,以及受制於tensorflow等底層框架的機制影像導致開發簡單應用很容易但是如果做復現最新論文算法的定製開發就會比較困難,而pytorch就比較好的平衡了易用性以及拓展性,用pytorch來實現上述功能則比較簡單,這也是pytorch應用越來越受歡迎的原因吧。不過由於實驗室之前的代碼都是用keras寫的,這裡的DCN算法也要用keras來實現。
  • 深度學習第51講:自編碼器(AutoEncoder)及其keras實現
    從本講開始,筆者將花一些時間和大家一起學習深度學習中的無監督模型。
  • 使用TF2與Keras實現經典GNN的開源庫——Spektral
    我們可以使用 Spektral 來進行網絡節點分類、預測分子特性、使用 GAN 生成新的拓撲圖、節點聚類、預測連結以及其他任意數據是使用拓撲圖來描述的任務。Spektral 中實現了多種目前經典的圖深度學習層:Graph Convolutional Networks (GCN)Chebyshev networks (ChebNets)GraphSAGEARMA convolutionsEdge-Conditioned
  • k均值聚類算法原理和(TensorFlow)實現(無師自通)
    我們知道,在機器學習中,有三種不同的學習模式:監督學習、無監督學習和強化學習:監督學習,也稱為有導師學習,網絡輸入包括數據和相應的輸出標籤信息。例如,在 MNIST 數據集中,手寫數字的每個圖像都有一個標籤,代表圖片中的數字值。
  • 如何用keras實現deepFM
    (當然這裡可能有各種原因導致的差異,並不能說下面的實現是絕對優於參考文章的)下面的內容完全是個人行為,有錯漏希望多指教Keras 的使用,包括如果使用 Sequential 搭建模型,以及如何使用函數式 API 搭建較簡單模型Dense, Embedding, Reshape, Concatenate, Add, Substract, Lambda 這幾個
  • 回歸、分類與聚類:三大方向剖解機器學習算法的優缺點(附Python和R...
    而機器之心也在文末給出了這些算法的具體實現細節。對機器學習算法進行分類不是一件容易的事情,總的來看,有如下幾種方式:生成與判別、參數與非參數、監督與非監督等等。然而,就實踐經驗來看,這些都不是實戰過程中最有效的分類算法的方式。因為對於應用機器學習而言,開發者一般會在腦海中有一個最終目標,比如預測一個結果或是對你的觀察進行分類。
  • 什麼是無監督學習?
    無監督學習即沒有標註的訓練數據集,需要根據樣本間的統計規律對樣本集進行分析,常見任務如聚類等。所以,無監督學習常常被用於數據挖掘,用於在大量無標籤數據中發現些什麼。它的訓練數據是無標籤的,訓練目標是能對觀察值進行分類或者區分等。
  • Keras使用進階(Ⅰ)
    恰好這大半年的research也用到了keras高級點的特性,尋思著是時候寫一篇keras使用進階的文章來記錄下自己「摸魚」的日子.用keras訓練多標籤數據通常用keras做分類任務,一張圖像往往只對應著一種類別,但是在實際的問題中,可能你需要預測出一張圖像的多種屬性。
  • 自步對比學習: 充分挖掘無監督學習樣本
    這裡著重區分一下目前很受關注的無監督預訓練(Unsupervised Pre-training)任務,存在兩點主要區別:1)無監督預訓練任務從網絡隨機初始化開始,無監督重識別任務從預訓練好的網絡開始;2)無監督預訓練的網絡需要經過fine-tune才可以應用在下遊任務上,而無監督重識別任務本身可以看作一個無監督的下遊任務,經過訓練的網絡可直接部署。
  • 使用 keras-bert 實現文本多分類任務
    本文將會介紹如何使用kera
  • K-Means聚類講解:算法和Sklearn的實現(附代碼)
    而向客戶提出錯誤的業務策略可能意味著失去該客戶,因此,重要的一點是我們必須實現良好的市場集群。什麼是無監督機器學習無監督機器學習是一種機器學習算法,試圖在沒有任何先驗知識的情況下推斷數據中的模式。與之相反的是有監督的機器學習,這裡我們有一個訓練集,該算法將嘗試通過將輸入與預定義的輸出進行匹配來查找數據中的模式。
  • 吳恩達《Machine Learning》精煉筆記 8:聚類 KMeans 及其 Python實現
    吳恩達《Machine Learning》精煉筆記 4:神經網絡基礎吳恩達《Machine Learning》精煉筆記 5:神經網絡吳恩達《Machine Learning》精煉筆記 6:關於機器學習的建議吳恩達《Machine Learning》精煉筆記 7:支持向量機 SVM本周的主要知識點是無監督學習中的兩個重點
  • 聚類算法中的若干挑戰問題
    聚類算法在實際應用中會面臨一些現實的挑戰問題,最新的聚類算法的研究熱點圍繞如何解決這些問題:  現實數據經常存在缺失的情況。例如醫療診斷中每個患者的檢測報告中並沒有包含所有的檢測項目,沒有檢測的項目就是缺失特徵,如何在特徵缺失的情況下進行聚類是當前研究的一個熱點。
  • 獨家 | 使用高斯混合模型,讓聚類更好更精確(附數據&代碼&學習資源)
    概述簡介我真的很喜歡研究無監督的學習問題,因為它們提供了一個完全不同於監督學習問題的挑戰:提供更大的空間來試驗我的數據。這也不難理解機器學習領域的大多數發展和突破都發生在無監督學習這一塊。但問題是,聚類有很多種,不只局限於我們之前學過的基本算法。