4. Adım: Modelinizi Oluşturma, Eğitme ve Değerlendirme

Bu bölümde modelimizi oluşturmak, eğitmek ve değerlendirmek için çalışacağız. 3. adımda S/W oranımızı kullanarak bir n-gram modeli veya dizi modeli kullanmayı seçtik. Şimdi, sınıflandırma algoritmamızı yazıp eğitme zamanı. Bunun için TensorFlow'u tf.keras API'siyle kullanırız.

Keras ile makine öğrenimi modelleri oluşturmak için katmanları bir araya getirmek, veri işleme yapı taşlarını bir araya getirmek gerekir. Tıpkı Lego tuğlalarını monte etmek gibi. Bu katmanlar, girişlerimizde gerçekleştirmek istediğimiz bir dönüşüm dizisi belirtebilmemizi sağlar. Öğrenim algoritmamız tek bir metin girişini alıp tek bir sınıflandırmayı gösterirken Sıralı model API'sini kullanarak doğrusal bir katman yığını oluşturabiliriz.

Doğrusal katman yığını

Şekil 9: Doğrusal katman yığını

Giriş katmanı ve ara katmanlar, n-gram veya dizi modeli oluşturmamıza bağlı olarak farklı şekilde yapılandırılır. Ancak model türünden bağımsız olarak, son katman belirli bir sorun için aynı olacaktır.

Son Katmanı Oluşturma

Yalnızca 2 sınıfımız (ikili sınıflandırma) olduğunda modelimiz tek bir olasılık puanı vermelidir. Örneğin, belirli bir giriş örneği için 0.2 çıkışının "Bu örneğin birinci sınıftaki (1. sınıf) %20 güveni, 0. sınıftaki% 80'i" anlamına geldiğini unutmayın. Böyle bir olasılık sonucunu elde etmek için son katmanın etkinleştirme işlevinin sigmoid işlevi olması ve kayıp işlevinin 1. sırada olması gerekir{1=1{11{11{1'ü{10 girilmelidir{11{1){1

2'den fazla sınıf (çok sınıflı sınıflandırma) varsa modelimiz sınıf başına bir olasılık puanı oluşturmalıdır. Bu puanların toplamı 1 olmalıdır. Örneğin, {0: 0.2, 1: 0.7, 2: 0.1} çıkışı "Bu örneğin sınıf 0, sınıf %10 ve sınıf 2'de %10 olduğu" anlamına gelir. Bu sonuçları elde etmek için son katmanın etkinleştirme işlevi softmax, modeli eğitmek için kullanılan kayıp işlevi ise kategorik çapraz entropi şeklinde olmalıdır. (Sağdaki Şekil 10'a bakın).

Son katman

Şekil 10: Son katman

Aşağıdaki kod, sınıf sayısını giriş olarak alan ve uygun sayıda katman birimi (ikili sınıflandırma için 1 birim, her sınıf için 1 birim) ve uygun etkinleştirme işlevi üreten bir işlevi tanımlar:

def _get_last_layer_units_and_activation(num_classes):
    """Gets the # units and activation function for the last network layer.

    # Arguments
        num_classes: int, number of classes.

    # Returns
        units, activation values.
    """
    if num_classes == 2:
        activation = 'sigmoid'
        units = 1
    else:
        activation = 'softmax'
        units = num_classes
    return units, activation

Aşağıdaki iki bölümde n-gram modelleri ve dizi modelleri için kalan model katmanlarının oluşturulmasına ilişkin adım adım açıklamalı kılavuz bulunmaktadır.

S/W oranı küçük olduğunda n-gram modellerinin dizi modellerinden daha iyi performans gösterdiğini tespit ettik. Dizi modelleri, çok sayıda küçük ve yoğun vektör olduğunda daha iyi sonuç verir. Bunun nedeni, yerleşik ilişkilerin yoğun bir alanda öğrenilmesidir. Bunun en iyi sonucu, birçok örnekte görülür.

N-gram modeli oluşturma [Seçenek A]

Jetonları, n-gram modelleri olarak bağımsız olarak (kelime sırasını dikkate almadan) işleyen modellerden bahsediyoruz. Basit çok katmanlı algılar (lojistik regresyon dahil), gradyan güçlendirme makineleri ve vektör makinelerini destekleyen modellerin tümü bu kategoriye girer. Metin sıralama hakkında herhangi bir bilgiden yararlanamazlar.

Yukarıda belirtilen n-gram modellerinin bazılarının performansını karşılaştırdık ve çok katmanlı algıların (MLP'ler) genellikle diğer seçeneklerden daha iyi performans gösterdiğini gözlemledik. MLP'ler kolayca tanımlanıp anlaşılabilir, doğru doğruluk sağlar ve nispeten az hesaplama gerektirir.

Aşağıdaki kod, tf.keras'da iki katmanlı bir makine öğrenimi modeli tanımlar. Bu örnekte, Normalleştirme için çıkış katmanları eklenir (eğitim örneklerine aşırı sığdırma işlemi önlemek için).

from tensorflow.python.keras import models
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.layers import Dropout

def mlp_model(layers, units, dropout_rate, input_shape, num_classes):
    """Creates an instance of a multi-layer perceptron model.

    # Arguments
        layers: int, number of `Dense` layers in the model.
        units: int, output dimension of the layers.
        dropout_rate: float, percentage of input to drop at Dropout layers.
        input_shape: tuple, shape of input to the model.
        num_classes: int, number of output classes.

    # Returns
        An MLP model instance.
    """
    op_units, op_activation = _get_last_layer_units_and_activation(num_classes)
    model = models.Sequential()
    model.add(Dropout(rate=dropout_rate, input_shape=input_shape))

    for _ in range(layers-1):
        model.add(Dense(units=units, activation='relu'))
        model.add(Dropout(rate=dropout_rate))

    model.add(Dense(units=op_units, activation=op_activation))
    return model

Dizi modeli oluşturma [Option B]

Jetonların bitişiğinden öğrenilebilen dizi modelleri, dizi modelleri olarak adlandırılır. Buna, modellerin CNN ve RNN sınıfları da dahildir. Veriler, bu modeller için dizi vektörleri olarak önceden işlenir.

Dizi modelleri hakkında genellikle öğrenilecek parametre sayısı daha fazladır. Bu modellerin ilk katmanı, yoğun bir vektör alanındaki kelimeler arasındaki ilişkiyi öğrenen bir yerleştirme katmanıdır. Kelime ilişkilerini öğrenmek çok sayıda örnek üzerinde en iyi sonucu verir.

Belirli bir veri kümesindeki kelimeler, büyük olasılıkla söz konusu veri kümesine özgü değildir. Böylece, diğer veri kümelerini kullanarak veri kümemizdeki kelimeler arasındaki ilişkiyi öğrenebiliriz. Bunun için, başka bir veri kümesinden öğrenilen yerleştirmeyi yerleştirme katmanımıza aktarabiliriz. Bu yerleştirmeler, önceden eğitilmiş yerleştirmeler olarak adlandırılır. Önceden eğitilmiş bir yerleştirmenin kullanılması, modele öğrenme sürecinde bir başlangıç sağlar.

GloVe gibi büyük arşivler kullanılarak eğitilmiş, önceden eğitilmiş yerleştirmeler vardır. GloVe, birçok şirkette (esas olarak Wikipedia) eğitildi. Dizi modellerimizi eğitirken GloVe yerleştirmelerinin bir sürümünü kullandık ve önceden eğitilmiş yerleştirmelerin ağırlıklarını dondurup ağın geri kalanını eğittikse modellerin iyi performans göstermediğini gözlemledik. Bunun nedeni, yerleştirme katmanının eğitildiği bağlamın, içeriği kullandığımız bağlamdan farklı olması olabilir.

Wikipedia verileri üzerinde eğitilmiş GloVe yerleştirmeleri, IMDb veri kümesimizdeki dil kalıplarıyla uyumlu olmayabilir. Tahmin edilen ilişkilerde güncelleme yapılması gerekebilir. Diğer bir deyişle, yerleştirme ağırlıkları içeriğe dayalı ayar yapılması gerekebilir. Bunu iki aşamada yapıyoruz:

  1. İlk çalıştırmada, yerleştirme katmanı ağırlıkları dondurulduğunda ağın geri kalanının öğrenmesine izin verilir. Bu çalıştırmanın sonunda model ağırlıkları, başlatılmamış değerlerinden çok daha iyi bir duruma ulaşır. İkinci çalıştırma için yerleştirme katmanının da öğrenmesine izin vererek ağdaki tüm ağırlıklarda küçük ayarlamalar yapıyoruz. Bu işleme, hassas yerleştirme yerleştirmesi diyoruz.

  2. Hassas ayarlı yerleştirmeler daha iyi sonuç verir. Ancak bu durum, ağı eğitmek için gerekli olan işlem gücünün artmasını sağlar. Yeterli sayıda örnek aldığımızda, bir yerleştirmeyi sıfırdan öğrenebiliriz. S/W > 15K için sıfırdan başlayarak hassas ayarlı yerleştirme ile aynı doğruluk düzeyinin geçerli olduğunu gördük.

CNN, sepCNN, RNN (LSTM &GRU), CNN-RNN ve yığınlı RNN gibi farklı dizi modellerini karşılaştırdık ve farklı mimari modeller uyguladık. Genellikle veri açısından verimli ve bilgi işlem açısından verimli bir evrimsel ağ varyantı olan sepCNN'lerin diğer modellerden daha iyi performans gösterdiğini tespit ettik.

Aşağıdaki kod, dört katmanlı bir sepCNN modeli oluşturur:

from tensorflow.python.keras import models
from tensorflow.python.keras import initializers
from tensorflow.python.keras import regularizers

from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.layers import Dropout
from tensorflow.python.keras.layers import Embedding
from tensorflow.python.keras.layers import SeparableConv1D
from tensorflow.python.keras.layers import MaxPooling1D
from tensorflow.python.keras.layers import GlobalAveragePooling1D

def sepcnn_model(blocks,
                 filters,
                 kernel_size,
                 embedding_dim,
                 dropout_rate,
                 pool_size,
                 input_shape,
                 num_classes,
                 num_features,
                 use_pretrained_embedding=False,
                 is_embedding_trainable=False,
                 embedding_matrix=None):
    """Creates an instance of a separable CNN model.

    # Arguments
        blocks: int, number of pairs of sepCNN and pooling blocks in the model.
        filters: int, output dimension of the layers.
        kernel_size: int, length of the convolution window.
        embedding_dim: int, dimension of the embedding vectors.
        dropout_rate: float, percentage of input to drop at Dropout layers.
        pool_size: int, factor by which to downscale input at MaxPooling layer.
        input_shape: tuple, shape of input to the model.
        num_classes: int, number of output classes.
        num_features: int, number of words (embedding input dimension).
        use_pretrained_embedding: bool, true if pre-trained embedding is on.
        is_embedding_trainable: bool, true if embedding layer is trainable.
        embedding_matrix: dict, dictionary with embedding coefficients.

    # Returns
        A sepCNN model instance.
    """
    op_units, op_activation = _get_last_layer_units_and_activation(num_classes)
    model = models.Sequential()

    # Add embedding layer. If pre-trained embedding is used add weights to the
    # embeddings layer and set trainable to input is_embedding_trainable flag.
    if use_pretrained_embedding:
        model.add(Embedding(input_dim=num_features,
                            output_dim=embedding_dim,
                            input_length=input_shape[0],
                            weights=[embedding_matrix],
                            trainable=is_embedding_trainable))
    else:
        model.add(Embedding(input_dim=num_features,
                            output_dim=embedding_dim,
                            input_length=input_shape[0]))

    for _ in range(blocks-1):
        model.add(Dropout(rate=dropout_rate))
        model.add(SeparableConv1D(filters=filters,
                                  kernel_size=kernel_size,
                                  activation='relu',
                                  bias_initializer='random_uniform',
                                  depthwise_initializer='random_uniform',
                                  padding='same'))
        model.add(SeparableConv1D(filters=filters,
                                  kernel_size=kernel_size,
                                  activation='relu',
                                  bias_initializer='random_uniform',
                                  depthwise_initializer='random_uniform',
                                  padding='same'))
        model.add(MaxPooling1D(pool_size=pool_size))

    model.add(SeparableConv1D(filters=filters * 2,
                              kernel_size=kernel_size,
                              activation='relu',
                              bias_initializer='random_uniform',
                              depthwise_initializer='random_uniform',
                              padding='same'))
    model.add(SeparableConv1D(filters=filters * 2,
                              kernel_size=kernel_size,
                              activation='relu',
                              bias_initializer='random_uniform',
                              depthwise_initializer='random_uniform',
                              padding='same'))
    model.add(GlobalAveragePooling1D())
    model.add(Dropout(rate=dropout_rate))
    model.add(Dense(op_units, activation=op_activation))
    return model

Modelinizi Eğitin

Model mimarisini inşa ettiğimize göre, modeli eğitmemiz gerekiyor. Eğitim, modelin mevcut durumunu temel alan bir tahminde bulunmayı, tahminin ne kadar yanlış olduğunu hesaplamayı ve ağın ağırlıklarını ya da parametrelerini güncellemeyi bu hatayı azaltıp modeli daha iyi hale getirmeyi içerir. Bu işlem, modelimiz birleşene ve artık öğrenene kadar tekrarlanır. Bu işlem için seçilecek üç temel parametre vardır (bkz. Tablo 2).

  • Metrik: Modelimizin performansını ölçmek için metrik kullanma. Denemelerimizde metrik olarak doğruluğu kullandık.
  • Kayıp işlevi: Eğitim işleminin, ağ ağırlıklarını ayarlayarak en aza indirmeye çalıştığı bir kayıp değerini hesaplamak için kullanılan bir işlev. Sınıflandırma sorunları için entropi kaybı iyi sonuç verir.
  • Optimize Edici: Ağ ağırlıklarının, kayıp işlevinin sonucuna göre nasıl güncelleneceğine karar veren bir işlevdir. Denemelerimizde popüler Adam optimize ediciyi kullandık.

Keras'ta bu öğrenme parametrelerini derleme yöntemini kullanarak bir modele iletebiliriz.

Öğrenme parametresi Değer
Metrik doğruluk
Kayıp işlevi - ikili sınıflandırma ikili_terentropi
Kayıp işlevi - çok sınıflı sınıflandırma seyrek_kategorik_tüm_kros
Optimize Edici Adam

2. Tablo: Öğrenme parametreleri

Asıl eğitim fit yöntemi kullanılarak gerçekleştirilir. Veri kümenizin boyutuna bağlı olarak bu, çoğu işlem döngüsünün harcanacağı yöntemdir. Her eğitim yinelemesinde, kayıpı hesaplamak için eğitim verilerinizden batch_size örnek kullanılır ve ağırlıklar bu değere göre bir kez güncellenir. Model, eğitim veri kümesinin tamamını gördükten sonra eğitim süreci bir epoch işlemini tamamlar. Her dönemin sonunda, modelin ne kadar iyi öğrendiğini değerlendirmek için doğrulama veri kümesini kullanırız. Veri kümesini kullanarak önceden belirlenmiş sayıda dönem için eğitimi tekrarlarız. Bunu, optimizasyon doğruluğu art arda kullanılan dönemler arasında dengeli hale geldiğinde erken durarak optimize edebilir ve böylece modelin artık eğitilmediğini görebilirsiniz.

Eğitim hiper parametresi Değer
Öğrenme oranı 1e-3
Dönemler 1.000
Grup boyutu 512
Erken durdurma parametre: val_loss, sabır: 1

3. Tablo: Hiperparametreleri eğitme

Aşağıdaki Keras kodu, yukarıdaki 2. Tablo ve 3'te seçilen parametreleri kullanarak eğitim sürecini uygular:

def train_ngram_model(data,
                      learning_rate=1e-3,
                      epochs=1000,
                      batch_size=128,
                      layers=2,
                      units=64,
                      dropout_rate=0.2):
    """Trains n-gram model on the given dataset.

    # Arguments
        data: tuples of training and test texts and labels.
        learning_rate: float, learning rate for training model.
        epochs: int, number of epochs.
        batch_size: int, number of samples per batch.
        layers: int, number of `Dense` layers in the model.
        units: int, output dimension of Dense layers in the model.
        dropout_rate: float: percentage of input to drop at Dropout layers.

    # Raises
        ValueError: If validation data has label values which were not seen
            in the training data.
    """
    # Get the data.
    (train_texts, train_labels), (val_texts, val_labels) = data

    # Verify that validation labels are in the same range as training labels.
    num_classes = explore_data.get_num_classes(train_labels)
    unexpected_labels = [v for v in val_labels if v not in range(num_classes)]
    if len(unexpected_labels):
        raise ValueError('Unexpected label values found in the validation set:'
                         ' {unexpected_labels}. Please make sure that the '
                         'labels in the validation set are in the same range '
                         'as training labels.'.format(
                             unexpected_labels=unexpected_labels))

    # Vectorize texts.
    x_train, x_val = vectorize_data.ngram_vectorize(
        train_texts, train_labels, val_texts)

    # Create model instance.
    model = build_model.mlp_model(layers=layers,
                                  units=units,
                                  dropout_rate=dropout_rate,
                                  input_shape=x_train.shape[1:],
                                  num_classes=num_classes)

    # Compile model with learning parameters.
    if num_classes == 2:
        loss = 'binary_crossentropy'
    else:
        loss = 'sparse_categorical_crossentropy'
    optimizer = tf.keras.optimizers.Adam(lr=learning_rate)
    model.compile(optimizer=optimizer, loss=loss, metrics=['acc'])

    # Create callback for early stopping on validation loss. If the loss does
    # not decrease in two consecutive tries, stop training.
    callbacks = [tf.keras.callbacks.EarlyStopping(
        monitor='val_loss', patience=2)]

    # Train and validate model.
    history = model.fit(
            x_train,
            train_labels,
            epochs=epochs,
            callbacks=callbacks,
            validation_data=(x_val, val_labels),
            verbose=2,  # Logs once per epoch.
            batch_size=batch_size)

    # Print results.
    history = history.history
    print('Validation accuracy: {acc}, loss: {loss}'.format(
            acc=history['val_acc'][-1], loss=history['val_loss'][-1]))

    # Save model.
    model.save('IMDb_mlp_model.h5')
    return history['val_acc'][-1], history['val_loss'][-1]

Dizi modelini eğitmek için gerekli kod örneklerini burada bulabilirsiniz.