TensorFlow實戰之K-Means聚類演算法實踐

TensorFlow實戰之K-Means聚類演算法實踐
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

原文地址:這裡

Google 最近開源了它的第二代人工智慧與數值計算庫TensorFlow。TensorFlow由Google大腦團隊開發,並且能夠靈活地執行在多個平臺上——包括GPU平臺與移動裝置中。

TensorFlow的核心就是使用所謂的資料流,可以參考Wikipedia上的有關於Genetic Programming 的相關知識,譬如:

正如你理解的,整個以樹狀圖的架構來表示整個計算流。每個節點即代表一個操作,TensorFlow稱作OPS,即operations的縮寫。非葉子節點還是很好理解的,一些葉子節點可以是特殊的操作型別,譬如返回一個常量值(譬如上述樹中的7或者2.2)。其他的一些葉子節點,譬如X或者Y這樣的,被當做placeholders,即會在執行中被動態地注入值。如果仔細觀察上圖中的箭頭的指向,可以發現這些箭頭指向就表明了不同節點之間輸出的依賴關係。因此,Data(在TensorFlow中被稱為Tensors),會在不同的節點之間逆向流動,這就就是他們被稱為TensorFlow的原因。TensorFlow也提供了其他的基於影象抽象的元件,譬如持久化的資料儲存(被稱為Variables),以及在譬如神經網路這樣的應用中對於Variables中的引數微調而進行的優化手段。

TensorFlow提供了非常有好的Python的介面,在看本篇文章之前建議閱讀以下:

1.基礎環境的搭建或者筆者的翻譯

2.參閱這個例子 來對TensorFlow的程式碼風格有一個模糊的認識。

3.接下來這個解釋 會闡述TensorFlow中的基礎的元件。

4.參考詳細的例子 來看看TensorFlow是怎麼解決常見的ML問題的。

5.在瞭解上述的基本知識後,可以閱讀Python docs這個介面文件來作為開發中的參考。

接下來,我會以用TensorFlow來解決常見的K-Means問題作為例子來闡述如何使用它。

import tensorflow as tf
from random import choice, shuffle
from numpy import array
def TFKMeansCluster(vectors, noofclusters):
"""
K-Means Clustering using TensorFlow.
`vertors`應該是一個n*k的二維的NumPy的陣列,其中n代表著K維向量的數目
'noofclusters' 代表了待分的叢集的數目,是一個整型值
"""
noofclusters = int(noofclusters)
assert noofclusters < len(vectors)
#找出每個向量的維度
dim = len(vectors[0])
#輔助隨機地從可得的向量中選取中心點
vector_indices = list(range(len(vectors)))
shuffle(vector_indices)
#計算圖
#我們建立了一個預設的計算流的圖用於整個演算法中,這樣就保證了當函式被多次呼叫      #時,預設的圖並不會被從上一次呼叫時留下的未使用的OPS或者Variables擠滿
graph = tf.Graph()
with graph.as_default():
#計算的會話
sess = tf.Session()
##構建基本的計算的元素
##首先我們需要保證每個中心點都會存在一個Variable矩陣
##從現有的點集合中抽取出一部分作為預設的中心點
centroids = [tf.Variable((vectors[vector_indices[i]]))
for i in range(noofclusters)]
##建立一個placeholder用於存放各個中心點可能的分類的情況
centroid_value = tf.placeholder("float64", [dim])
cent_assigns = []
for centroid in centroids:
cent_assigns.append(tf.assign(centroid, centroid_value))
##對於每個獨立向量的分屬的類別設定為預設值0
assignments = [tf.Variable(0) for i in range(len(vectors))]
##這些節點在後續的操作中會被分配到合適的值
assignment_value = tf.placeholder("int32")
cluster_assigns = []
for assignment in assignments:
cluster_assigns.append(tf.assign(assignment,
assignment_value))
##下面建立用於計算平均值的操作節點
#輸入的placeholder
mean_input = tf.placeholder("float", [None, dim])
#節點/OP接受輸入,並且計算0維度的平均值,譬如輸入的向量列表
mean_op = tf.reduce_mean(mean_input, 0)
##用於計算歐幾里得距離的節點
v1 = tf.placeholder("float", [dim])
v2 = tf.placeholder("float", [dim])
euclid_dist = tf.sqrt(tf.reduce_sum(tf.pow(tf.sub(
v1, v2), 2)))
##這個OP會決定應該將向量歸屬到哪個節點
##基於向量到中心點的歐幾里得距離
#Placeholder for input
centroid_distances = tf.placeholder("float", [noofclusters])
cluster_assignment = tf.argmin(centroid_distances, 0)
##初始化所有的狀態值
##這會幫助初始化圖中定義的所有Variables。Variable-initializer應該定         ##義在所有的Variables被構造之後,這樣所有的Variables才會被納入初始化
init_op = tf.initialize_all_variables()
#初始化所有的變數
sess.run(init_op)
##叢集遍歷
#接下來在K-Means聚類迭代中使用最大期望演算法。為了簡單起見,只讓它執行固           #定的次數,而不設定一個終止條件
noofiterations = 100
for iteration_n in range(noofiterations):
##期望步驟
##基於上次迭代後算出的中心點的未知
##the _expected_ centroid assignments.
#首先遍歷所有的向量
for vector_n in range(len(vectors)):
vect = vectors[vector_n]
#計算給定向量與分配的中心節點之間的歐幾里得距離
distances = [sess.run(euclid_dist, feed_dict={
v1: vect, v2: sess.run(centroid)})
for centroid in centroids]
#下面可以使用叢集分配操作,將上述的距離當做輸入
assignment = sess.run(cluster_assignment, feed_dict = {
centroid_distances: distances})
#接下來為每個向量分配合適的值
sess.run(cluster_assigns[vector_n], feed_dict={
assignment_value: assignment})
##最大化的步驟
#基於上述的期望步驟,計算每個新的中心點的距離從而使叢集內的平方和最小
for cluster_n in range(noofclusters):
#收集所有分配給該叢集的向量
assigned_vects = [vectors[i] for i in range(len(vectors))
if sess.run(assignments[i]) == cluster_n]
#計算新的叢集中心點
new_location = sess.run(mean_op, feed_dict={
mean_input: array(assigned_vects)})
#為每個向量分配合適的中心點
sess.run(cent_assigns[cluster_n], feed_dict={
centroid_value: new_location})
#返回中心節點和分組
centroids = sess.run(centroids)
assignments = sess.run(assignments)
return centroids, assignments

需要注意的是,如果

for i in range(100):
x = sess.run(tf.assign(variable1, placeholder))

像上面那樣看似無害地在每次執行的時候建立一個新的OP(譬如tf.assign或者tf.zeros這樣的),這樣會一定的影響效能。作為替代的,你應該為每個任務定義一個特定的OP,然後在迴圈中呼叫這個OP。可以使用len(graph.get_operations())這個方法來檢測是否有冗餘的非必需的OPs。準確來說,sess.run應該是在迭代中唯一會與graph產生互動的方法。在上述程式碼的138~139行中可以看出,一系列的ops/Variables可以組合在sess.run中使用。

相關文章

人工智慧 最新文章