聚類(K-means)實現手寫數字識別-2
阿新 • • 發佈:2020-12-09
其他實現手寫數字識別的方法:
1.KNN實現手寫數字識別
2. 卷積神經網路(CNN)實現手寫數字識別
3. 全連線神經網路實現手寫數字識別
4. 聚類(K-means)實現手寫數字識別
- 實驗資料是老師收集了所有人的手寫數字圖片,且經過處理將影象生成了.txt檔案,如何生成點選這,如下圖
- 程式碼實現
from __future__ import print_function
import numpy as np
import tensorflow as tf
from tensorflow.contrib.factorization import KMeans
from os import listdir
from keras.utils import to_categorical
"""
函式說明:將32x32的二進位制影象轉換為1x1024向量
"""
def img2vector(filename):
# 建立1x1024零向量
returnVect = np.zeros((1, 1024))
# 開啟檔案
fr = open(filename)
# 按行讀取
for i in range(32):
# 讀一行資料
lineStr = fr.readline()
# 每一行的前32個元素依次新增到returnVect中
for j in range(32):
returnVect[0, 32 * i + j] = float(lineStr[j])
# 返回轉換後的1x1024向量
return returnVect
'''
函式說明:獲取標籤
'''
def getLabel(Datapath):
# 訓練集的Labels
hwLabels = []
# 返回Datapath目錄下的檔名
trainingFileList = listdir(Datapath)
# 返回資料夾下檔案的個數
m = len( trainingFileList)
# 從檔名中解析出訓練集的類別
for i in range(m):
# 獲得檔案的名字
fileNameStr = trainingFileList[i]
# 獲得分類的數字
classNumber = int(fileNameStr.split('_')[0])
# 將獲得的類別新增到hwLabels中
hwLabels.append(classNumber)
return hwLabels
'''
函式說明:獲取資料
'''
def getData(Datapath):
# 返回train目錄下的檔名
trainingFileList = listdir(Datapath)
# 返回資料夾下檔案的個數
m = len(trainingFileList)
# 初始化訓練的Mat矩陣,訓練集
trainingMat = np.zeros((m, 1024))
for i in range(m):
# 獲得檔案的名字
fileNameStr = trainingFileList[i]
# 將每一個檔案的1x1024資料儲存到trainingMat矩陣中
trainingMat[i, :] = img2vector(Datapath+'/%s' % (fileNameStr))
return trainingMat
# 載入資料
train_images = getData('train')
test_images = getData('testless')
train_labels = getLabel('train')
train_labels = to_categorical(train_labels)
test_labels = getLabel('testless')
test_labels = to_categorical(test_labels)
full_data_x = train_images
# 引數
num_steps = 1000 # 訓練次數
batch_size = 10 # 每一批的樣本數
k = 60 # clusters的數量
num_classes = 10 # 10分類
num_features = 1024 # 每張圖片是32*32
# 輸入圖片
X = tf.placeholder(tf.float32, shape=[None, num_features])
# Labels (將標籤分配給質心並用於測試)
Y = tf.placeholder(tf.float32, shape=[None, num_classes])
# K-Means 的引數
# inputs:輸入張量或輸入張量列表。假設資料點先前已被隨機置換。
# num_clusters:一個整數張量,指定簇的數量。如果initial_clusters是張量或numpy陣列,則忽略此引數。
# distance_metric:用於群集的距離度量。支援的選項:“squared_euclidean”,“cosine”。
# use_mini_batch:如果為true,請使用小批量k-means演算法。
# mini_batch_steps_per_iteration:更新的叢集中心同步回主副本的步驟數。
kmeans = KMeans(inputs=X, num_clusters=k, distance_metric='cosine',
use_mini_batch=True)
# 建立 KMeans 模型
training_graph = kmeans.training_graph()
# 返回值
# all_scores: 每個向量到每個簇的距離,是一個[樣本數, 簇數]的矩陣
# cluster_idx: 每個樣本被分到的簇的標記,為([樣本數], type)的元組
# scores: 每個樣本到其被分到的簇的距離,為[樣本數]大小的矩陣,
# cluster_centers_initialized:返回bool值,cluster是否被初始化(不知道有什麼用)
# init_op: 初始化操作,sess init的時候需要傳入樣本
# training_op: 訓練操作
if len(training_graph) > 6:
(all_scores, cluster_idx, scores, cluster_centers_initialized,
cluster_centers_var, init_op, train_op) = training_graph
else:
(all_scores, cluster_idx, scores, cluster_centers_initialized,
init_op, train_op) = training_graph
cluster_idx = cluster_idx[0]
avg_distance = tf.reduce_mean(scores) # 用於計算張量tensor沿著指定的數軸(tensor的某一維度)上的的平均值
# 初始化變數 (用預設值)
init_vars = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init_vars, feed_dict={X: full_data_x})
sess.run(init_op, feed_dict={X: full_data_x}) # 使用之前 一定要使用資料初始化 KMeans
# 訓練
for i in range(1, num_steps + 1):
_, d, idx = sess.run([train_op, avg_distance, cluster_idx],
feed_dict={X: full_data_x})
if i % 10 == 0 or i == 1:
print("Step %i, Avg Distance: %f" % (i, d))
# 為每個質心分配標籤
# 使用每次訓練的標籤計算每個質心的標籤總數
# 計算樣本到最近的質心
counts = np.zeros(shape=(k, num_classes))
# print(len(idx))
for i in range(len(idx)):
counts[idx[i]] += train_labels[i]
# 將最頻繁的標籤分配給質心
labels_map = [np.argmax(c) for c in counts]
# print(labels_map)
labels_map = tf.convert_to_tensor(labels_map) # 將給定值轉換為張量
# 評估
# 查詢:centroid_id 的標籤
cluster_label = tf.nn.embedding_lookup(labels_map, cluster_idx)
# print(cluster_label)
# 計算準確路
# tf.equal(x,y,name=None)
# 判斷,x, y 是不是相等,它的判斷方法不是整體判斷,
# 而是逐個元素進行判斷,如果相等就是True,不相等,就是False
# 由於是逐個元素判斷,所以x,y 的維度要一致。
# tf.cast():用於改變某個張量的資料型別
# tf.argmax(input,axis)根據axis取值的不同返回每行或者每列最大值的索引。
# axis=0時比較每一列的元素,將每一列最大元素所在的索引記錄下來,
# 最後輸出每一列最大元素所在的索引陣列。
# axis=1的時候,將每一行最大元素所在的索引記錄下來,
# 最後返回每一行最大元素所在的索引陣列
correct_prediction = tf.equal(cluster_label, tf.cast(tf.argmax(Y, 1), tf.int32))
accuracy_op = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 測試模型
test_x, test_y = test_images, test_labels
print("Test Accuracy:", sess.run(accuracy_op, feed_dict={X: test_x, Y: test_y}))