在机器学习和深度学习领域,特征往往是高维度的,然而不幸的是,我们的电脑屏幕是二维的,我们的人眼也只能观察最多三维,所以必须对特征进行降维之后才能可视化。

一、准备工作:提取MNIST在LeNet5中的特征

  方法很简单,我们在第一节的代码上修改,我们取出倒数第二个全连接层的输出特征,有84维。代码如下,多输出一个emb。

def forward(self, x):
    x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
    x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))
    x = x.view(-1, self.num_flat_features(x))
    x = F.relu(self.fc1(x))
    emb = F.relu(self.fc2(x))
    x = self.fc3(emb)
    return emb,x

  然后用训练好的模型过一遍数据集,得到数据集所有样本的嵌入向量embs,同时也收集labels用于后面按类别画图:

model.eval()
embs = []
labels = []
for data, target in test_loader:
    data, target = data.cuda(), target.cuda()
    emb,output = model(data)
    embs.append(emb.data.cpu().numpy())
    labels.append(target.data.cpu().numpy())
embs = np.concatenate(embs)
labels = np.concatenate(labels)

二、使用sklearn中的t-SNE可视化

  使用tSNE可视化不用更改网络结构,直接对原网络得到的输出进行处理即可,sklearn中已经封装好此功能:

from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, learning_rate=200, metric='cosine',n_jobs=-1)
tsne.fit_transform(embs)
outs_2d = np.array(tsne.embedding_)

import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
css4 = list(mcolors.CSS4_COLORS.keys())
#我选择了一些较清楚的颜色,更多的类时也能画清晰
color_ind = [2,7,9,10,11,13,14,16,17,19,20,21,25,28,30,31,32,37,38,40,47,51,
         55,60,65,82,85,88,106,110,115,118,120,125,131,135,139,142,146,147]
css4 = [css4[v] for v in color_ind]
for lbi in range(10):
    temp = outs_2d[labels==lbi]
    plt.plot(temp[:,0],temp[:,1],'.',color=css4[lbi])
plt.title('feats dimensionality reduction visualization by tSNE,test data')

  注意在TSNE的参数中可以指定距离类型metric,默认是euclidean,我这里使用了cosine,还可以是correlation等其他距离。
在这里插入图片描述
在这里插入图片描述

图1. 用sklearn的tSNE法画出MNIST嵌入特征的分布,两次

  可以看出,由于随机种子的不同,每次画出来的结果不一样,每个类别的形态是大致一样的,但相对位置会有变化,这也说明tSNE在降维的时候能够保证较近的点的距离关系,但不能保证较远的点的距离关系,通常也就是类内和类间能够很好的体现,但类间的距离关系不能体现。比如黑色和红色的类在第一张图中很近,但在第二张图中很远。或者从另一个角度说,tSNE在降维的同时,也具备一定的分类能力。

三、使用hypertools中的多种降维方法

  hypertools是Kaggle推出的一种降维工具包,集成了多种降维算法,如PCA、TSNE、Isomap、UMAP等。此外还有聚类算法和对齐算法等,用起来更加方便。可以用pip install hypertools安装。降维和画图的核心代码用一行搞定:

import hypertools as hyp
import matplotlib.pyplot as plt
hyp.plot(embs,'.',reduce='TSNE',ndims=2,hue=labels)
plt.title('TSNE')

  注意,这个hyp.plot画的图内部也是调用matplotlib.pyplot,所以可以直接混合使用plt的命令实现更多的画图功能,如上面的plt.title()。下面给出各种降维方法的效果:
在这里插入图片描述

图2. 用hypertools的各种降维方法画出MNIST嵌入特征的分布

  通常TSNE和UMAP两种方法可视化效果较好,其他的如PCA更多的保留了样本间距离信息的比例关系,反而看起来各类分的不是那么开,而UMAP则更极端一些,它把各类间区分的相当开。
使用hypertools也可以实现聚类,带的聚类算法有K-Means, AgglomerativeClustering, Birch, FeatureAgglomeration, SpectralClustering这几种。如果没有labels信息,可以先聚类,用聚类结果代替labels画出各簇的图:

clust = hyp.cluster(embs, cluster='KMeans',n_clusters = 10)
hyp.plot(embs,'.',reduce='TSNE',ndims=2,hue=clust)
plt.title('TSNE, clutering by KMeans')

在这里插入图片描述

图3. 用hypertools的KMeans聚类后再用TSNE画出MNIST嵌入特征的分布

  最后说一个小细节,注意看图3的各簇中仍有一些其他簇的“噪点”,这些噪点应是TSNE分类和KMeans分类的误差造成的,这也说明图2中的噪点也不全是标注错误造成的。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐