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 n-gram modeli veya sıra modeli kullanmayı tercih ettik. Şimdi sıra, sınıflandırma algoritmamızı yazıp eğitmeye geldi. Bunun için tf.keras API ile TensorFlow'u kullanacağız.

Keras ile makine öğrenimi modelleri oluşturmak, tıpkı Lego tuğlaları gibi, katmanları ve veri işleme yapı taşlarını bir araya getirmekten ibarettir. Bu katmanlar, girişimizde gerçekleştirmek istediğimiz dönüşüm sırasını belirtmemize olanak tanır. Öğrenme algoritmamız tek bir metin girişini alıp tek bir sınıflandırma çıkardığında, 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 mı yoksa dizi modeli mi oluşturduğumuza bağlı olarak farklı şekilde oluşturulacaktır. Ancak model türü ne olursa olsun son katman belirli bir sorun için aynı olur.

Son Katmanı Oluşturma

Yalnızca 2 sınıfınız (ikili sınıflandırma) olduğunda modelimiz tek bir olasılık puanı oluşturmalıdır. Örneğin, belirli bir giriş örneği için 0.2 çıkışı, bu örneğin birinci sınıfta (1. sınıf) olduğuna% 20 güvenir, ikinci sınıfta (0. sınıf) olduğuna dair güven% 80 anlamına gelir. Böyle bir olasılık puanı oluşturmak için son katmanın etkinleştirme işlevi sigmoid işlevi ve modeli eğitmek içinikili entropi işlevi olmalıdır. (Soldaki Şekil 10'a bakın).

2'den fazla sınıf (çok sınıflı sınıflandırma) olduğunda modelimiz her sınıf için bir olasılık puanı vermelidir. Bu puanların toplamı 1 olmalıdır. Örneğin, {0: 0.2, 1: 0.7, 2: 0.1} çıkışı, "bu örneğin 0. sınıfta olduğuna, 1. sınıfta olduğuna dair %70 güven oranı ve 2. sınıfta olduğuna dair %10 güven düzeyine sahip olduğu anlamına gelir." Bu puanları elde etmek için son katmanın aktivasyon fonksiyonu softmax, modeli eğitmek için kullanılan kayıp işlevi ise kategorik çapraz entropi olmalıdır. (bkz. Şekil 10, sağdaki).

Son katman

Şekil 10: Son katman

Aşağıdaki kod, sınıfların sayısını giriş olarak alan ve uygun sayıda katman birimi (ikili sınıflandırma için 1 birim, aksi takdirde her sınıf için 1 birim) ve uygun etkinleştirme işlevini ü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ı açıklanmaktadır.

S/W oranı düşük olduğunda n-gram modellerinin, dizi modellerinden daha iyi performans gösterdiğini tespit ettik. Sıra modelleri, çok sayıda küçük ve yoğun vektör olduğunda daha iyi sonuç verir. Çünkü yerleştirme ilişkileri yoğun bir alanda öğrenilir ve bunun en iyisi birçok örnekte gerçekleşir.

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

Jetonları bağımsız olarak işleyen (kelime sırasını dikkate almadan) modellere n-gram modelleri olarak atıfta bulunuruz. Çok katmanlı basit algıların (mantıksal regresyon gradyan güçlendiren makineler ve destek vektör makineleri modelleri dahil) tümü bu kategoriye girer. Metin sıralamasıyla ilgili hiçbir bilgiyi kullanamazlar.

Yukarıda bahsedilen n-gram modellerinden bazılarının performansını karşılaştırdık ve çok katmanlı algılayıcıların (MLP'ler) genellikle diğer seçeneklerden daha iyi performans gösterdiğini gözlemledik. MLP'lerin tanımlanması ve anlaşılması basittir, iyi doğruluk sağlar ve nispeten az hesaplama gerektirir.

Aşağıdaki kod, tf.keras'ta iki katmanlı bir MLP modelini tanımlar ve eğitim örneklerinin üzerine sığmasını önlemek amacıyla birkaç normalleştirme için bırakma katmanı ekler.

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

Sıra modeli oluşturma [Option B]

Jetonların bitişiğinden bilgi edinebilen modellere sıra modelleri olarak atıfta bulunuruz. Buna, CNN ve RNN model sınıfları dahildir. Veriler, bu modeller için dizi vektörleri olarak önceden işlenir.

Dizi modelleri genellikle öğrenilecek daha fazla sayıda parametreye sahiptir. Bu modellerdeki ilk katman, yoğun bir vektör uzayında bulunan kelimeler arasındaki ilişkiyi öğrenen bir yerleştirme katmanıdır. Kelime ilişkilerinin öğrenilmesi, birçok örnekte 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. Bunu yapmak için başka bir veri kümesinden öğrenilen bir yerleştirmeyi, yerleştirme katmanımıza aktarabiliriz. Bu yerleştirmelere, önceden eğitilmiş yerleştirmeler denir. Önceden eğitilmiş yerleştirme tekniğinin kullanılması, modelin öğrenme sürecinde bir başlangıç yapmasını sağlar.

GloVe gibi büyük bir derleme kullanılarak eğitilmiş, önceden eğitilmiş yerleştirmeler vardır. GloVe birden fazla topluluk (esas olarak Vikipedi) ile eğitildi. Dizi modellerimizin eğitimini, GloVe yerleştirmelerinin bir sürümünü kullanarak test ettik ve önceden eğitilmiş yerleştirmelerin ağırlıklarını dondurup ağın yalnızca geri kalanını eğitirsek modellerin iyi performans göstermediğini gördük. Bunun nedeni, yerleştirme katmanının eğitildiği bağlamın, onu kullandığımız bağlamdan farklı olması olabilir.

Wikipedia verileri kullanılarak eğitilen GloVe yerleştirmeleri, IMDb veri kümesimizdeki dil kalıplarıyla uyumlu olmayabilir. Tahmin edilen ilişkilerin güncellenmesi gerekebilir. Örneğin, yerleştirme ağırlıkları bağlamsal incelenebilir. Bunu iki aşamada yapıyoruz:

  1. İlk çalıştırmada, yerleştirme katmanı ağırlıkları dondurularak 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ırmada, yerleştirme katmanının da öğrenmesine ve ağdaki tüm ağırlıklarda hassas ayarlamalar yapmasına olanak tanıyoruz. Bu işleme ince ayar yapılmış bir yerleştirme işlemi diyoruz.

  2. İnce ayarlanmış yerleştirmeler daha iyi doğruluk sağlar. Ancak bu durum, ağın eğitilmesi için gereken işlem gücünün artmasını gerektirir. Yeterli sayıda örnekle, yerleştirmeyi sıfırdan öğrenmeyi de başarabiliriz. S/W > 15K için sıfırdan başlayarak ince ayar yerleştirme kullanımıyla aynı doğruluk oranının etkili olduğunu gözlemledik.

CNN, sepCNN, RNN (LSTM ve GRU), CNN-RNN ve yığılmış RNN gibi farklı dizi modellerini karşılaştırdık ve model mimarilerini değiştirdik. Genellikle veri açısından daha verimli ve işlem açısından daha verimli olan kıvrımlı bir 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

Artık model mimarisini oluşturduğumuza göre modeli eğitmemiz gerekiyor. Eğitim, bu hatayı en aza indirmek ve modelin daha iyi tahmin edebilmesi için modelin mevcut durumuna göre tahminde bulunmayı, tahminin ne kadar yanlış olduğunu hesaplamayı ve ağın ağırlıklarını ya da parametrelerini güncellemeyi kapsar. Bu işlemi, modelimiz birleşene ve artık öğrenene kadar tekrar ederiz. Bu işlem için seçilecek üç temel parametre vardır (Tablo 2'ye bakın.)

  • Metrik: Metrik kullanarak modelimizin performansını ölçme. Denemelerimizde metrik olarak doğruluğu kullandık.
  • Kayıp işlevi: Kayıp değerini hesaplamak için kullanılan ve eğitim sürecinin ağ ağırlıklarını ayarlayarak en aza indirmeye çalıştığı bir işlev. Sınıflandırma problemlerinde çapraz entropi kaybı iyi sonuç verir.
  • Optimize edici: Ağ ağırlıklarının, kayıp işlevinin çıktısına göre nasıl güncelleneceğine karar veren bir işlev. Denemelerimizde popüler Adam optimize ediciyi kullandık.

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

Tablo 2: Öğrenme parametreleri

Öğrenme parametresi Değer
Metrik doğruluk
Kayıp fonksiyonu - ikili sınıflandırma binary_crossentropy
Kayıp fonksiyonu - çok sınıflı sınıflandırma sparse_categorical_crossentropy
Optimizasyon Meraklısı adam

Asıl eğitim, fit yöntemi kullanılarak gerçekleşir. Veri kümenizin boyutuna bağlı olarak, çoğu işlem döngüsünün harcanacağı yöntem budur. Her eğitim yinelemesinde, kaybın hesaplanması için eğitim verilerinizden batch_size sayıda örnek kullanılır ve ağırlıklar bu değere bağlı olarak bir kez güncellenir. Model, tüm eğitim veri kümesini gördüğünde 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. Önceden belirlenmiş sayıda dönem için veri kümesini kullanarak eğitimi tekrar ederiz. Doğrulama doğruluğunun ardışık dönemler arasında dengeye oturup modelin artık eğitilmediğini göstermesi için erkenden durdurarak bunu optimize edebiliriz.

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

Tablo 3: Eğitim hiperparametreleri

Aşağıdaki Keras kodu, yukarıdaki Tablo 2 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]

Sıra modelini eğitmeye yönelik kod örneklerini burada bulabilirsiniz.