Schritt 4: Modell erstellen, trainieren und bewerten

In diesem Abschnitt beschäftigen wir uns mit der Erstellung, Schulung und Bewertung modellieren. In Schritt 3 haben sich entweder für ein N-Gramm-Modell oder ein Sequenzmodell mit unserem Verhältnis S/W entschieden. Jetzt ist es an der Zeit, unseren Klassifizierungsalgorithmus zu schreiben und zu trainieren. Wir verwenden TensorFlow mit dem tf.keras API dafür verwenden.

Beim Erstellen von Modellen für maschinelles Lernen mit Keras geht es darum, Schichten, Datenverarbeitungsbausteine, ähnlich wie wir bei Lego-Bausteinen Bausteine. Mithilfe dieser Schichten können wir die Reihenfolge der gewünschten Transformationen angeben. auf unseren Input leisten können. Da unser Lernalgorithmus eine einzelne Texteingabe und eine einzelne Klassifizierung ausgibt, können wir einen linearen Layer-Stapel erstellen. mithilfe der Sequenzielles Modell der API erstellen.

Linearer Ebenenstapel

Abbildung 9: Linearer Ebenenstapel

Die Eingabe- und die Zwischenschicht sind unterschiedlich aufgebaut. je nachdem, ob wir ein N-Gramm- oder ein Sequenzmodell erstellen. Aber Unabhängig vom Modelltyp bleibt die letzte Ebene bei einem bestimmten Problem gleich.

Letzte Ebene konstruieren

Wenn wir nur zwei Klassen haben (binäre Klassifizierung), sollte unser Modell eine den einzelnen Wahrscheinlichkeitswert. Beispielsweise wird 0.2 für ein bestimmtes Eingabebeispiel ausgegeben. bedeutet: „20% Wahrscheinlichkeit, dass diese Stichprobe in der ersten Klasse (Klasse 1) ist, und 80% davon sie ist in der zweiten Klasse (Klasse 0).“ Für die Ausgabe eines solchen Wahrscheinlichkeitswerts Aktivierungsfunktion der letzten Ebene sollte ein Sigmoidfunktion, und die Verlustfunktion die zum Trainieren des Modells verwendet wird, binäre Kreuzentropie. (siehe Abbildung 10, links).

Wenn es mehr als zwei Klassen gibt (Klassifizierung mit mehreren Klassen), stellt unser Modell einen Wahrscheinlichkeitswert pro Klasse ausgeben sollte. Die Summe dieser Bewertungen sollte 1. Die Ausgabe von {0: 0.2, 1: 0.7, 2: 0.1} bedeutet beispielsweise „20% Wahrscheinlichkeit, dass diese Stichprobe ist in Klasse 0, 70% in Klasse 1 und 10% in Klasse 1. Klasse 2.“ Für die Ausgabe dieser Werte muss die Aktivierungsfunktion der letzten Schicht sollte „Softmax“ sein und die zum Trainieren des Modells verwendete Verlustfunktion kategoriale Kreuzentropie. (siehe Abbildung 10, rechts).

Letzte Ebene

Abbildung 10: Letzte Ebene

Der folgende Code definiert eine Funktion, die die Anzahl der Klassen als Eingabe verwendet, und gibt die entsprechende Anzahl von Layer-Einheiten aus (1 Einheit bei Binärprogrammen). Klassifizierung; andernfalls 1 Einheit für jede Klasse) und die entsprechende Aktivierung :

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

In den folgenden beiden Abschnitten wird die Erstellung des verbleibenden Modells beschrieben. Schichten für N-Gramm-Modelle und Sequenzmodelle.

Wenn das S/W-Verhältnis klein ist, haben wir festgestellt, dass N-Gramm-Modelle besser abschneiden als Sequenzmodelle. Sequenzmodelle sind besser, wenn es eine große Anzahl von kleinen, dichten Vektoren. Das liegt daran, dass Beziehungen eingebetteter Inhalte und das geschieht am besten bei vielen Proben.

N-Gramm-Modell erstellen [Option A]

Wir beziehen uns dabei auf Modelle, die die Tokens unabhängig verarbeiten und keine Wortreihenfolge des Kontos) als N-Gramm-Modelle. Einfache mehrschichtige Perceptrons (einschließlich logistische Regression Gradient-Boosting-Maschinen, und Vektormaschinenmodelle unterstützen) alle in diese Kategorie fallen: können sie keine Informationen Textsortierung.

Wir haben die Leistung einiger der oben genannten N-Gramm-Modelle verglichen und festgestellt, dass Multi-Layer-Perceptrons (MLPs) in der Regel eine bessere Leistung erzielen als weitere Optionen. MLPs sind einfach zu definieren und zu verstehen, und erfordern relativ wenig Rechenleistung.

Der folgende Code definiert ein zweischichtiges MLP-Modell in tf.keras. Dabei werden Dropout-Ebenen für Regularisierung um zu verhindern, Überanpassung bis hin zu Trainingsbeispielen.

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

Sequenzmodell erstellen [Option B]

Wir bezeichnen Modelle, die aus der Nähe von Tokens als Sequenz lernen können. Modelle. Dazu gehören auch CNN- und RNN-Modellklassen. Die Daten werden vorverarbeitet als Sequenzvektoren für diese Modelle.

Sequenzmodelle haben in der Regel eine größere Anzahl von Parametern, die erlernt werden müssen. Die erste in diesen Modellen eine Einbettungsschicht, die die Beziehung zwischen zwischen den Wörtern in einem dichten Vektorraum. Das Erlernen von Wortbeziehungen funktioniert bei vielen Samples am besten ist.

Wörter in einem bestimmten Dataset sind höchstwahrscheinlich nicht eindeutig für dieses Dataset. Wir können also die Beziehung zwischen den Wörtern in unserem Dataset mithilfe anderer Datasets ermitteln. Dazu können wir eine aus einem anderen Dataset erlernte Einbettung in unser Einbettungsebene. Diese Einbettungen werden als vortrainierte Einbettungen bezeichnet. Einbettungen. Mit einer vortrainierten Einbettung erhält das Modell einen Vorsprung Lernprozess.

Es sind vortrainierte Einbettungen verfügbar, die mit großen Korpora, z. B. GloVe. GloVe hat wurde in mehreren Korpora (hauptsächlich Wikipedia) geschult. Wir haben die Schulung Sequenzmodelle mit einer Version von GloVe-Einbettungen. Wir haben beobachtet, dass wir, wenn wir die Gewichte der vortrainierten Einbettungen eingefroren und nur der Rest der funktionierten die Modelle nicht gut. Das könnte daran liegen, dass der Kontext bei dem die Einbettungsebene trainiert wurde, in dem wir sie verwendet haben.

GloVe-Einbettungen, die mit Wikipedia-Daten trainiert wurden, stimmen möglicherweise nicht mit der Sprache überein Mustern in unserem IMDb-Dataset. Die abgeleiteten Beziehungen benötigen Aktualisierung – d.h., die Einbettungsgewichtungen erfordern möglicherweise eine kontextabhängige Feinabstimmung. Wir machen das in zwei Phasen:

  1. Beim ersten Durchlauf wurden die Gewichtungen der Einbettungsschicht eingefroren und der Rest wird zugelassen. des Netzwerks lernen. Am Ende dieser Ausführung erreichen die Modellgewichtungen einen Zustand viel besser als ihre nicht initialisierten Werte. Beim zweiten Durchlauf Ermöglicht es der Einbettungsebene, ebenfalls zu lernen und Feinabstimmungen an allen Gewichtungen vorzunehmen im Netzwerk. Wir bezeichnen diesen Prozess als eine abgestimmte Einbettung.

  2. Detaillierte Einbettungen erzielen eine höhere Genauigkeit. Dies betrifft jedoch Kosten für mehr Rechenleistung, die zum Trainieren des Netzwerks erforderlich ist. Bei genügend Stichproben zu erhalten, könnten wir auch eine Einbettung lernen, von Grund auf neu erstellen. Wir haben festgestellt, dass für S/W > 15K effektiv bei null anzufangen liefert ungefähr die gleiche Genauigkeit wie eine abgestimmte Einbettung.

Wir haben verschiedene Sequenzmodelle wie CNN, sepCNN und RNN (LSTM &GRU), CNN-RNN und gestapeltes RNN, wobei die Modellarchitekturen. Wir fanden heraus, dass sepCNNs, eine Convolutional Network-Variante, sind häufig daten- und recheneffizienter und erzielen eine bessere Leistung als die andere Modelle.

<ph type="x-smartling-placeholder">

Mit dem folgenden Code wird ein sepCNN-Modell mit vier Schichten erstellt:

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

Modell trainieren

Nachdem Sie die Modellarchitektur erstellt haben, müssen Sie das Modell trainieren. Beim Training wird eine Vorhersage auf Basis des aktuellen Modellstatus getroffen. Berechnung, wie falsch die Vorhersage ist, und aktualisieren die Gewichtungen oder Parameter des Netzwerks zur Minimierung dieses Fehlers besser machen. Wir wiederholen diesen Vorgang, bis unser Modell konvergiert ist und nicht mehr lernen. Für diesen Prozess müssen drei wichtige Parameter ausgewählt werden (siehe Tabelle 2.

  • Messwert: Wie Sie die Leistung unseres Modells mithilfe eines metric. Wir haben Genauigkeit verwendet, als Messwert in unseren Tests.
  • Verlustfunktion: Eine Funktion, mit der ein Verlustwert berechnet wird. dass der Trainingsprozess dann versucht, durch Abstimmung der Netzwerk-Gewichtungen. Für Klassifizierungsprobleme eignet sich der Kreuzentropieverlust gut.
  • Optimierungstool: Eine Funktion, die bestimmt, wie die Netzwerkgewichtung bestimmt wird basierend auf der Ausgabe der Verlustfunktion aktualisiert. Wir haben die beliebten Adam-Optimierungstool verwenden.

In Keras können wir diese Lernparameter mithilfe der zusammenstellen .

Tabelle 2: Lernparameter

Lernparameter Wert
Messwert Genauigkeit
Verlustfunktion – binäre Klassifizierung binary_crossentropy
Verlustfunktion – Klassifizierung mit mehreren Klassifizierungen sparse_categorical_crossentropy
Optimierung Adam

Das eigentliche Training erfolgt mithilfe der fit-Methode. Je nach Größe der Dataset ist dies die Methode, mit der die meisten Rechenzyklen genutzt werden. In jeder Trainingsdurchlauf, batch_size Stichproben aus Ihren Trainingsdaten sind zur Berechnung des Verlusts verwendet, und die Gewichtungen werden einmal auf der Grundlage dieses Werts aktualisiert. Der Trainingsprozess führt einen epoch durch, sobald das Modell die gesamte Trainings-Dataset. Am Ende jeder Epoche werden mithilfe des Validierungs-Datasets wie gut das Modell lernt. Wir wiederholen das Training mit dem Dataset, für eine vorgegebene Anzahl von Epochen. Wir können dies optimieren, indem wir die Anzeige frühzeitig beenden, wenn sich die Validierungsgenauigkeit zwischen aufeinanderfolgenden Epochen stabilisiert, was zeigt, wird das Modell nicht mehr trainiert.

Trainings-Hyperparameter Wert
Lernrate 1e–3
Epochen 1000
Batchgröße 512
Vorzeitiges Beenden Parameter: val_loss, Geduld: 1

Tabelle 3: Hyperparameter trainieren

Mit dem folgenden Keras-Code wird der Trainingsprozess mithilfe der Parameter implementiert in den Tabellen 2 und 3 oben:

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]

Codebeispiele zum Trainieren des Sequenzmodells finden Sie hier.