📜  CNTK-序列分类

📅  最后修改于: 2020-12-10 05:00:01             🧑  作者: Mango


在本章中,我们将详细了解CNTK中的序列及其分类。

张量

CNTK工作的概念是张量。基本上,CNTK的输入,输出以及参数被组织为张量,通常被认为是广义矩阵。每个张量都有一个等级

  • 等级0的张量是标量。

  • 等级1的张量是一个向量。

  • 等级2的张量是矩阵。

在这里,这些不同的尺寸称为轴。

静态轴和动态轴

顾名思义,静态轴在网络的整个生命周期中具有相同的长度。另一方面,动态轴的长度可能因实例而异。实际上,通常在呈现每个小批量之前不知道它们的长度。

动态轴就像静态轴一样,因为它们还定义了张量中包含的有意义的数字分组。

为了更清楚一点,让我们看看如何在CNTK中表示一小段短视频剪辑。假设视频剪辑的分辨率均为640 *480。并且,这些剪辑也以彩色拍摄,通常使用三个通道进行编码。这进一步意味着我们的minibatch具有以下内容-

  • 3个静态轴,分别为长度640、480和3。

  • 两个动态轴;视频和最小批量轴的长度。

这意味着如果一个微型批处理具有16个视频,每个视频的长度为240帧,则将表示为16 * 240 * 3 * 640 * 480张量。

在CNTK中使用序列

首先了解长期记忆网络,让我们了解CNTK中的序列。

长期记忆网络(LSTM)

长期记忆网络

Hochreiter&Schmidhuber引入了长期短期记忆(LSTM)网络。它解决了使基本的循环层能够长时间记住事物的问题。 LSTM的体系结构如上图所示。如我们所见,它具有输入神经元,记忆细胞和输出神经元。为了解决梯度消失的问题,长期短期存储网络使用显式存储单元(存储先前的值)和随后的门-

  • 忘记门-顾名思义,它告诉存储单元忘记先前的值。存储单元存储这些值,直到门(即“忘记门”)告诉它忘记它们为止。

  • 输入门-顾名思义,它为单元添加了新内容。

  • 输出门-顾名思义,输出门决定何时将矢量从单元传递到下一个隐藏状态。

在CNTK中使用序列非常容易。让我们借助以下示例进行查看-

import sys
import os
from cntk import Trainer, Axis
from cntk.io import MinibatchSource, CTFDeserializer, StreamDef, StreamDefs,\
   INFINITELY_REPEAT
from cntk.learners import sgd, learning_parameter_schedule_per_sample
from cntk import input_variable, cross_entropy_with_softmax, \
   classification_error, sequence
from cntk.logging import ProgressPrinter
from cntk.layers import Sequential, Embedding, Recurrence, LSTM, Dense
def create_reader(path, is_training, input_dim, label_dim):
   return MinibatchSource(CTFDeserializer(path, StreamDefs(
      features=StreamDef(field='x', shape=input_dim, is_sparse=True),
      labels=StreamDef(field='y', shape=label_dim, is_sparse=False)
   )), randomize=is_training,
   max_sweeps=INFINITELY_REPEAT if is_training else 1)
def LSTM_sequence_classifier_net(input, num_output_classes, embedding_dim,
LSTM_dim, cell_dim):
   lstm_classifier = Sequential([Embedding(embedding_dim),
      Recurrence(LSTM(LSTM_dim, cell_dim)),
      sequence.last,
      Dense(num_output_classes)])
return lstm_classifier(input)
def train_sequence_classifier():
   input_dim = 2000
   cell_dim = 25
   hidden_dim = 25
   embedding_dim = 50
   num_output_classes = 5
   features = sequence.input_variable(shape=input_dim, is_sparse=True)
   label = input_variable(num_output_classes)
   classifier_output = LSTM_sequence_classifier_net(
   features, num_output_classes, embedding_dim, hidden_dim, cell_dim)
   ce = cross_entropy_with_softmax(classifier_output, label)
   pe =      classification_error(classifier_output, label)
   rel_path = ("../../../Tests/EndToEndTests/Text/" +
      "SequenceClassification/Data/Train.ctf")
   path = os.path.join(os.path.dirname(os.path.abspath(__file__)), rel_path)
   reader = create_reader(path, True, input_dim, num_output_classes)
input_map = {
   features: reader.streams.features,
   label: reader.streams.labels
}
lr_per_sample = learning_parameter_schedule_per_sample(0.0005)
progress_printer = ProgressPrinter(0)
trainer = Trainer(classifier_output, (ce, pe),
sgd(classifier_output.parameters, lr=lr_per_sample),progress_printer)
minibatch_size = 200
for i in range(255):
   mb = reader.next_minibatch(minibatch_size, input_map=input_map)
trainer.train_minibatch(mb)
   evaluation_average = float(trainer.previous_minibatch_evaluation_average)
   loss_average = float(trainer.previous_minibatch_loss_average)
return evaluation_average, loss_average
if __name__ == '__main__':
   error, _ = train_sequence_classifier()
   print(" error: %f" % error)
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

上述程序的详细说明将在下一部分中介绍,尤其是当我们要构建递归神经网络时。