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.
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).
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:
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.
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.