<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 3. TensorFlow 中的聚類 前一章中介紹的線性回歸是一種監督學習算法,我們使用數據和輸出值(或標簽)來構建適合它們的模型。但我們并不總是擁有標記數據,盡管如此,我們也希望以某種方式分析它們。在這種情況下,我們可以使用無監督學習算法,例如聚類。聚類方法被廣泛使用,因為它通常是數據分析的初步篩選的好方法。 在本章中,我將介紹名為 K-means 的聚類算法。它肯定是最受歡迎的,廣泛用于自動將數據分組到相關的子集中,以便子集中的所有元素彼此更相似。在此算法中,我們沒有任何目標或結果變量來預測估計值。 我還將使用本章來介紹 TensorFlow 的知識,并在更詳細地介紹名為`tensor`(張量)的基本數據結構。我將首先解釋這種類型的數據是什么樣的,并展示可以在其上執行的轉換。然后,我將使用張量在案例研究中展示 K-means 算法的使用。 ### 基本數據結構:張量 TensorFlow 程序使用稱為張量的基本數據結構來表示其所有數據。張量可以被認為是動態大小的多維數據數組,其具有靜態數據類型的屬性,可以從布爾值或字符串到各種數字類型。下面是 Python 中的主要類型及其等價物的表格。 | TensorFlow 中的類型 | Python 中的類型 | 描述 | | --- | --- | --- | | `DT_FLOAT` | `tf.float32` | 32 位浮點 | | `DT_INT16` | `tf.int16` | 16 位整數 | | `DT_INT32` | `tf.int32` | 32 位整數 | | `DT_INT64` | `tf.int64` | 64 位整數 | | `DT_STRING` | `tf.string` | 字符串 | | `DT_BOOL` | `tf.bool` | 布爾值 | 另外,每個張量擁有階(Rank),這是其維度的數量。例如,以下張量(在 Python 中定義為列表)的階為 2: ``` t = [[1,2,3],[4,5,6],[7,8,9]] ``` 張量可以有任何階。二階張量通常被認為是矩陣,一階張量將是向量。零階被認為是標量值。 TensorFlow 文檔使用三種類型的命名約定來描述張量的維度:形狀(Shape),階(Rank)和維數(Dimension Number)。下表顯示了它們之間的關系,以便使跟蹤 TensorFlow 文檔更容易: | 形狀 | 階 | 維數 | | --- | --- | --- | | `[]` | 0 | 0-D | | `[D0]` | 1 | 1-D | | `[D0, D1]` | 2 | 2-D | | `[D0, D1, D2]` | 3 | 3-D | | … | … | … | | `[D0, D1, ... Dn]` | n | n-D | 這些張量可以通過一系列 TensorFlow 軟件包提供的轉換進行操作。 下面,我們將在下表中討論其中的一些內容。 在本章中,我們將詳細介紹其中一些內容。 可以在 TensorFlow 的官方網站 [18] 上找到完整的轉換列表和詳細信息。 | 操作 | 描述 | | tf.shape | 獲取張量的形狀 | | tf.size | 獲取張量的大小 | | tf.rank | 獲取張量的階 | | tf.reshape | 改變張量的形狀,保持包含相同的元素 | | tf.squeeze | 刪除大小為 1 的張量維度 | | tf.expand_dims | 將維度插入張量 | | tf.slice | 刪除部分張量 | | tf.split | 將張量沿一個維度劃分為多個張量 | | tf.tile | 將一個張量多次復制,并創建新的張量 | | tf.concat | 在一個維度上連接張量 | | tf.reverse | 反轉張量的特定維度 | | tf.transpose | 轉置張量中的維度 | | tf.gather | 根據索引收集部分 | 例如,假設你要將`2×2000`(2D 張量)的數組擴展為立方體(3D 張量)。 我們可以使用`tf.expand_ dims`函數,它允許我們向張量插入一個維度: ```py vectors = tf.constant(conjunto_puntos) extended_vectors = tf.expand_dims(vectors, 0) ``` 在這種情況下,`tf.expand_dims`將一個維度插入到由參數給定的一個張量中(維度從零開始)。 從視覺上看,上述轉變如下: ![](https://jorditorres.org/wp-content/uploads/2016/02/image023.gif) 如你所見,我們現在有了 3D 張量,但我們無法根據函數參數確定新維度 D0 的大小。 如果我們使用`get_shape()`操作獲得此`tensor`的形狀,我們可以看到沒有關聯的大小: ```py print expanded_vectors.get_shape() ``` 它可能會顯示: ```py TensorShape([Dimension(1), Dimension(2000), Dimension(2)]) ``` 在本章的后面,我們將看到,由于 TensorFlow 形狀廣播, 張量的許多數學處理函數(如第一章所示),能夠發現大小未指定的維度的大小,,并為其分配這個推導出的值。 ### TensorFlow 中的數據存儲 在介紹 TensorFlow 的軟件包之后,從廣義上講,有三種主要方法可以在 TensorFlow 程序上獲取數據: 1. 來自數據文件。 2. 數據作為常量或變量預加載。 3. 那些由 Python 代碼提供的。 下面,我簡要介紹其中的每一個。 1) **數據文件** 通常,從數據文件加載初始數據。這個過程并不復雜,鑒于本書的介紹性質,我邀請讀者訪問TensorFlow 的網站 [19],了解如何從不同文件類型加載數據。你還可以查看 Python 代碼[`input_data.py`](https://github.com/jorditorresBCN/TutorialTensorFlow/blob/master/input_data.py) [20](可在 Github 上找到),它從文件中加載 MNIST 數據(我將在下面幾章使用它)。 2) **變量和常量** 當談到小集合時,也可以預先將數據加載到內存中;創建它們有兩種基本方法,正如我們在前面的例子中看到的那樣: * `constant(…)`用于常量 * `Variable(…)`用于變量 TensorFlow 包提供可用于生成常量的不同操作。在下表中,你可以找到最重要的操作的摘要: | 操作 | 描述 | | --- | --- | | `tf.zeros_like` | 創建一個張量,所有元素都初始化為 0 | | `tf.ones_like` | 創建一個張量,所有元素都初始化為 1 | | `tf.fill` | 創建一個張量,其中所有元素都初始化為由參數給出的標量值 | | `tf.constant` | 使用參數列出的元素創建常量張量 | 在 TensorFlow 中,在模型的訓練過程中,參數作為變量保存在存儲器中。 創建變量時,可以使用由函數參數定義的張量作為初始值,該值可以是常量值或隨機值。 TensorFlow 提供了一系列操作,可生成具有不同分布的隨機張量: | 操作 | 描述 | | --- | --- | | `tf.random_normal` | 具有正態分布的隨機值 | | `tf.truncated_normal` | 具有正態分布的隨機值,但消除那些幅度大于標準差 2 倍的值 | | `tf.random_uniform` | 具有均勻分布的隨機值 | | `tf.random_shuffle` | 在第一維中隨機打亂張量元素 | | `tf.set_random_seed` | 設置隨機種子 | 一個重要的細節是,所有這些操作都需要特定形狀的張量作為函數的參數,并且創建的變量具有相同的形狀。 通常,變量具有固定的形狀,但TensorFlow提供了在必要時對其進行重塑的機制。 使用變量時,必須在構造圖之后,在使用`run()`函數執行任何操作之前顯式初始化這些變量。 正如我們所看到的,為此可以使用`tf.initialize_all_variables()`。 通過 TensorFlow 的`tf.train.Saver()`類,可以在訓練模型時和之后將變量保存到磁盤上,但是這個類超出了本書的范圍。 3) **由Python代碼提供** 最后,我們可以使用我們所謂的“符號變量”或占位符來在程序執行期間操作數據。調用是`placeholder()`,參數為元素類型和張量形狀,以及可選的名稱。 從 Python 代碼調用`Session.run()`或`Tensor.eval()`的同時,張量由`feed_dict`參數中指定的數據填充。回想第 1 章中的第一個代碼: ```py import tensorflow as tf a = tf.placeholder("float") b = tf.placeholder("float") y = tf.mul(a, b) sess = tf.Session() print sess.run(y, feed_dict={a: 3, b: 3}) ``` 在最后一行代碼中,調用`sess.run()`時,我們傳遞兩個張量`a`和`b`的值到`feed_dict`參數。 通過張量的簡要介紹,我希望從現在起讀者可以毫不費力地讀懂下面幾章的代碼。 ### K-Means 算法 K-Means 是一種無監督算法,可以解決聚類問題。 它的過程遵循一種簡單易行的方法,通過一定數量的簇(假設`k`簇)對給定數據集進行聚類。 簇內的數據點是同構的,不同簇的點是異構的,這意味著子集中的所有元素與其余元素相比更為相似。 算法的結果是一組`K`個點,稱為質心,它們是所得的不同組的焦點,以及點集的標簽,這些點分配給其中一個簇。 簇內的所有點與質心的距離都比任何其他質心更近。 如果我們想要直接最小化誤差函數(所謂的 NP-hard 問題),那么簇的生成是一個計算上很昂貴的問題。因此,已經創建了一些算法,通過啟發式在局部最優中快速收斂。 最常用的算法使用迭代優化技術,它在幾次迭代中收斂。 一般來講,這種技術有三個步驟: + 初始步驟(步驟 0):確定`K`個質心的初始集合。 + 分配步驟(步驟 1):將每個觀測值分配到最近的組。 + 更新步驟(步驟 2):計算每個新組的新質心。 有幾種方法可以確定初始`K`質心。 其中一個是在數據集中隨機選擇`K`個觀測值并將它們視為質心;這是我們將在我們的示例中使用的那個。 分配(步驟 1)和更新(步驟 2)的步驟在循環中交替,直到認為算法已經收斂為止,這可以是,例如,當點到組的分配不再改變的時候。 由于這是一種啟發式算法,因此無法保證它收斂于全局最優,結果取決于初始組。 因此,由于算法通常非常快,通常使用不同的初始質心值重復執行多次,然后權衡結果。 要在 TensorFlow 中開始編寫 K-means 的示例,我建議首先生成一些數據作為測試平臺。 我建議做一些簡單的事情,比如在 2D 空間中隨機生成 2,000 個點,遵循二維正態分布來繪制一個空間,使我們能夠更好地理解結果。 例如,我建議使用以下代碼: ```py num_puntos = 2000 conjunto_puntos = [] for i in xrange(num_puntos): if np.random.random() &gt; 0.5: conjunto_puntos.append([np.random.normal(0.0, 0.9), np.random.normal(0.0, 0.9)]) else: conjunto_puntos.append([np.random.normal(3.0, 0.5), np.random.normal(1.0, 0.5)]) ``` 正如我們在前一章中所做的那樣,我們可以使用一些 Python 圖形庫來繪制數據。 我建議像以前一樣使用 matplotlib,但這次我們還將使用基于 matplotlib 的可視化包 Seaborn 和數據操作包 pandas,它允許我們使用更復雜的數據結構。 如果未安裝這些軟件包,則必須先使用`pip`執行此操作,然后才能運行以下代碼。 要顯示隨機生成的點,我建議使用以下代碼: ```py import matplotlib.pyplot as plt import pandas as pd import seaborn as sns df = pd.DataFrame({"x": [v[0] for v in conjunto_puntos], "y": [v[1] for v in conjunto_puntos]}) sns.lmplot("x", "y", data=df, fit_reg=False, size=6) plt.show() ``` 此代碼生成二維空間中的點圖,如下面的截圖所示: ![](https://jorditorres.org/wp-content/uploads/2016/02/image024.png) 在 TensorFlow 中實現的 k-means 算法將上述點分組,例如在四個簇中,可能像這樣(基于 Shawn Simister 在他的博客中展示的模型 [21]): ```py import numpy as np vectors = tf.constant(conjunto_puntos) k = 4 centroides = tf.Variable(tf.slice(tf.random_shuffle(vectors),[0,0],[k,-1])) expanded_vectors = tf.expand_dims(vectors, 0) expanded_centroides = tf.expand_dims(centroides, 1) assignments = tf.argmin(tf.reduce_sum(tf.square(tf.sub(expanded_vectors, expanded_centroides)), 2), 0) means = tf.concat(0, [tf.reduce_mean(tf.gather(vectors, tf.reshape(tf.where( tf.equal(assignments, c)),[1,-1])), reduction_indices=[1]) for c in xrange(k)]) update_centroides = tf.assign(centroides, means) init_op = tf.initialize_all_variables() sess = tf.Session() sess.run(init_op) for step in xrange(100): _, centroid_values, assignment_values = sess.run([update_centroides, centroides, assignments]) ``` 我建議讀者使用以下代碼檢查`assignment_values`張量中的結果,該代碼生成像上面那樣的圖: ```py data = {"x": [], "y": [], "cluster": []} for i in xrange(len(assignment_values)): data["x"].append(conjunto_puntos[i][0]) data["y"].append(conjunto_puntos[i][1]) data["cluster"].append(assignment_values[i]) df = pd.DataFrame(data) sns.lmplot("x", "y", data=df, fit_reg=False, size=6, hue="cluster", legend=False) plt.show() ``` 截圖以及我的代碼執行結果如下圖所示: ![](https://jorditorres.org/wp-content/uploads/2016/02/image026.png) ### 新的組 我假設讀者可能會對上一節中介紹的 K-means 代碼感到有些不知所措。 好吧,我建議我們一步一步詳細分析它,特別是觀察涉及的張量以及它們在程序中如何轉換。 首先要做的是將所有數據移到張量。 在常數張量中,我們使初始點保持隨機生成: ```py vectors = tf.constant(conjunto_vectors) ``` 按照上一節中介紹的算法,為了開始我們必須確定初始質心。 隨著我前進,一個選項可能是,從輸入數據中隨機選擇`K`個觀測值。 一種方法是使用以下代碼,它向 TensorFlow 表明,它必須隨機地打亂初始點并選擇前`K`個點作為質心: ```py k = 4 centroides = tf.Variable(tf.slice(tf.random_shuffle(vectors),[0,0],[k,-1])) ``` 這`K`個點存儲在 2D 張量中。 要知道這些張量的形狀,我們可以使用`tf.Tensor.get_shape()`: ```py print vectors.get_shape() print centroides.get_shape() TensorShape([Dimension(2000), Dimension(2)]) TensorShape([Dimension(4), Dimension(2)]) ``` 我們可以看到`vectors`是一個數組,D0 維包含 2000 個位置,每個位置一個向量,D1 的位置是每個點`x, y`。 相反,`centroids`是一個矩陣,維度 D0 有四個位置,每個質心一個位置,D1 和`vectors`相同。 接下來,算法進入循環。 第一步是為每個點計算其最接近的質心,根據平方歐幾里德距離 [22](只能在我們想要比較距離時使用): ![](https://jorditorres.org/wp-content/uploads/2016/02/image028.jpg) 為了計算該值,使用`tf.sub(vectors, centroides`。 我們應該注意到,雖然減法的兩個張量都有 2 個維度,但它們在一個維度上大小不同(維度 D0 為 2000 和 4),實際上它們也代表不同的東西。 為了解決這個問題,我們可以使用之前討論過的一些函數,例如`tf.expand_dims`,以便在兩個張量中插入一個維度。 目的是將兩個張量從 2 維擴展到 3 維來使尺寸匹配,以便執行減法: ```py expanded_vectors = tf.expand_dims(vectors, 0) expanded_centroides = tf.expand_dims(centroides, 1) ``` `tf.expand_dims`在每個張量中插入一個維度;在`vectors`張量的第一維(D0),以及`centroides`張量的第二維(D1)。 從圖形上看,我們可以看到,在擴展后的張量中,每個維度具有相同的含義: ![](https://jorditorres.org/wp-content/uploads/2016/02/image031.gif) 它似乎得到了解決,但實際上,如果你仔細觀察(在插圖中概述),在每種情況下都有大小無法確定的些維度。 請記住,使用`get_shape()`函數我們可以發現: ```py print expanded_vectors.get_shape() print expanded_centroides.get_shape() ``` 輸出如下: ```py TensorShape([Dimension(1), Dimension(2000), Dimension(2)]) TensorShape([Dimension(4), Dimension(1), Dimension(2)]) ``` 使用 1 表示沒有指定大小。 但我已經展示 TensorFlow 允許廣播,因此`tf.sub`函數能夠自己發現如何在兩個張量之間將元素相減。 直觀地,并且觀察先前的附圖,我們看到兩個張量的形狀匹配,并且在這些情況下,兩個張量在一定維度上具有相同的尺寸。 這些數學,如 D2 維度所示。 相反,在維度 D0 中只有`expanded_centroides`的定義大小。 在這種情況下,如果我們想要在此維度內對元素執行減法,則 TensorFlow 假定`expanded_vectors`張量的維度 D0 必須是相同的大小。 對于`expended_centroides`張量的維度 D1 的大小也是如此,其中 TensorFlow 推導出`expanded_vectors`張量的尺寸 D1 的大小。 因此,在分配步驟(步驟 1)中,算法可以用 TensorFlow 代碼的這四行表示,它計算平方歐幾里德距離: ```py diff=tf.sub(expanded_vectors, expanded_centroides) sqr= tf.square(diff) distances = tf.reduce_sum(sqr, 2) assignments = tf.argmin(distances, 0) ``` 而且,如果我們看一下張量的形狀,我們會看到它們分別對應`diff`,`sqr`,`distance`和`assign`,如下所示: ```py TensorShape([Dimension(4), Dimension(2000), Dimension(2)]) TensorShape([Dimension(4), Dimension(2000), Dimension(2)]) TensorShape([Dimension(4), Dimension(2000)]) TensorShape([Dimension(2000)]) ``` 也就是說,`tf.sub`函數返回了張量`dist`,其中包含質心和向量的坐標的差(維度 D1 表示數據點,D0 表示質心,每個坐標`x, y`在維度 D2 中表示)。 `sqr`張量包含它們的平方。 在`dist`張量中,我們可以看到它已經減少了一個維度,它在`tf.reduce_sum`函數中表示為一個參數。 我用這個例子來解釋 TensorFlow 提供的幾個操作,它們可以用來執行減少張量維數的數學運算,如`tf.reduce_sum`。在下表中,你可以找到最重要的操作摘要。 | 操作 | 描述 | | --- | --- | | tf.reduce_sum | 沿一個維度計算元素總和 | | tf.reduce_prod | 沿一個維度計算元素的乘積 | | tf.reduce_min | 沿一個維度計算元素最小值 | | tf.reduce_max | 沿一個維度計算元素最大值 | | tf.reduce_mean | 沿一個維度計算元素平均值 | 最后,使用`tf.argmin`實現分配,它返回張量的某個維度的最小值的索引(在我們的例子中是 D0,記得它是質心)。 我們還有`tf.argmax`操作: | 手術 | 描述 | | --- | --- | | tf.argmin | 沿某個維度返回最小值的索引 | | tf.argmax | 沿某個維度返回最大值的索引 | 事實上,上面提到的 4 條語句可以在一行代碼中匯總,正如我們在上一節中看到的那樣: ```py assignments = tf.argmin(tf.reduce_sum(tf.square(tf.sub(expanded_vectors, expanded_centroides)), 2), 0) ``` 但無論如何,內部的`tensors`,以及它們定義為節點和執行的內部圖的操作,就像我們之前描述的那樣。 ### 計算新的質心 在那段代碼中,我們可以看到`means`張量是`k`張量的連接結果,它們對應屬于每個簇的每個點的平均值。 接下來,我將評論每個 TensorFlow 操作,這些操作涉及計算屬于每個簇的每個點的平均值 [23]。 * 使用`equal`,我們可以得到布爾張量(`Dimension(2000)`),它(使用`true`)表示`assignments`張量`K`個簇匹配的位置,當時我們正在計算點的平均值。 * 使用`where`構造一個張量(`Dimension(1) x Dimension(2000)`),帶有布爾張量中值為`true`的位置,布爾張量作為參數接收的_布爾張量_。 * 用`reshape`構造張量(`Dimension(2000) x Dimension(1)`),其中`vectors`張量內的點的索引屬于簇`c`。 * 用`gather`構造張量(`Dimension(1) x Dimension(2000)`),它收集形成簇`c`的點的坐標。 * 使用`reduce_mean`,構造張量_(`Dimension(1) x Dimension(2)`)_,其中包含屬于簇`c`的所有點的平均值。 無論如何,如果讀者想要深入研究代碼,正如我常說的那樣,你可以在 TensorFlow API 頁面上找到有關這些操作的更多信息,以及非常具有說明性的示例 [24]。 ### 圖表執行 最后,我們必須描述上述代碼中,與循環相對應的部分,以及使用`means`張量的新值更新質心的部分。 為此,我們需要創建一個操作,它將`means`張量的值分配到質心中,而不是在執行操作`run()`時,更新的質心的值在循環的下一次迭代中使用: ```py update_centroides = tf.assign(centroides, means) ``` 在開始運行圖之前,我們還必須創建一個操作來初始化所有變量: ```py init_op = tf.initialize_all_variables() ``` 此時一切準備就緒。 我們可以開始運行圖了: ```py sess = tf.Session() sess.run(init_op) for step in xrange(num_steps): _, centroid_values, assignment_values = sess.run([update_centroides, centroides, assignments]) ``` 在此代碼中,每次迭代中,更新每個初始點的質心和新的簇分配。 請注意,代碼指定了三個操作,它必須查看`run()`調用的執行,并按此順序運行。 由于要搜索三個值,`sess.run()`會在訓練過程中返回元素為三個 numpy 數組的數據結構,內容為相應張量。 由于`update_centroides`是一個結果是不返回的參數的操作,因此返回元組中的相應項不包含任何內容,因此被排除,用`_`來表示 [25] 。 對于其他兩個值,質心和每個簇的分配點,我們有興趣在完成所有`num_steps`次迭代后在屏幕上顯示它們。 我們可以使用簡單的打印。 輸出如下: ```py print centroid_values [[ 2.99835277e+00 9.89548564e-01] [ -8.30736756e-01 4.07433510e-01] [ 7.49640584e-01 4.99431938e-01] [ 1.83571398e-03 -9.78474259e-01]] ``` 我希望讀者的屏幕上有類似的值,因為這表明他已成功執行了本書這一章中展示的代碼。 我建議讀者在繼續之前嘗試更改代碼中的任何值。 例如`num_points`,特別是`k`的數量,并使用生成圖的先前代碼查看它如何更改`assignment_values`張量中的結果。 請記住,為了便于測試本章所述的代碼,可以從 Github [26] 下載。 包含此代碼的文件名是`Kmeans.py`。 在本章中,我們展示了 TensorFlow 的一些知識,特別是基本數據結構張量,它來自實現 KMeans 聚類算法的 TensorFlow 代碼示例。 有了這些知識,我們就可以在下一章中逐步使用 TensorFlow 構建單層神經網絡。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看