2018 年 12 月

33 卷,第 12

测试运行-使用 CNTK 的可视化效果的 Autoencoders

通过James McCaffrey

James McCaffrey假设你有描述一组人员的数据。每个人员为由一个年龄值和高度值。如果你想要关系图数据无法保留时间置于 x 轴,y 轴上的高度和为女性使用彩色圆点 (例如,蓝色表示男性) 和粉红色。数据有两个维度,因此没有问题。

但是,如果您的数据具有六个维度,如年龄、 高度、 weight、 收入、 债务、 ZIP 代码?要绘制此类数据,一种方法是使用神经网络 autoencoder 的两个维度下将六个高维数据压缩。将会丢失一些信息,但您将能够构建 2D 图形。

了解本文所述观点的最佳方式是查看图 1 中的演示程序。演示数据有 1,797 项。每个项的维数 64 和属于 10 个类之一。演示创建 Microsoft Cognitive Toolkit (CNTK) 神经网络 autoencoder 压缩到两个维度,标记为 component1 和 componet2,每个项,然后图形显示结果。我们可以看到数据中的相关模式。例如,类 0 (黑色的点) 的数据项各不相同类 7 项 (橙色点)。但类 8 项 (红点) 具有大量具有类 5 项目 (浅绿色圆点) 的相似性。

Autoencoder 可视化效果使用 CNTK 演示运行
图 1 Autoencoder 可视化效果使用 CNTK 演示运行

本文假定具有 C 系列语言的中级或更好的编程技能和基本熟悉机器学习,但并不假定您知道 autoencoders 有关的任何信息。所有的演示代码是本文中介绍。完整源代码和演示程序使用的数据文件也是本文随附的下载中提供的。所有常规错误检查已删除以保持主要概念尽可能清楚明确。

了解数据

演示数据如下所示:

0,0,0,1,11,0,0,0,0,0,0,7,8, ... 16,4,0,0,4
0,0,9,14,8,1,0,0,0,0,12,14, ... 5,11,1,0,8
...

没有 1,797 数据项,每行,并且每一行都具有 65 以逗号分隔的值。数据的每行表示 8x8 粗糙手写的数字。上一行的前 64 值为灰度像素值介于 0 和 16 之间。在行上的最后一个值是数字值,因此第一项的像素值表示"4"和第二个项具有像素值为"8"。

演示 autoencoder 旨在减少到只需两个值的数据项的 64 维度,因此该项可以绘制为 x,y 关系图上的点。即使演示数据表示的图像,autoencoders 可以使用任何一种高维数数值数据。

演示数据称为 UCI 数字数据集,请参阅bit.ly/2xDW3IY,或下载本文随附的文件中。

安装 CNTK

Microsoft CNTK 是一个功能强大的开放源代码神经网络库。CNTK 编写 c + + 中的性能,但具有为了方便使用和保持头脑清醒的 Python API。不要将 CNTK 安装为独立系统。首先安装某个包含核心 Python 解释器和多个几百个其他包的 Python 分发版。然后将 CNTK 安装为 Python 外接程序包。

安装 CNTK 可能比较棘手。对于演示,我首先安装 Anaconda3 4.1.1 Windows,在 repo.continuum.io/archive 使用很好的自解压缩可执行文件的分发。发行版本包含 Python 3.5.2 和所需的 CNTK 的多个包。

接下来,我通过下载兼容安装 CNTK 于 v2.4 仅 CPU (我的计算机不一定 GPU) 从本地计算机的 CNTK.whl 文件bit.ly/2OfCCQg。然后我打开命令行界面中,导航到包含 CNTK.whl 文件的目录并输入该命令:

> pip install cntk-2.4-cp35-cp35m-win_amd64.whl

如果您是初次接触 Python,您可以松散将.whl 文件作为某种程度上类似于.msi 安装文件和 pip 作为某种程度上类似于 Windows 安装程序。Python 是版本控制方面非常脆弱,因此您必须要非常小心地安装 Anaconda Python 和 CNTK 的兼容版本。大多数 CNTK 安装问题,请参阅我的直接与版本不兼容。

演示程序

在列表中显示了演示程序使用了少量小幅改动,以节省空间的结构图 2。使用两个空格而不是常用的四个空格,以节省空间,我缩进。并请注意,Python 使用行继续符"\"字符。我使用记事本来编辑我的程序。我的大多数同事更青睐的更复杂的编辑器,但我喜欢记事本的简单性。

图 2 Autoencoder 演示程序结构

# digits_autoenc.py
# condense the UCI digits to two dimensions
# CNTK 2.4 Anaconda3 4.1.1 (Python 3.5.2)
import numpy as np
import cntk as C
import matplotlib.pyplot as plt
def main():
  # 0. get started
  print("Begin UCI digits autoencoder with CNTK demo ")
  np.random.seed(1)
  # 1. load data into memory
  # 2. define autoencoder
  # 3. train model
  # 4. generate (x,y) pairs for each data item
  # 5. graph the data in 2D
  print("End autoencoder using CNTK demo ")
if __name__ == "__main__":
  main()

演示程序名为 digits_autoenc.py,它通过导入 NumPy、 CNTK 和 Pyplot 包启动。NumPy 启用 Python 中的基本数值操作并 Pyplot 用于显示散点图中所示图 1。启动消息后, 程序开始执行通过设置全局 NumPy 随机种子,因此结果将是可重现。

该演示将加载使用 NumPy loadtxt 函数的内存中的定型数据:

data_file = ".\\Data\\digits_uci_test_1797.txt"
data_x = np.loadtxt(data_file, delimiter=",",
  usecols=range(0,64), dtype=np.float32)
labels = np.loadtxt(data_file, delimiter=",",
  usecols=[64], dtype=np.float32)
data_x = data_x / 16

该代码假定将数据放在名为 Data 的子目录中。Loadtxt 函数具有很多可选参数。在这种情况下,函数调用指定的数据是以逗号分隔。Float32 数据类型是默认的 cntk,所以我可以省略显式指定。Data_x 对象保存所有 1,797 行 64 像素值和标签对象保留相应的 10 个类值。通过将除以 16,应确保所有像素值都缩放介于 0.0 和 1.0 之间修改 data_x 对象。

定义 Autoencoder

演示程序使用 64-32-2-32-64 神经网络 autoencoder 模型,使用以下语句:

my_init = C.initializer.glorot_uniform(seed=1)
X = C.ops.input_variable(64, np.float32)  # inputs
layer1 = C.layers.Dense(32, init=my_init,
  activation=C.ops.sigmoid)(X)
layer2 = C.layers.Dense(2, init=my_init,
  activation=C.ops.sigmoid)(layer1)
layer3 = C.layers.Dense(32, init=my_init,
  activation=C.ops.sigmoid)(layer2)
layer4 = C.layers.Dense(64, init=my_init,
  activation=C.ops.sigmoid)(layer3)

初始值设定项对象指定 Glorot 算法,通常可进行深度神经网络的性能优于均匀分布。X 对象设置为存放 64 的输入的值。接下来的四层创建 autoencoder 该 crunches 到 32 个值,64 的输入值,然后会那些下只有两个值。Autoencoder 是编码器解码器网络的一种专用的形式。中的关系图图 3演示了 autoencoder 体系结构。

Autoencoder 体系结构
图 3 Autoencoder 体系结构

若要保持较小,关系图的大小图 3显示 6-3-2-3-6 autoencoder 而不是 64-32-2-32-64 的演示 autoencoder 体系结构。

请注意,输出的值相同的输入值,以便 autoencoder 学习来预测其自己的输入。解码器一部分 autoencoder 扩展备份到 64 个原始值的中间层中的两个值。所有这是每个 64 高维数据项将映射到只有两个值的最终结果。若要获取这些值在该演示程序定义了:

enc_dec = C.ops.alias(layer4)
  encoder = C.ops.alias(layer2)

在口头上,编码器解码器接受 X 对象中的值,并在具有 64 个节点的第 4 层中生成输出。编码器接受 X 对象中的值,并在 layer2 具有两个节点中生成输出。

该演示各个层上使用 sigmoid 激活。这会导致介于 0.0 和 1.0 之间的所有内部层节点。有许多用于 autoencoders 的设计选项。可以在每个层中使用不同数量的内部层和不同数量的节点。可以使用不同的激活函数,包括很少使用线性函数。使用时 autoencoder 进行可视化的维数约简,生成可视化效果的质量是主观判定的因此您的设计选择试用和错误的问题。

定型 Autoencoder

使用以下七个语句准备定型:

Y = C.ops.input_variable(64, np.float32)  # targets
loss = C.squared_error(enc_dec, Y)
learner = C.adam(enc_dec.parameters, lr=0.005, momentum=0.90)
trainer = C.Trainer(enc_dec, (loss), [learner])
N = len(data_x)
bat_size = 2
max_epochs = 10000

Y 对象保存与 X 对象相同的值并定型损失函数将这些值进行比较。此演示程序指定丢失函数中,均方根的误差,但每个值都介于 0.0 和 1.0 由于使用 sigmoid 激活函数,因为交叉熵误差可能已被使用。

对于深度神经网络,Adam (自适应时刻估计) 算法通常的执行性能优于基本随机梯度下降。学习速率值 (0.005) 和动量值 (介于 0.90) 是超参数和必须通过反复试验来确定。(两个) 的批大小和最大数量的训练迭代数 (10,000 个) 也是超参数。

培训执行如下所示:

for i in range(0, max_epochs):
  rows = np.random.choice(N, bat_size, replace=False)
  trainer.train_minibatch({ X: data_x[rows], Y: data_x[rows] })
  if i > 0 and i % int(max_epochs/10) == 0:
    mse = trainer.previous_minibatch_loss_average
    print("epoch = " + str(i) + " MSE = %0.4f " % mse)

在每个定型迭代,random.choice 函数从 1,797 行数据中选择两个行。这是相当简陋的方法,因为某些行可能通常比其他行选择。你可以编写更复杂的批处理系统中,但对于 autoencoders 演示程序使用的方法是简单而有效。

此演示程序通过对当前批的两个项,每隔 10,000 显示平方的误差丢失监视培训 / 10 = 1000 的时期。旨在确保往往在培训; 期间降低错误但是,因为批大小太小,是波动的一小段在定型期间丢失。

使用编码器

定型后,演示程序会生成 (x,y) 对的每个 1,797 数据项目:

reduced = encoder.eval(data_x)

返回值是具有 1,797 行和两个列的矩阵。每一行表示原始数据的约简的维数版本。这两个列中的值是介于 0.0 和 1.0 之间,因为 autoencoder 所有层上使用 sigmoid 激活。

演示程序准备使用这些语句的可视化效果:

print("Displaying 64-dim data in 2D: \n")
plt.scatter(x=reduced[:, 0], y=reduced[:, 1],
  c=labels, edgecolors='none', alpha=0.9,
  cmap=plt.cm.get_cmap('nipy_spectral', 10), s=20)

X 和 y 的散点图函数参数都是 x 轴和 y 轴的值。语法减少 [:,0] 表示矩阵,但只是第一列中的所有行。C 参数指定颜色。在这种情况下保存所有 0 到 9 的值为每个数据项的标签对象传递到 c。

Alpha 参数指定每个标记点的透明度级别。Cmap 参数接受颜色映射。值 nipy_spectral 和意味着来提取范围为 0 的光谱颜色渐变的 10 个值的 10 = 黑色、 到 4 = 绿色,9 = 灰色。Pyplot 库支持许多不同的颜色映射。S 参数是以像素为单位度量的标记点的大小。

如最后,演示程序设置后散点图,以便:

plt.xlabel('component 1')
  plt.ylabel('component 2')
  plt.colorbar()
  print("End autoencoder using CNTK demo ")
  plt.show()
if __name__ == "__main__":
  main()

内置 colorbar 函数使用 nipy_spectral 渐变中的 10 个值。另一种方法是使用图例函数。

总结

有几种备选方法进行数据可视化的维数约简。主成分分析 (PCA) 是几十年来已使用经典统计技术。较新技术,包括从 2008 年,称为嵌入 (T-SNE) 的 t 分布的随机邻居,通常很好,但仅限于使用相对较小数据集。

Autoencoders 可以用于数据可视化效果的维数约简以外的目的。例如,可以使用 autoencoder 从图像或文档中删除的干扰。其理念是减少到某种形式的核心组件,在过程中,删除干扰数据,然后展开数据,从而在某种意义上的更干净数据。


Dr.James McCaffrey 供职于华盛顿地区雷蒙德市沃什湾的 Microsoft Research。他一直从事多个关键的 Microsoft 产品,包括 Internet Explorer 和必应。Dr.可通过 jamccaff@microsoft.com 与 McCaffrey 取得联系。

衷心感谢以下 Microsoft 专家对本文的审阅:Chris Lee, Ricky Loynd   


在 MSDN 杂志论坛讨论这篇文章