关于t-SNE降维方法

论文原图是这样的:

324e607f59ee

image.png

1. 什么是t-SNE:

全名是t-distributed Stochastic Neighbor Embedding(t-SNE),翻译过来应该可以叫学生t分布的随机邻点嵌入法。

t-SNE将数据点之间的相似度转换为概率。原始空间中的相似度由高斯联合概率表示,嵌入空间的相似度由“学生t分布”表示。t-SNE在一些降维方法中表现得比较好。因为t-SNE主要是关注数据的局部结构。

通过原始空间和嵌入空间的联合概率的Kullback-Leibler(KL)散度来评估可视化效果的好坏,也就是说用有关KL散度的函数作为loss函数,然后通过梯度下降最小化loss函数,最终获得收敛结果。

正式点来描述就是:

给定一组

math?formula=N 个点

math?formula=x_1%2C%20%5Ccdots%2C%20x_N%20%5Cin%20%5Cmathbb%7BR%7D%5Ed, t-SNE 首先计算

math?formula=x_i

math?formula=x_j之间的相似度

math?formula=p_%7Bij%7D。这个相似度公式定义为:

math?formula=p_%7Bij%7D%20%3D%20(p_%7Bi%20%5Cmid%20j%7D%20%2B%20p_%7Bj%20%5Cmid%20i%7D)%2F(2N)

对于每个

math?formula=i都有

math?formula=p_%7Bj%20%5Cmid%20i%7D%20%5Cpropto%20%5Cexp(%5C%7Cx_i-x_j%5C%7C%5E2%2F%5Csigma_i%5E2) ,这里就是用的高斯核了,只涉及到一个参数

math?formula=%5Csigma_i.

for some parameter

math?formula=%5Csigma_i. Intuitively, the value

math?formula=p_%7Bij%7D measures the `similarity' between points

math?formula=x_i and

math?formula=x_j. t-SNE then aims to learn the lower dimensional points

math?formula=y_1%2C%20%5Ccdots%2C%20y_N%20%5Cin%20%5Cmathbb%7BR%7D%5E2 such that if

math?formula=q_%7Bij%7D%20%5Cpropto%20(1%2B%5C%7Cy_i-y_j%20%5C%7C_2%5E2)%5E%7B-1%7D, then

math?formula=q_%7Bij%7D minimizes the Kullback–Leibler divergence of the distribution

math?formula=%5C%7Bq_%7Bij%7D%5C%7D from the distribution

math?formula=%5C%7Bp_%7Bij%7D%5C%7D. For a more detailed explanation of the t-SNE algorithm, see \cite{orig_tsne}.

直观地讲,该值

math?formula=p_%7Bij%7D衡量点与点之间的相似性。 然后t-SNE学习较低的维度,以便在低维空间中将分布的KL散度最小化。

这里简单列一下t-SNE的算法:

324e607f59ee

image.png

2. t-SNE的问题

t-SNE的计算复杂度很高,在数百万个样本数据集中可能需要几个小时,而PCA可以在几秒钟或几分钟内完成

只能限于二维或三维嵌入。

算法是随机的,具有不同种子的多次实验可以产生不同的结果。虽然选择loss最小的结果就行,但可能需要多次实验以选择超参数。

3. t-SNE的参数

这里列一下在TensorFlow中t-SNE相关的参数,其实参数很多,但是TensorFlow做了很多自动化处理,所以只考虑下面这几个:

Dimension: 这个只是考虑输出结果是二维空间还是三维空间。

Perplexity:这个可以叫困惑度,他说明了如何在数据的本地和全局方面之间取得平衡。也就是说通过困惑度去猜测某个点的邻居有多少个。这个对邻点数量的猜测可以对最后结果的图片复杂度影响很大。我们通过调整Perplexity可以分析出很多不同结果的降维图片。在上面的那篇原始论文(Visualizing Data using t-SNE .)中提到:“The performance of SNE is fairly robust to changes in the perplexity, and typical values are between 5 and 50”, 也就是t-SNE的鲁棒性很不错,一般在5到50之间调整就可以了

Learning Rate: 这个学习率是在运行t-SNE算法的时候,进行梯度更新的步长。学习率的设置可以自由调整,但是也要根据样本量的大小来调整,样本量少学习率就调小一点。

Supervise: 这个参数是调整标签的重要程度的,我们输入的数据都是成对的(数据,标签),这个参数可以从0(不用标签)到10(全部标签都用到)进行调整。具体细节可以参考来自IBN的这篇文章Interactive supervision with TensorBoard

4. 实验工具:TensorBoard

TensorFlow是一个开源软件库,在机器学习,深度学习以及强化学习这些领域应用最广泛的最基础的工具,他好处之一是自动计算微分,然后很容易搭建神经网络并进行训练。

TensorBoard 是用于可视化 TensorFlow 模型的训练过程的工具(the flow of tensors,在你安装 TensorFlow 的时候就已经安装了 TensorBoard。

他的组成比较复杂,功能比较多,参考这个结构:

324e607f59ee

image.png

我们主要只是使用EMBEDDINGS功能。

5. TensorFlow安装

安装Python 3.7.2

pip安装tensorflow 1.13.1

6. 实验设定

这次实验我们只做做基础的使用MNIST观察下t-SNE的结果,只用了1000张手写数字图片。

MNIST是一个简单的计算机视觉数据集。它包含如下所示的手写数字的图片集:

324e607f59ee

image.png

下载的数据包含两部分,6万个训练数据(mnist.train)和10万各测试数据(mnist.test)。这个区分是非常重要的:在机器学习领域,我们分离出一部分数据,这部分数据我们不用来作训练,以此来保证我们学到的是通用的规则。

就像前面提到的那样,每个MNIST数据有都有两个部分:一个手写数字的图片,以及一个相应的标签。我们用"xs"表示图片,用"ys"表示标签。训练数据和测试数据都有xs和ys,以测试数据举例来说,训练图片是mnist.train.images,训练标签是mnist.train.labels。

每个图片都是28X28像素,我们可以将它理解为一个大数组。

324e607f59ee

image.png

这个数组可以flatten为一个包含28X28=784个数字的向量,如何flatten这个数组是没有关系的,因为我们在所有图片中都是相同的。从这个角度看,MNIST图片只是一堆784维空间中的一个点

我们将mnist看作是一个[60000,784]的张量(an n-dimensional array) 。第一个维度是图片的索引,第二个维度图片上像素的索引。这个张量的每个实体都是某个图片,某个像素的,像素亮度用0到1之间的数字表示

MNIST对应的标签是0~9的数字,描述了给定图片是哪个数字。基于本教程的目的,我们想要我们的标签作为"one-hot vectors",one-hot vector是一个大多数维度都是0,只有一个维度为1的向量。在我们这个例子里,第n个数字会表示为一个第n位为1的向量,比如0会表示为[1,0,0,0,0,01,0,0,0,0,0,0,0,0,0,0],相应的,mnist.train.labels是一个[60000,10]的float数组。

7. 实验的代码

我们实验的代码如下

这里我们主要使用的网络架构是这样的,输入图片进入第一层卷积神经网络,使用32个[5,5]形状的滤波器,并使用补偿为2的最大池化操作。然后进入第二层卷积神经网络,使用64个[5,5]形状的滤波器,并使用补偿为2的最大池化操作。最后把得到的张量铺平成一个一维度的向量,通过一个512个cell的全连接网络,最后再进入soft输出结果是数字1-10的概率。

使用cross-entropy作为损失函数,并使用优化算法

#导入相关的库

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data

import os

import time

from tensorflow.contrib.tensorboard.plugins import projector

import matplotlib.pyplot as plt

import numpy as np

#这里用slim这个API来进行卷积网络构建

slim = tf.contrib.slim

#定义卷积神经网络模型

#网络架构是卷积网络--最大池化--卷积网络--最大池化---flatten---MLP-softmax的全连接MLP

def model(inputs, is_training, dropout_rate, num_classes, scope='Net'):

inputs = tf.reshape(inputs, [-1, 28, 28, 1])

with tf.variable_scope(scope):

with slim.arg_scope([slim.conv2d, slim.fully_connected],

normalizer_fn=slim.batch_norm):

net = slim.conv2d(inputs, 32, [5, 5], padding='SAME', scope='conv1')

net = slim.max_pool2d(net, 2, stride=2, scope='maxpool1')

tf.summary.histogram("conv1", net)

net = slim.conv2d(net, 64, [5, 5], padding='SAME', scope='conv2')

net = slim.max_pool2d(net, 2, stride=2, scope='maxpool2')

tf.summary.histogram("conv2", net)

net = slim.flatten(net, scope='flatten')

fc1 = slim.fully_connected(net, 1024, scope='fc1')

tf.summary.histogram("fc1", fc1)

net = slim.dropout(fc1, dropout_rate, is_training=is_training, scope='fc1-dropout')

net = slim.fully_connected(net, num_classes, scope='fc2')

return net, fc1

def create_sprite_image(images):

"""更改图片的shape"""

if isinstance(images, list):

images = np.array(images)

img_h = images.shape[1]

img_w = images.shape[2]

n_plots = int(np.ceil(np.sqrt(images.shape[0])))

sprite_image = np.ones((img_h * n_plots, img_w * n_plots))

for i in range(n_plots):

for j in range(n_plots):

this_filter = i * n_plots + j

if this_filter < images.shape[0]:

this_img = images[this_filter]

sprite_image[i * img_h:(i + 1) * img_h,

j * img_w:(j + 1) * img_w] = this_img

return sprite_image

def vector_to_matrix_mnist(mnist_digits):

"""把正常的mnist数字图片(batch,28*28)这个格式,转换为新的张量形状(batch,28,28)"""

return np.reshape(mnist_digits, (-1, 28, 28))

def invert_grayscale(mnist_digits):

"""处理下图片颜色,黑色变白,白色边黑"""

return 1 - mnist_digits

if __name__ == "__main__":

# 定义参数

#学习率

learning_rate = 1e-4

#定义迭代参数

total_epoch = 500

#定义批量

batch_size = 200

#程序运行中打印频率

display_step = 20

#程序运行中保存结果的频率

save_step = 100

load_checkpoint = False

checkpoint_dir = "checkpoint"

checkpoint_name = 'model.ckpt'

#结果存放的路径

logs_path = "logs"

#定义我们使用多少个图片

test_size = 1000

#定义第二层路径

projector_path = 'projector'

# 网络参数

n_input = 28 * 28 # 每个图片是28*28个像素,也就是784个特征

n_classes = 10 # MNIST数据集有0-9是个类别的结果

dropout_rate = 0.5 # Dropout的比率

mnist = input_data.read_data_sets('MNIST-data', one_hot=True)

# 定义计算图

x = tf.placeholder(tf.float32, [None, n_input], name='InputData')

y = tf.placeholder(tf.float32, [None, n_classes], name='LabelData')

is_training = tf.placeholder(tf.bool, name='IsTraining')

keep_prob = dropout_rate

logits, fc1 = model(x, is_training, keep_prob, n_classes)

with tf.name_scope('Loss'):

loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))

tf.summary.scalar("loss", loss)

with tf.name_scope('Accuracy'):

correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))

accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

tf.summary.scalar("accuracy", accuracy)

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)

projector_dir = os.path.join(logs_path, projector_path)

path_metadata = os.path.join(projector_dir,'metadata.tsv')

path_sprites = os.path.join(projector_dir, 'mnistdigits.png')

# 检查结果目录的状态

if not os.path.exists(projector_dir):

os.makedirs(projector_dir)

# 这里进行嵌入

mnist_test = input_data.read_data_sets('MNIST-data', one_hot=False)

batch_x_test = mnist_test.test.images[:test_size]

batch_y_test = mnist_test.test.labels[:test_size]

embedding_var = tf.Variable(tf.zeros([test_size, 1024]), name='embedding')

assignment = embedding_var.assign(fc1)

config = projector.ProjectorConfig()

embedding = config.embeddings.add()

embedding.tensor_name = embedding_var.name

embedding.metadata_path = os.path.join(projector_path,'metadata.tsv')

embedding.sprite.image_path = os.path.join(projector_path, 'mnistdigits.png')

embedding.sprite.single_image_dim.extend([28,28])

# 初始化变量

init = tf.global_variables_initializer()

# 'Saver' op to save and restore all the variables

saver = tf.train.Saver()

merged_summary_op = tf.summary.merge_all()

# 运行计算图

with tf.Session() as sess:

sess.run(init)

# Restore model weights from previously saved model

prev_model = tf.train.get_checkpoint_state(checkpoint_dir)

if load_checkpoint:

if prev_model:

saver.restore(sess, prev_model.model_checkpoint_path)

print('Checkpoint found, {}'.format(prev_model))

else:

print('No checkpoint found')

summary_writer = tf.summary.FileWriter(logs_path, graph=tf.get_default_graph())

projector.visualize_embeddings(summary_writer, config)

start_time = time.time()

# 开始训练

for epoch in range(total_epoch):

batch_x, batch_y = mnist.train.next_batch(batch_size)

# reshapeX = np.reshape(batch_x, [-1, 28, 28, 1])

# 开始反向传播算法

sess.run(optimizer, feed_dict={x: batch_x, y: batch_y,

is_training: True})

if epoch % display_step == 0:

# 计算损失和精度

cost, acc, summary = sess.run([loss, accuracy, merged_summary_op],

feed_dict={x: batch_x,

y: batch_y,

is_training: False})

elapsed_time = time.time() - start_time

start_time = time.time()

print('epoch {}, training accuracy: {:.4f}, loss: {:.5f}, time: {}'

.format(epoch, acc, cost, elapsed_time))

summary_writer.add_summary(summary, epoch)

if epoch % save_step == 0:

# 保存训练的结果

sess.run(assignment, feed_dict={x: mnist.test.images[:test_size],

y: mnist.test.labels[:test_size], is_training: False})

checkpoint_path = os.path.join(checkpoint_dir, checkpoint_name)

save_path = saver.save(sess, checkpoint_path)

print("Model saved in file: {}".format(save_path))

# 保存结果

saver.save(sess, os.path.join(logs_path, "model.ckpt"), 1)

# 创建可视化的图片

to_visualise = batch_x_test

to_visualise = vector_to_matrix_mnist(to_visualise)

to_visualise = invert_grayscale(to_visualise)

sprite_image = create_sprite_image(to_visualise)

# 保存可视化的图片

plt.imsave(path_sprites, sprite_image, cmap='gray')

# 写文件

with open(path_metadata, 'w') as f:

f.write("Index\tLabel\n")

for index, label in enumerate(batch_y_test):

f.write("%d\t%d\n" % (index, label))

print("训练完成")

8. 实验结果

在上面的代码训练完成之后,我们把结果保存在了代码中定义的目录logs中。我们直接进入logs目录的父目录然后在CMD中启动tensorboard即可:

​ tensorboard --logdir logs

启动过程如下所示:

324e607f59ee

image.png

然后我们通过chrome浏览器访问tensorboard,

我们在PROJECTOR可以看到t-SNE的结果:

324e607f59ee

image.png

这个记过看起来这1000个图片在三维空间上确实是把不同的图片分开了。Perplexity,learning rate与supervise都随意调的,可以仔细调整看看。然后这里只跑了184次迭代,因为发现这里效果看起来不错,训练的迭代次数往后越多,这些堆分开得越远。效果很好,但是不好看。

我们看看在二维空间的可视化结果:

324e607f59ee

image.png

同样的参数下也只训练了182个迭代,效果不错的。

此外最后我们再看看PCA降维的效果,感觉和T-SNE差别比较大,没有深入研究,可能TSNE是在动态训练,PCA这里只是静态的。注意PCA在三维上是需要手动选择特征的。

324e607f59ee

image.png

T SNE降维matlab程序,关于t-SNE降维方法相关推荐

  1. 仁慈型dea matlab程序,数据包络分析(DEA)方法..docx

    数据包络分析(DEA)方法. 二.数据包络分析(DEA)方法数据包络分析(data envelopment analysis, DEA)是由著名运筹学家Charnes, Cooper和Rhodes于1 ...

  2. 线性规划单纯形法的matlab程序,线性规划单纯形法的MATLAB实现_数学专业.doc

    摘要:运筹学有着长远的发展历史,并且不断地发展变化出许多分支理论,线性规划是运筹学中专研较早,发展比较快速,对现实社会作用涵盖面广,理论系统趋于成熟的一个重要分支,虽然其只是运筹学的一小部分,但是作用 ...

  3. 有确定项微分方程的matlab程序,微分方程的数值解法matlab四阶龙格—库塔法课件...

    <微分方程的数值解法matlab四阶龙格-库塔法课件>由会员分享,可在线阅读,更多相关<微分方程的数值解法matlab四阶龙格-库塔法课件(36页珍藏版)>请在人人文库网上搜索 ...

  4. fcm算法的MATLAB实现,FCM算法的matlab程序(初步)

    FCM算法的matlab程序 1.采用iris数据库 iris_data.txt 5.1 3.5 1.4 0.2 4.9 3 1.4 0.2 4.7 3.2 1.3 0.2 4.6 3.1 1.5 0 ...

  5. matlab 流程计算方法,吸波材料LLG公式计算复磁导率的过程及matlab程序

    看到一篇paper,利用Landau-Lifshitz-Gilbert 公式计算片状颗粒的复磁导率.(JAP 107,033913, 2010) http://scitation.aip.org/co ...

  6. matlab图像定位分割,車牌定位matlab程序:通過hsv彩色分割方式定位車牌

    最近看了<基於數字圖像處理的車牌識別研究>這篇論文,對車牌識別知識講的很仔細,推薦. 1.(摘自<基於數字圖像處理的車牌識別研究>) 通過對大量車牌圖像的分析,可以發現對於具有 ...

  7. matlab dfp法,DFP算法及Matlab程序.docx

    DFP算法及Matlab程序 作业二 用DFP算法求解,取,.一.求解:求迭代点x1令,得的极小值点,所以得:于是,由DFP修正公式有下一个搜索方向为求迭代点x2令,得的极小值点于是得:,所以:,因H ...

  8. matlab程序eX2_2是什么意思,第2章 MATLAB程序设计

    第2章MATLAB程序设计基础 Matlab以矩阵为运算单元,除非特殊需要,矩阵不必事先定义维数大小.Matlab还提供了丰富的矩阵运算函数,如求逆矩阵的inv函数,求方阵行列式的det函数,求矩阵特 ...

  9. 不用工具箱的神经网络matlab程序_MATLAB中的神经网络工具箱(2)函数命令及模型搭建...

    前面介绍了神经网络工具箱GUI的使用,它功能强大可以直接生成脚本.但是函数命令的灵活性是GUI所不及的.也应该有所了解. 神经网络函数命令 1.网络创建函数 函数名称 功能 fitnet 创建函数拟合 ...

  10. matlab解决多旅游商问题,多旅行商问题的matlab程序

    %多旅行商问题的matlab程序 function varargout = mtspf_ga(xy,dmat,salesmen,min_tour,pop_size,num_iter,show_prog ...

最新文章

  1. python太阳花绘图_python中turtle如何画太阳花?
  2. 两个变量交换值 和按位异或的理解
  3. NET插件系统之四——提升系统搜索插件和启动速度的思考
  4. 移动游戏高速增长为市场营销带来新的机会
  5. 利用Java的BigDecimal与马青公式精确计算π后10000位,
  6. 创业者具备的五大技能_一、如今大学生创业需要具备哪些知识与技能?
  7. 汕头市队赛 SRM16 T2
  8. Servlet与JSP间的传值问题
  9. Maven:导入Oracle的jar包时出现错误
  10. actionscript 3.0 怎么写android 程序,(ActionScript3.0笔记)第一个程序HelloWorld!
  11. Python isinstance() 函数用法及实例另类高级使用(附带classmethod 修饰符、json.dumps)
  12. MobileNet V2简单总结
  13. LeetCode刷题(Python)——在排序数组中查找元素的第一个和最后一个位置
  14. 明晚9点 华为新款折叠屏手机MateXs即将闪亮登场
  15. SpringBoot POM web开发(spring-boot-starter-web)
  16. 通过prompt方法增强开放领域问答模型
  17. 学生成绩管理系统实验报告_学生成绩管理系统设计
  18. NDoc使用简要手册增加了例子代码
  19. 海格里斯智能自动化立体库仓储管理系统 物流生鲜电商冷链立库应用
  20. 自定义Switch(秒懂)

热门文章

  1. Windows 7下可以使用的虚拟光驱软件
  2. Cisco 模拟器rstp生成树
  3. 打开我的收藏夹 -- Python篇
  4. html 源码_html制作个人博客网站模板源码下载
  5. linux加载dl580网卡驱动,HP DL580G5安装centos下的阵列卡驱动
  6. Proxomitron之天涯只看规则
  7. 基于ZigBee设计的天气监测系统
  8. struts框架——ActionForm+DynaActionForm
  9. dreamweaver php网站模板,用DreamWeaver模板工具批量制作网页
  10. Windows XP SP3 下 High Definition Audio 声卡安装方法