CNTK - Классификация последовательностей
В этой главе мы подробно узнаем о последовательностях в CNTK и их классификации.
Тензоры
Концепция, по которой работает CNTK, tensor. В основном, входы, выходы и параметры CNTK организованы какtensors, который часто рассматривается как обобщенная матрица. Каждый тензор имеетrank -
Тензор ранга 0 - скаляр.
Тензор ранга 1 - это вектор.
Тензор 2-го ранга - аматрикс.
Здесь эти разные размеры называются axes.
Статические оси и динамические оси
Как следует из названия, статические оси имеют одинаковую длину на протяжении всего срока службы сети. С другой стороны, длина динамических осей может варьироваться от экземпляра к экземпляру. Фактически, их длина обычно не известна до представления каждой мини-партии.
Динамические оси похожи на статические оси, потому что они также определяют значимую группировку чисел, содержащихся в тензоре.
пример
Чтобы было понятнее, давайте посмотрим, как минипакет коротких видеоклипов представлен в CNTK. Предположим, что разрешение всех видеоклипов составляет 640 * 480. Кроме того, клипы снимаются в цвете, который обычно кодируется с помощью трех каналов. Это также означает, что наша мини-партия имеет следующее -
3 статические оси длиной 640, 480 и 3 соответственно.
Две динамические оси; длина видео и оси мини-пакета.
Это означает, что если в мини-пакете 16 видео, каждое из которых имеет длину 240 кадров, это будет представлено как 16*240*3*640*480 тензоры.
Работа с последовательностями в CNTK
Давайте разберемся с последовательностями в CNTK, сначала узнав о сети долгосрочной памяти.
Сеть долгосрочной краткосрочной памяти (LSTM)
Сети долговременной краткосрочной памяти (LSTM) были представлены Hochreiter & Schmidhuber. Это решило проблему получения базового повторяющегося слоя, чтобы запоминать вещи на долгое время. Архитектура LSTM приведена выше на схеме. Как мы видим, у него есть входные нейроны, ячейки памяти и выходные нейроны. Чтобы бороться с проблемой исчезающего градиента, сети долговременной памяти используют явную ячейку памяти (хранят предыдущие значения) и следующие ворота -
Forget gate- Как следует из названия, он указывает ячейке памяти забыть предыдущие значения. Ячейка памяти хранит значения до тех пор, пока вентиль, то есть «ворота забыть», не скажет ему забыть их.
Input gate - Как следует из названия, он добавляет в ячейку новый материал.
Output gate - Как следует из названия, выходной элемент решает, когда перейти по векторам от ячейки к следующему скрытому состоянию.
Работать с последовательностями в 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
Подробное объяснение вышеуказанной программы будет рассмотрено в следующих разделах, особенно когда мы будем создавать рекуррентные нейронные сети.