tensorflow 5. K均值回归用于手写数字识别

65 篇文章 4 订阅
34 篇文章 4 订阅

本代码展示的是tensorflow中K均值算法。
代码原始地址在这里

下面这段摘自百度百科:
K-means算法是硬聚类算法,是典型的基于原型的目标函数聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法得到迭代运算的调整规则。

代码里面并没有把K的值直接设为10,而是设为25.然后把这25簇分为10类(对应10个数字)。相当于K均值之后用最近邻再次分类,思路很赞,调整K的值可以无限逼近拟合现实。K值用来调整计算粒度。K与训练样本相同,效果就和最近邻一样了。

经过测试,K值不同最终获得的准确率也不一样:

K值准确率
100.52
250.71
500.8
1000.86
2000.90
5000.93
10000.94
50000.96

个人感觉,K值越大,分类越细,越是能更多的拟合向量的分布特征。但是综合来看,K=100是性价比较高的数字。K值越大,计算的越慢。K=5000让我的i7-8550U压力山大, 0.96差不多是极限了吧,没有心思测试10000的K值了。

源码

(下文中的图心应该指别人说的质心,不知道怎么翻译,就这么着了)

import numpy as np
import tensorflow as tf
from tensorflow.contrib.factorization import KMeans

# 本代码演示K均值的用法, tensorflow版本必须大于等于V1.1.0
# 代码项目:Project: https://github.com/aymericdamien/TensorFlow-Examples/

# 由于tensorflow实现的K均值算法无法从GPU中获得额外好处,所以我们忽略GPU设备
import os

os.environ['CUDA_VISIBLE_DEVICES'] = ''

# 导入MNIST数据集
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('../data', one_hot=True)
full_data_x = mnist.train.images # shape:(55000, 784),注意记住这个55000,理解后面会用到

# 模型超参数
num_steps = 50  # 训练的总步数
batch_size = 1024  # 每个batch的样本数
k = 25  # K的大小
num_classes = 10  # 十个数字,这也是模型最终分类的个数
num_features = 784  # 每个图片都是28X28,共784个像素

# 输入图片
X = tf.placeholder(tf.float32, shape=[None, num_features])
# 标注
Y = tf.placeholder(tf.float32, shape=[None, num_classes])

# K-Means的参数,其实是从库里使用提前封装好的图
kmeans = KMeans(inputs=X, num_clusters=k, distance_metric='cosine', use_mini_batch=True)

# 构建K-Means的计算图
training_graph = kmeans.training_graph()

if len(training_graph) > 6:  # tensorflow 1.4及以上版本
    (all_scores, cluster_idx, scores, cluster_cnters_initialized,
     cluster_cnters_var, init_op, train_op) = training_graph
else:
    (all_scores, cluster_idx, scores, cluster_cnters_initialized,
     init_op, train_op) = training_graph

cluster_idx = cluster_idx[0] # 存放所有数据的图心序号
avg_distance = tf.reduce_mean(scores) # 存放平均距离

# 初始化变量
init_vars = tf.global_variables_initializer()

# 建立一个tensorflow会话
sess = tf.Session()

# 运行初始化操作
sess.run(init_vars, feed_dict={X: full_data_x})
sess.run(init_op, feed_dict={X: full_data_x})

# 训练
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('步骤 %i, 平均距离是:%f' % (i, d))

# 给每个图心分配一个标签
# 计算每个图心的样本个数,把样本归入离它最近的图心(使用idx)
counts = np.zeros(shape=(k, num_classes))  # counts的shape是(25, 10),用于存放25个图心分类的频率计数
for i in range(len(idx)):
    # idx的shape是(55000,),每个成员都是0~24之间的值,对应所属图心的编号
    counts[idx[i]] += mnist.train.labels[i]
    # mnist.train.labels的shape是(55000, 10), 每个成员都是独热编码,用来标注属于哪个数字

# 将最高频的标注分配给图心。 len(labels_map)是25,也就是每个图心一个成员,记录每个图心所属的数字分类
labels_map = [np.argmax(c) for c in counts]
# 转换前,labels_map的shape为(25,)
labels_map = tf.convert_to_tensor(labels_map)
# 此时labels_map变成了一个const op,输出就是上面(25,)包含的值

# 评估模型。下面开始构建评估计算图
# 注意:centroid_id就是对应label
cluster_label = tf.nn.embedding_lookup(labels_map, cluster_idx)
# cluster_idx输出的tensor,每个成员都映射到labels_map的一个值。
# cluster_label的输出就是映射的label值,后面用来跟标注比较计算准确度

# 计算准确率
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 = mnist.test.images, mnist.test.labels
print("测试准确率:", sess.run(accuracy_op, feed_dict={X: test_x, Y: test_y}))
输出:
Connected to pydev debugger (build 173.4301.16)
Extracting ../data\train-images-idx3-ubyte.gz
Extracting ../data\train-labels-idx1-ubyte.gz
Extracting ../data\t10k-images-idx3-ubyte.gz
Extracting ../data\t10k-labels-idx1-ubyte.gz
2018-03-29 10:57:11.388774: I C:\tf_jenkins\home\workspace\rel-win\M\windows\PY\36\tensorflow\core\platform\cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
步骤 1, 平均距离是:0.341471
步骤 10, 平均距离是:0.221609
步骤 20, 平均距离是:0.220328
步骤 30, 平均距离是:0.219776
步骤 40, 平均距离是:0.219419
步骤 50, 平均距离是:0.219154
测试准确率: 0.7127

进程已结束,退出代码0
本程序牵涉到的知识点:
  • convert_to_tensor
  • embedding_lookup

tf.convert_to_tensor用于将一个变量转化为计算图中的const op。
使用pycharm调试,查看转化后labels_map的op为:

name: "Const_2"
op: "Const"
attr {
  key: "dtype"
  value {
    type: DT_INT32
  }
}
attr {
  key: "value"
  value {
    tensor {
      dtype: DT_INT32
      tensor_shape {
        dim {
          size: 25
        }
      }
      tensor_content: "\003\000\000\000\001\000\000\000\010\000\000\000\006\000\000\000\002\000\000\000\006\000\000\000\004\000\000\000\005\000\000\000\007\000\000\000\t\000\000\000\003\000\000\000\003\000\000\000\002\000\000\000\004\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\007\000\000\000\001\000\000\000\002\000\000\000\003\000\000\000\006\000\000\000\001\000\000\000\005\000\000\000"
    }
  }
}

(下面这段来自知乎:https://www.zhihu.com/question/52250059)
embedding_lookup(params, ids)其实就是按照ids顺序返回params中的第ids行。
比如说,ids=[1,3,2],就是返回params中第1,3,2行。返回结果为由params的1,3,2行组成的tensor.

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值