CNTK API文档翻译(1)——使用数列

CNTK(Computational Network Toolkit)是微软推出的一个机器学习框架,所以要阅读本系列需要有机器学习的知识基础,有兴趣了解机器学习的同学们请出门右转,看我的Python与人工神经网络系列。

另外这期算是整个文档的综述,讲了CNTK最基本的概念,主要以Sequence classification为例子,我表示Sequence我查了好久都不知道怎么翻译,暂且翻译成数列。

CNTK重的术语

CNTK的输入数据、输出数据和参数全部都用张量表示。每个张量有一个阶数,一个标量是一个0阶张量,一个向量是一个1阶张量,一个矩阵是一个2阶张量等等。我们经常用坐标轴来表示张量的不同维度。

每个CNTK张量有一些固定维度和一些动态的维度。张量在神经网络运行的整个生命周期在固定维度上的长度保持不变,动态维度在定义时与固定维度类似,但有一些不同:

  • 其长度可能根据实力的不同而变化
  • 在训练的取样确定之前,其长度通常是不确定的
  • 他们可能是按顺序列好的

训练的每个取样数据也是一个张量。不过,他的维度是可变的,通常被成为取样维数,他的长度可能在每次取样时不同。在写这个文档时,CNTK支持动态扩展维度,来让我们用一些比较高阶的方法使用数列,因此有时候会被叫做数列维度,不过还没有正式统一的命名。在数列运算的过程中,CNTK使用这个数列维度进行一个简单的类型检查来决定两个数列的操作是否合法。

举两个例子。第一个我们来看在CNTK里面怎么表示视频画面的取样。假设这个视频中所有画面的分辨率都是640×480,其色彩也都是标准的三通道。这就表示我们的取样张量有三个固定的维度,其长度分别是640,480,3。同事他还有两个动态维度,一个是视频个数这个维度,一个是取样长度这个维度。所以假设有16个视频,每个视频的取样都是240帧,那么在神经网络中运转的取样张量就是16×240×3×640×480。

另一个例子展示了使用机器学习来建立文档索引的优雅解决方案,这个索引可以用于文档的快速查询。一般来说,在这个应用场景下,训练数据集一般是一些搜索(关键字)和与之相关的文档的集合,这个相关关系应该是一个标记,标记文档与这个搜索是否相关。如果我们要用固定维度来表示一篇文章,我们就可以建立一个矢量,矢量的长度是这个文档的词汇量,每个要素的值是对应词出现的次数。当然我们也可以用动态维度来表示,打个比方,我们可以用一个嵌套结构组织数据:

  • Query: CNTK
    • Document 1:
      • Microsoft
      • Cognitive
      • Toolkit
    • Document 2:
      • Cartoon
      • Network
    • Document 3:
      • NVIDIA
      • Microsoft
      • Accelerate
      • AI
  • Query: flower
    • Document 1:
      • Flower
      • Wikipedia
    • Document 2:
      • Local
      • Florist
      • Flower
      • Delivery

第一层是取样维度,文档层应该是动态维度,因为每个关键字相关的文档是不同的。最里一层也应该是动态维度,因为每个文档的词汇量是不同的。当然,这个取样张量还是会有一些固定维度,比如每个单词的标识。当有足够的数据时,还能够有另外的数据组织方式,比如建立一个上下文会话,包含多个相关查询。(这里需要补充一下,上一段使用固定维度的时候,数据完全是按一个查询关键字一个文档组织的,原文档中没有提到)

数列分类

在深度学习上最让人兴奋的领域是递归神经网络伟大想法(RNNs,Recurrent Neural Networks)。RNNs某种程度上是深度学习领域的隐含马尔可夫模型(Hidden Markov Models,注:隐含马尔可夫模型是一个并不复杂的数学模型,由美国数学家鲍姆等人在20世纪六七十年代在发表的一系列论文中提出,到目前为止,他一直被认为是解决大多数自然语言处理问题最快速有效的方法)。RNNs是一种能够使用几个固定的参数来处理边长数列的神经网络,因为他学会总结之前的输出特征,归一化成一个固定维度的数据,用来生成这一轮的特征数据,并当作下下次输入数据。换句话说,他保留了更早运算周期的信息。所以传统神经网络如下图左边,而RNNs如下图右边:
image

如上图的右边所显示的,RNNs是处理数列的一种比较合理的结构,他能够处理的数据包括各种各样的当前状态会与前一个状态有关联的数据,比如音乐、视频等。虽然RNNs确实很好很强大,但是一个完整的RNN,他的每个状态和其之前的状态不是线性关系,所以使用传统的随机梯度下降算法训练起来非常困难。因为梯度需要反向传播,但是之前状态的参数的权重与当前状态的参数权重相差会非常大(这点我在Python与人工神经网络第11期有详细阐述)。

上述问题目前还是神经网络领域的热门研究方向,一个在实践中似乎有效的解决方案是LSTM(Long Short Term Memory)神经网络。LSTM神经网络是一个非常有用的典型RNN,我们建议在实际使用中用到RNN时使用它。一个LSTM神经网络是一个通过输入值和状态值得到输出值和新状态值的可微分的函数,这个网址有比较详细的介绍:http://colah.github.io/posts/2015-08-Understanding-LSTMs

在我们之后的例子中,我们会用到LSTM神经网络来进行数列分类。不过为了达到更好的效果,再次我们引入一个新概念:单词映射(word embeddings,注:找不到合适的翻译,简单来说是把单词映射成矢量,详细介绍请参考维基百科:https://en.wikipedia.org/wiki/Word_embedding)。在传统自然语言处理(NPL, Natural Language Processing)时,单词使用基于高维张量的标准基底向量表示,比如第一个单词是(1,0,0,…),第二个单词是(0,1,0,…),所有的单词都是与其他单词垂直的。但是这不是一个完美的描述方式,在真实的语言中,有很多单词非常相似或者他们的词性相似,也就是说这些词在相同场景下的特征值应该相似。我们可以定义一个简单的神经网络,来给每个单词给定一个通过机器学习来的表达向量,以此来将每个单词自动的映射到一个向量。打个比方,在有些场景下,“猫”和“狗”的表示向量会比较相似。目前已经有了一些已经训练了上千万单词的成熟单词映射库比如Glove,不过在我们的教程中准备从头学起。

现在我们已经了解了在数列分类中需要使用的技术:单词映射和递归RNNs,由此我们可以大概想到我们的网络层级了:
1. 单词映射层(每个单词都会映射成一个矢量)
2. LSTM层(允许每个单词与他的前一个单词相关)
3. Softmax层(按照概率归一化,Softmax在我的Python与人工神经网络第九期有详细介绍)

这里有一个神经网络与我们上述内容非常相似,源码地址:https://github.com/Microsoft/CNTK/blob/v2.0.rc2/Examples/SequenceClassification/SimpleExample/Python/SequenceClassification.py
image

允许这段代码应该得到如下输出:

average      since    average      since      examples
   loss       last     metric       last
------------------------------------------------------
    1.61       1.61      0.886      0.886            44
    1.61        1.6      0.714      0.629           133
     1.6       1.59       0.56      0.448           316
    1.57       1.55      0.479       0.41           682
    1.53        1.5      0.464      0.449          1379
    1.46        1.4      0.453      0.441          2813
    1.37       1.28       0.45      0.447          5679
     1.3       1.23      0.448      0.447         11365
error: 0.333333

我们把上述代码里面的难点过一遍。最开始是设置了这个神经网络的参数,输入神经元个数2000个,LSTM层神经元个数和其细胞状态个数分别是24,单词映射层神经元个数50,最终分为5类,也就是说输出神经元个数是5个。运算开始,我们定义两个输入数据,一个是feature,就是数据本身,一个是label,就是数据的标记。之后实例化我们的模型,函数LSTM_sequence_classifier_net用来将输入数据引入映射矩阵最后返回单词映射好的表达方式,然后将其输入LSTM层,通过选择LSTM的最后一个隐藏状态,返回一个固定长度的输出张量:

lstm_classifier = Sequential([Embedding(embedding_dim),
                              Recurrence(LSTM(LSTM_dim, cell_dim))[0],
                              sequence.last,
                              Dense(num_output_classes)])

上面的代码就是CNTK表示的神经网络的完整形态,我们在第二行中选择了第一个输出值作为LSTM层的输出值,因为他的第二个输出值是表示状态的。现在我们设置好了标准和训练迭代:取样大小维200,基本随机梯度下降算法、默认参数和0.0005的学习效率。这个最先进的强大数列分类模型能够处理非常大的数据,当然与此同事也需要更高的计算机性能。除此之外,我们还能够通过堆叠LSTM层来构造更复杂的神经网络,理论上来说,堆叠LSTM层与在前馈网络中堆叠图层应该差不多,不过网络的构造得依据具体项目来设计,并不是越多越好。

使用Numpy数组构造数列

虽然CNTK有一些非常高效的内置读取器,但是有时候你的数据已经是numpy数组了,所以还是有必要知道怎么样来构造输入数列和取样数列的。

我们之前有讨论过文本长度,也就是一维张量,现在我们来看看图片。假设有这么一个输入数据,代表了一张特别小的的彩色图片:

x = sequence.input((3,32,32))

然后我想构造一个包含四张图片数列,分别是img1到img4,对CNTK而言,你需要构造一个张量,包含这四张图片:

img_seq = np.stack([img1, img2, img3, img4])
output = network.eval({x:[img_seq]})

Numpy里的stack函数将所有的输入数据按一个新的维度堆叠起来,所以img_seq的大小应该是4×3×32×32。也许你注意到在我们把img_seq绑定到x的时候先给他加了一个中括号,也就是形成了一个数组,这是因为取样数据都是数组,这就表示第一个取样数据,当然如果确定每次取样的数量都是一样的,那就不用先构造数组了,可以直接张量表示。


欢迎扫码关注我的微信公众号获取最新文章
image

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值