Bước 4: Xây dựng, đào tạo và đánh giá mô hình của bạn

Trong phần này, chúng tôi sẽ nỗ lực xây dựng, đào tạo và đánh giá mô hình của mình. Ở Bước 3, chúng tôi chọn sử dụng mô hình ngam hoặc mô hình trình tự, sử dụng tỷ lệ S/W. Đã đến lúc bạn viết thuật toán phân loại và huấn luyện thuật toán. Chúng ta sẽ sử dụng TensorFlow với API tf.keras để thực hiện việc này.

Việc xây dựng các mô hình máy học bằng Keras tập trung vào việc lắp ráp các lớp, các khối xây dựng xử lý dữ liệu với nhau, giống như cách chúng ta lắp ráp các viên gạch Lego. Các lớp này cho phép chúng ta chỉ định trình tự biến đổi mà chúng ta muốn thực hiện trên dữ liệu đầu vào. Vì thuật toán học tập của chúng tôi nhập một văn bản duy nhất và tạo ra một phân loại duy nhất, nên chúng tôi có thể tạo một ngăn xếp tuyến tính gồm các lớp bằng cách sử dụng API Mô hình tuần tự.

Ngăn xếp các lớp tuyến tính

Hình 9: Ngăn xếp các lớp tuyến tính

Lớp đầu vào và lớp trung gian sẽ được xây dựng theo cách khác nhau, tuỳ thuộc vào việc chúng ta đang xây dựng mô hình n-gam hay trình tự trình tự. Tuy nhiên, bất kể loại mô hình là gì, lớp cuối cùng sẽ giống nhau đối với một vấn đề nhất định.

Xây dựng lớp cuối cùng

Khi chỉ có 2 lớp (phân loại tệp nhị phân), mô hình của chúng tôi sẽ cho ra một điểm xác suất duy nhất. Ví dụ: việc nhập 0.2 cho một mẫu đầu vào nhất định có nghĩa là "20% độ tin cậy rằng mẫu này nằm trong lớp đầu tiên (lớp 1), 80% cho rằng lớp đó ở lớp thứ hai (lớp 0)." Để xuất ra điểm xác suất như vậy, hàm kích hoạt của lớp cuối cùng phải là một hàm sigmoidhàm xoá được dùng để đào tạo mô hình1 của 1

Khi có nhiều hơn 2 lớp (phân loại nhiều lớp), mô hình của chúng ta sẽ cho ra một điểm xác suất cho mỗi lớp. Tổng số điểm này phải là 1. Ví dụ: việc nhập {0: 0.2, 1: 0.7, 2: 0.1} có nghĩa là “20% độ tin cậy rằng mẫu này là ở lớp 0, 70% là ở lớp 1 và 10% rằng lớp đó là ở lớp 2”. Để xuất ra các điểm số này, hàm kích hoạt của lớp cuối cùng phải là mềm tối đa và hàm mất để dùng để đào tạo mô hình nên là entropy phân loại. (Xem Hình 10, bên phải).

Lớp cuối

Hình 10: Lớp cuối cùng

Đoạn mã sau đây xác định một hàm nhận số lượng lớp làm đầu vào và xuất ra số đơn vị lớp thích hợp (1 đơn vị để phân loại nhị phân; nếu không, 1 đơn vị cho mỗi lớp) và hàm kích hoạt thích hợp:

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

Hai phần sau sẽ hướng dẫn cách tạo lớp mô hình còn lại cho mô hình n gam và mô hình trình tự.

Khi tỷ lệ S/W nhỏ, chúng tôi nhận thấy rằng các mô hình ngam hoạt động tốt hơn các mô hình trình tự. Mô hình trình tự sẽ tốt hơn khi có một số lượng lớn các vectơ nhỏ, dày đặc. Điều này là do các mối quan hệ nhúng được tìm hiểu trong không gian rộng và điều này xảy ra tốt nhất trên nhiều mẫu.

Xây dựng mô hình n gam [Tuỳ chọn A]

Chúng tôi gọi các mô hình xử lý các mã thông báo một cách độc lập (không tính đến thứ tự từ) dưới dạng các mô hình n gam. Các bộ cảm biến nhiều lớp đơn giản (bao gồm cả hồi quy hồi quy), máy tăng cường độ dốcmáy vectơ hỗ trợ đều thuộc danh mục này; chúng không thể tận dụng bất kỳ thông tin nào về thứ tự văn bản.

Chúng tôi so sánh hiệu suất của một số mô hình ngam nêu trên và quan sát thấy rằng ceptron nhiều lớp (MLP) thường hoạt động tốt hơn so với các tuỳ chọn khác. MLP rất dễ xác định và hiểu, cung cấp độ chính xác cao và yêu cầu tính toán tương đối ít.

Đoạn mã sau đây xác định mô hình MLP hai lớp trong tf.keras, thêm một vài lớp bỏ qua để chuẩn hoá (để ngăn chặn việc cung cấp quá nhiều thông tin cho mẫu đào tạo.

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

Xây dựng mô hình trình tự [Tuỳ chọn B]

Chúng tôi gọi các mô hình có thể học từ thao tác của các mã thông báo gần nhau dưới dạng mô hình trình tự. Có cả các lớp mô hình CNN và RNN. Dữ liệu được xử lý trước dưới dạng vectơ trình tự cho các mô hình này.

Mô hình trình tự thường có số lượng thông số lớn hơn để tìm hiểu. Lớp đầu tiên trong các mô hình này là lớp nhúng. Lớp này sẽ tìm hiểu mối quan hệ giữa các từ trong không gian vectơ dày đặc. Mối quan hệ từ vựng đã hoạt động hiệu quả nhất qua nhiều mẫu.

Các từ trong tập dữ liệu nhất định rất có thể không phải là duy nhất đối với tập dữ liệu đó. Do đó, chúng ta có thể tìm hiểu mối quan hệ giữa các từ trong tập dữ liệu bằng cách sử dụng(các) tập dữ liệu khác. Để làm vậy, chúng ta có thể chuyển một video nhúng đã học từ một tập dữ liệu khác vào lớp nhúng của chúng tôi. Những video nhúng này được gọi là tính năng nhúng trước khi đào tạo. Việc sử dụng tính năng nhúng trước khi đào tạo giúp mô hình khởi đầu thuận lợi trong quá trình tìm hiểu.

Có sẵn các nội dung nhúng đã đào tạo trước được đào tạo bằng các tập sao lục lớn, chẳng hạn như GloVe. GloVe đã được đào tạo về nhiều tập sao lục (chủ yếu là Wikipedia). Chúng tôi đã thử nghiệm việc huấn luyện các mô hình trình tự của mình bằng cách sử dụng một phiên bản nhúng của GloVe và quan sát thấy rằng nếu chúng tôi dừng quá trình trọng số của các video nhúng được huấn luyện trước và chỉ huấn luyện phần còn lại của mạng, thì các mô hình sẽ hoạt động không hiệu quả. Điều này có thể là do ngữ cảnh mà lớp nhúng được đào tạo có thể khác với ngữ cảnh mà chúng tôi sử dụng.

Các nội dung nhúng GloVe được đào tạo về dữ liệu Wikipedia có thể không phù hợp với các mẫu ngôn ngữ trong tập dữ liệu IMDb của chúng tôi. Mối quan hệ được dự đoán có thể cần cập nhật, tức là trọng số nhúng có thể cần điều chỉnh theo ngữ cảnh. Chúng tôi thực hiện việc này trong hai giai đoạn:

  1. Trong lần chạy đầu tiên, với trọng số của lớp nhúng bị treo, chúng ta cho phép phần còn lại của mạng tìm hiểu. Khi kết thúc lượt chạy này, các trọng số mô hình sẽ đạt trạng thái tốt hơn nhiều so với giá trị chưa khởi tạo. Trong lần chạy thứ hai, chúng tôi cũng cho phép lớp nhúng tìm hiểu, thực hiện các điều chỉnh nhỏ cho tất cả trọng số trong mạng. Chúng tôi gọi đây là quy trình nhúng đã tinh chỉnh.

  2. Tính năng nhúng được tinh chỉnh giúp mang lại độ chính xác cao hơn. Tuy nhiên, điều này xảy ra khi hệ thống điện toán gia tăng cần thiết để huấn luyện mạng. Khi có đủ số lượng mẫu, chúng tôi có thể làm tốt việc nhúng từ đầu. Chúng tôi quan sát thấy rằng đối với S/W > 15K, việc bắt đầu từ đầu sẽ mang lại độ chính xác tương tự như khi sử dụng tính năng nhúng tinh chỉnh.

Chúng tôi so sánh các mô hình trình tự khác nhau như CNN, sepCNN, RNN (LSTM & GRU), CNN-RNN và RNN xếp chồng, khác nhau giữa các cấu trúc mô hình. Chúng tôi nhận thấy rằng sepCNN, một biến thể mạng tích chập thường hiệu quả hơn về dữ liệu và hiệu quả tính toán, hoạt động tốt hơn các mô hình khác.

Mã sau đây tạo mô hình sepCNN bốn lớp:

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

Đào tạo mô hình

Hiện tại, chúng ta đã xây dựng kiến trúc mô hình xong, chúng ta cần đào tạo mô hình. Quá trình đào tạo bao gồm dự đoán dựa trên trạng thái hiện tại của mô hình, tính toán mức độ không chính xác của thông tin dự đoán và cập nhật trọng số hoặc thông số của mạng để giảm thiểu lỗi này và làm cho mô hình dự đoán tốt hơn. Chúng tôi lặp lại quá trình này cho đến khi mô hình của chúng tôi hội tụ và không thể tìm hiểu được nữa. Có 3 thông số chính cần chọn cho quy trình này (Xem Bảng 2).

  • Chỉ số: Cách đo lường hiệu suất của mô hình bằng cách sử dụng chỉ số. Chúng tôi đã sử dụng độ chính xác làm chỉ số trong thử nghiệm của mình.
  • Hàm mất: Hàm dùng để tính giá trị tổn thất mà quá trình huấn luyện sau đó cố gắng giảm thiểu bằng cách điều chỉnh trọng số mạng. Đối với các bài toán phân loại, tổn thất entropy hoạt động tốt.
  • Trình tối ưu hoá: Một hàm quyết định cách cập nhật trọng số mạng dựa trên kết quả của hàm suy hao. Chúng tôi đã sử dụng trình tối ưu hoá Adam phổ biến trong các thử nghiệm của mình.

Trong Keras, chúng ta có thể truyền các tham số học tập này đến một mô hình bằng cách sử dụng phương thức biên dịch.

Thông số học tập Giá trị
Chỉ số độ chính xác
Hàm mất - phân loại nhị phân tệp nhị phân_crossentropy
Hàm tổn thất – phân loại nhiều lớp sparse_categorycal_crossentropy
Trình tối ưu hóa adam

Bảng 2: Thông số học tập

Quá trình đào tạo thực tế diễn ra bằng cách sử dụng phương thức fit. Tuỳ thuộc vào kích thước của tập dữ liệu, đây là phương thức mà hầu hết các chu kỳ điện toán sẽ được sử dụng. Trong mỗi lần lặp lại huấn luyện, số lượng batch_size mẫu từ dữ liệu huấn luyện được sử dụng để tính toán mức hao tổn và các trọng số được cập nhật một lần dựa trên giá trị này. Quá trình đào tạo hoàn tất một epoch sau khi mô hình thấy toàn bộ tập dữ liệu đào tạo. Vào cuối mỗi khoảng thời gian bắt đầu của hệ thống, chúng tôi sử dụng tập dữ liệu xác thực để đánh giá mức độ hiệu quả của mô hình. Chúng tôi lặp lại quá trình đào tạo bằng tập dữ liệu cho một số lượng thời gian bắt đầu của hệ thống. Chúng tôi có thể tối ưu hoá điều này bằng cách dừng sớm, khi độ chính xác xác thực ổn định giữa các khoảng thời gian bắt đầu của hệ thống liên tiếp, cho thấy rằng mô hình không còn được huấn luyện nữa.

Huấn luyện siêu tham số Giá trị
Tốc độ học tập 1e-3
Thời gian bắt đầu của hệ thống 1000
Kích thước lô 512
Dừng sớm thông số: val_loss, kiên nhẫn: 1

Bảng 3: Các siêu tham số huấn luyện

Mã Keras sau đây triển khai quá trình đào tạo bằng cách sử dụng các thông số được chọn trong Bảng 2 & 3 ở trên:

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]

Vui lòng tìm ví dụ về mã để đào tạo mô hình trình tự tại đây.