Langkah 4: Build, Latih, dan Evaluasi Model Anda

Di bagian ini, kita akan berupaya membuat, melatih, dan mengevaluasi model. Pada Langkah 3, kita memilih untuk menggunakan model n-gram atau model urutan, menggunakan rasio S/W. Sekarang, saatnya menulis algoritme klasifikasi dan melatihnya. Untuk hal ini, kita akan menggunakan TensorFlow dengan tf.keras API.

Membuat model machine learning dengan Keras adalah tentang merakit lapisan, elemen penyusun pemrosesan data, seperti halnya menyusun bata Lego. Lapisan ini memungkinkan kita menentukan urutan transformasi yang ingin dilakukan atas input kita. Karena algoritme pembelajaran kita menerima satu input teks dan menghasilkan satu klasifikasi, kita dapat membuat tumpukan lapisan linear menggunakan Model model.

Tumpukan lapisan linear

Gambar 9: Tumpukan linear pada lapisan

Lapisan input dan lapisan perantara akan dibuat secara berbeda, bergantung pada apakah kita mem-build model n-gram atau urutan. Namun, terlepas dari jenis model, lapisan terakhir akan sama untuk masalah tertentu.

Membangun Lapisan Terakhir

Jika kita hanya memiliki 2 class (klasifikasi biner), model kita akan menghasilkan satu skor probabilitas. Misalnya, meng-output 0.2 untuk sampel input tertentu berarti “20% yakin bahwa sampel ini ada di class pertama (class 1), 80% bahwa berada di class kedua (class 0).” Untuk menghasilkan skor probabilitas seperti itu, fungsi aktivasi dari lapisan terakhir harus berupa fungsi sigmoid, dan fungsi kerugian yang digunakan untuk melatih model harus menjadi bin1 (1-1)

Jika ada lebih dari 2 class (klasifikasi multi-class), model kita akan menampilkan satu skor probabilitas per class. Jumlah skor ini harus 1. Misalnya, menghasilkan {0: 0.2, 1: 0.7, 2: 0.1} berarti “20% yakin bahwa sampel ini berada di class 0, 70% berada di class 1, dan 10% berada di class 2.” Untuk menampilkan skor ini, fungsi aktivasi lapisan terakhir harus softmax, dan fungsi kerugian yang digunakan untuk melatih model harus entropi silang kategori. (Lihat Gambar 10, kanan).

Lapisan terakhir

Gambar 10: Lapisan terakhir

Kode berikut menentukan fungsi yang menggunakan jumlah class sebagai input, dan menampilkan jumlah unit lapisan yang sesuai (1 unit untuk klasifikasi biner; jika tidak, 1 unit untuk setiap class) dan fungsi aktivasi yang sesuai:

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

Dua bagian berikut ini membahas pembuatan lapisan model yang tersisa untuk model n-gram dan model urutan.

Jika rasio S/W kecil, kami menemukan bahwa model n-gram berperforma lebih baik daripada model urutan. Model urutan akan lebih baik jika ada banyak vektor kecil yang padat. Hal ini karena hubungan penautan dipelajari di ruang padat, dan hal ini paling baik dilakukan pada banyak sampel.

Buat model n-gram [Opsi A]

Kami merujuk pada model yang memproses token secara independen (tidak mempertimbangkan urutan kata) sebagai model n-gram. Perseptron multi-lapisan sederhana (termasuk model regresi logistik), mesin penguat gradien, dan mesin vektor dukungan termasuk dalam kategori ini; mereka tidak dapat memanfaatkan informasi apa pun tentang pengurutan teks.

Kami membandingkan performa beberapa model n-gram yang disebutkan di atas dan mengamati bahwa perseptron multi-lapisan (MLP) biasanya berperforma lebih baik daripada opsi lainnya. MLP mudah ditentukan dan dipahami, memberikan akurasi yang baik, dan memerlukan komputasi yang relatif sedikit.

Kode berikut menentukan model MLP dua lapis di tf.keras, yang menambahkan beberapa Dropout layer untuk regularisasi (untuk mencegah overfit ke contoh pelatihan).

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

Model urutan build [Opsi B]

Kami merujuk pada model yang dapat belajar dari kedekatan token sebagai model urutan. Ini mencakup class model CNN dan RNN. Data diproses sebelumnya sebagai vektor urutan untuk model ini.

Model urutan umumnya memiliki jumlah parameter yang lebih besar untuk dipelajari. Lapisan pertama dalam model ini adalah lapisan penyematan, yang mempelajari hubungan antara kata-kata dalam ruang vektor yang padat. Mempelajari hubungan kata berfungsi dengan baik pada banyak contoh.

Kata-kata dalam set data tertentu cenderung tidak unik untuk set data tersebut. Dengan demikian, kita dapat mempelajari hubungan antara kata dalam set data menggunakan set data lain. Untuk melakukannya, kita dapat mentransfer penyematan yang dipelajari dari set data lain ke lapisan sematan. Embedding ini disebut sebagai embeddings terlatih . Penggunaan penyematan terlatih memberi model awal yang baik dalam proses pembelajaran.

Ada penyematan terlatih yang tersedia yang telah dilatih menggunakan korporasi besar, seperti GloVe. GloVe telah dilatih dengan beberapa korpora (terutama Wikipedia). Kami menguji pelatihan model urutan kami menggunakan versi penyematan GloVe dan mengamati bahwa jika kami membekukan bobot penyematan terlatih dan hanya melatih seluruh jaringan, model tersebut tidak berperforma dengan baik. Penyebabnya mungkin karena konteks tempat lapisan penyematan dilatih mungkin berbeda dari konteks tempat kita menggunakannya.

Penyematan GloVe yang dilatih pada data Wikipedia mungkin tidak sesuai dengan pola bahasa dalam set data IMDb kami. Kesimpulan hubungan mungkin memerlukan beberapa pembaruan—yaitu, bobot penyematan mungkin memerlukan penyesuaian kontekstual. Kita melakukannya dalam dua tahap:

  1. Pada percobaan pertama, dengan bobot lapisan penyematan beku, kami membiarkan jaringan yang lain untuk belajar. Di akhir proses ini, bobot model mencapai status yang jauh lebih baik daripada nilai yang tidak diinisialisasi. Untuk operasi kedua, kami juga mengizinkan lapisan penyematan untuk belajar, membuat penyesuaian yang baik untuk semua bobot dalam jaringan. Kami merujuk proses ini untuk menggunakan penyematan yang ditingkatkan.

  2. Penyematan yang ditingkatkan kualitasnya menghasilkan akurasi yang lebih baik. Namun, hal ini akan menimbulkan peningkatan daya komputasi yang diperlukan untuk melatih jaringan. Dengan jumlah sampel yang memadai, kita juga dapat mempelajari penyematan dari awal dengan baik. Kami mengamati bahwa untuk S/W > 15K, mulai dari awal secara efektif akan menghasilkan akurasi yang sama seperti saat menggunakan embedding yang ditingkatkan.

Kami membandingkan berbagai model urutan seperti CNN, sepCNN, RNN (LSTM & GRU), CNN-RNN, dan RNN yang ditumpuk, dengan bervariasi arsitektur model. Kami menemukan bahwa sepCNN, varian jaringan konvolusional yang sering lebih efisien data dan efisien, berperforma lebih baik daripada model lain.

Kode berikut membuat model sepCNN empat lapis:

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

Melatih Model Anda

Setelah membuat arsitektur model, kita perlu melatih model. Pelatihan melibatkan pembuatan prediksi berdasarkan status model saat ini, menghitung seberapa salah prediksinya, dan memperbarui bobot atau parameter jaringan untuk meminimalkan error ini dan membuat model memprediksi lebih baik. Kami mengulangi proses ini hingga model kami dikonvergensi dan tidak dapat lagi dipelajari. Ada tiga parameter utama yang harus dipilih untuk proses ini (Lihat Tabel 2.

  • Metrik: Cara mengukur performa model menggunakan metrik. Kami menggunakan akurasi sebagai metrik dalam eksperimen.
  • Fungsi kerugian: Fungsi yang digunakan untuk menghitung nilai kerugian yang coba diminimalkan oleh proses pelatihan dengan menyesuaikan bobot jaringan. Untuk masalah klasifikasi, kerugian lintas-entropi berfungsi dengan baik.
  • Optimizer: Fungsi yang menentukan cara bobot jaringan diperbarui berdasarkan output fungsi kerugian. Kami menggunakan pengoptimal Adam yang populer dalam eksperimen kami.

Di Keras, kita dapat meneruskan parameter pembelajaran ini ke model menggunakan metode compile.

Parameter pembelajaran Nilai
Metrik akurasi
Fungsi kerugian - klasifikasi biner biner_crossentropi
Fungsi kerugian - klasifikasi kelas jamak sparse_categorycal_crossentropy
Optimizer Adam

Tabel 2: Parameter pembelajaran

Pelatihan yang sebenarnya dilakukan menggunakan metode fit. Bergantung pada ukuran set data, ini adalah metode yang akan digunakan untuk sebagian besar siklus komputasi. Dalam setiap iterasi pelatihan, jumlah sampel batch_size dari data pelatihan Anda digunakan untuk menghitung kerugian, dan bobot diperbarui sekali, berdasarkan nilai ini. Proses pelatihan ini menyelesaikan epoch setelah model melihat seluruh set data pelatihan. Di akhir setiap epoch, kita menggunakan set data validasi untuk mengevaluasi seberapa baik model belajar. Kami mengulangi pelatihan menggunakan set data untuk jumlah epoch yang telah ditentukan. Kita dapat mengoptimalkannya dengan berhenti lebih awal, saat akurasi validasi stabil di antara epoch berturut-turut, yang menunjukkan bahwa model tidak lagi dilatih.

Hyperparameter pelatihan Nilai
Kecepatan pembelajaran 1e-3
Epoch 1000
Ukuran tumpukan 512
Penghentian awal parameter: val_loss, kesabaran: 1

Tabel 3: Hyperparameter pelatihan

Kode Keras berikut mengimplementasikan proses pelatihan menggunakan parameter yang dipilih dalam Tabel 2 & 3 di atas:

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]

Temukan contoh kode untuk melatih model urutan di sini.