CNTK - Dizi Sınıflandırması
Bu bölümde CNTK'daki diziler ve sınıflandırılması hakkında detaylı bilgi edineceğiz.
Tensörler
CNTK'nın çalıştığı konsept, tensor. Temel olarak CNTK girdileri, çıktıları ve parametreleri şu şekilde düzenlenir:tensors, genellikle genelleştirilmiş bir matris olarak düşünülür. Her tensörün birrank -
Seviye 0 tensörü skalerdir.
Seviye 1 tensörü bir vektördür.
Seviye 2'nin tensörü, amatristir.
Burada bu farklı boyutlara axes.
Statik eksenler ve Dinamik eksenler
Adından da anlaşılacağı gibi, statik eksenler ağın ömrü boyunca aynı uzunluğa sahiptir. Öte yandan, dinamik eksenlerin uzunluğu örnekten örneğe değişebilir. Aslında uzunlukları tipik olarak her mini parti sunulmadan önce bilinmemektedir.
Dinamik eksenler, aynı zamanda tensörde bulunan sayıların anlamlı bir gruplamasını tanımladıkları için statik eksenler gibidir.
Misal
Daha net hale getirmek için, bir kısa video klip grubunun CNTK'da nasıl temsil edildiğini görelim. Video kliplerin tümünün çözünürlüğünün 640 * 480 olduğunu varsayalım. Ayrıca klipler, genellikle üç kanal ile kodlanan renkli olarak çekilir. Ayrıca, mini partimizin aşağıdakilere sahip olduğu anlamına gelir -
Sırasıyla 640, 480 ve 3 uzunluğunda 3 statik eksen.
İki dinamik eksen; videonun uzunluğu ve minibatch eksenleri.
Bu, bir mini partinin her biri 240 kare uzunluğunda 16 videosu varsa, şu şekilde temsil edileceği anlamına gelir: 16*240*3*640*480 tensörler.
CNTK'da sekanslarla çalışmak
Önce Uzun-Kısa Süreli Bellek Ağını öğrenerek CNTK'daki dizileri anlayalım.
Uzun-Kısa Süreli Bellek Ağı (LSTM)
Uzun-kısa süreli bellek (LSTM'ler) ağları Hochreiter & Schmidhuber tarafından tanıtıldı. Bir şeyleri uzun süre hatırlamak için temel bir yinelenen katman elde etme sorununu çözdü. LSTM'nin mimarisi yukarıdaki şemada verilmiştir. Gördüğümüz gibi, giriş nöronlarına, hafıza hücrelerine ve çıkış nöronlarına sahiptir. Kaybolan gradyan sorunuyla mücadele etmek için, Uzun-kısa süreli bellek ağları açık bir bellek hücresi (önceki değerleri depolar) ve aşağıdaki kapıları kullanır -
Forget gate- Adından da anlaşılacağı gibi, hafıza hücresine önceki değerleri unutmasını söyler. Bellek hücresi değerleri, geçit yani 'geçidi unut' ona onları unutmasını söyleyene kadar saklar.
Input gate - Adından da anlaşılacağı gibi, hücreye yeni şeyler ekler.
Output gate - Adından da anlaşılacağı gibi, çıktı kapısı vektörlerin hücreden sonraki gizli duruma ne zaman geçeceğine karar verir.
CNTK'da sekanslarla çalışmak çok kolay. Aşağıdaki örnek yardımıyla görelim -
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
Yukarıdaki programın ayrıntılı açıklaması, özellikle Tekrarlayan Sinir ağları oluşturacağımız zaman sonraki bölümlerde ele alınacaktır.