web-dev-qa-db-fra.com

Empêcher l'ajustement excessif de la classification de texte à l'aide de l'intégration de Word avec LSTM

Objectif :

  • Identification du libellé de classe à l'aide d'une question saisie par l'utilisateur (telle que Question Système de réponse). 
  • Données extraites du fichier Big PDF et nécessité de prédire le nombre de pages ____ en fonction des entrées de l'utilisateur.
  • Principalement utilisé dans le document de politique, où les utilisateurs Ont des questions à propos de la politique et doivent afficher un numéro de page Particulier.

Implémentation précédente: Recherche élastique appliquée mais beaucoup moins de précision, car l’utilisateur entre un texte du type "J'ai besoin" == "veut" 


Informations sur le jeu de données: L'ensemble de données contient chaque ligne sous forme de texte (ou paragraphe) et d'étiquette (sous forme de numéro de page). ici la taille du jeu de données est petite, je n'ai que 500 lignes.

Mise en œuvre actuelle:

  • Application de l'incorporation de mots (gant) avec LSTM dans Keras et la fin du processus est Tensor-flow 
  • Droupout appliqué 
  • Activité appliquéeRégularisation 
  • Appliqué L2 W_normaliseur (de 0,1 à 0,001) 
  • Appliqué différents nb_Epoch de 10 à 600 
  • EMBEDDING_DIM changé de 100 à 300 des données de gant

PNL appliquée pour,

  • Convertir en minuscule 
  • Supprimer Stop Word of English 
  • Stemming 
  • Supprimer les numéros 
  • Supprimer l'URL et l'adresse IP

Résultat: la précision des données de test (ou des données de validation) est de 23%, tandis que celle des trains est de 91%.


Code:

import time
from time import strftime

import numpy as np
from keras.callbacks import CSVLogger, ModelCheckpoint
from keras.layers import Dense, Input, LSTM, ActivityRegularization
from keras.layers import Embedding, Dropout,Bidirectional
from keras.models import Model
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import Tokenizer
from keras.regularizers import l2
from keras.utils import to_categorical

import pickle
from DataGenerator import *

BASE_DIR = ''
GLOVE_DIR = 'D:/Dataset/glove.6B'  # BASE_DIR + '/glove.6B/'

MAX_SEQUENCE_LENGTH = 50
MAX_NB_WORDS = 20000
EMBEDDING_DIM = 300
VALIDATION_SPLIT = 0.2

# first, build index mapping words in the embeddings set
# to their embedding vector
np.random.seed(1337)  # for reproducibility

print('Indexing Word vectors.')

t_start = time.time()

embeddings_index = {}

if os.path.exists('pickle/glove.pickle'):
    print('Pickle found..')
    with open('pickle/glove.pickle', 'rb') as handle:
        embeddings_index = pickle.load(handle)
else:
    print('Pickle not found...')
    f = open(os.path.join(GLOVE_DIR, 'glove.6B.300d.txt'), encoding='utf8')
    for line in f:
        values = line.split()
        Word = values[0]
        coefs = np.asarray(values[1:], dtype='float32')
        embeddings_index[Word] = coefs
    f.close()
    with open('pickle/glove.pickle', 'wb') as handle:
        pickle.dump(embeddings_index, handle, protocol=pickle.HIGHEST_PROTOCOL)

print('Found %s Word vectors.' % len(embeddings_index))

# second, prepare text samples and their labels
print('Processing text dataset')

texts = []  # list of text samples
labels = []  # list of label ids
labels_index = {}  # dictionary mapping label name to numeric id

(texts, labels, labels_index) = get_data('D:/PolicyDocument/')

print('Found %s texts.' % len(texts))

# finally, vectorize the text samples into a 2D integer tensor
tokenizer = Tokenizer(nb_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)

Word_index = tokenizer.Word_index
print('Found %s unique tokens.' % len(Word_index))
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)

labels = to_categorical(np.asarray(labels))
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)

# split the data into a training set and a validation set
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]
num_validation_samples = int(VALIDATION_SPLIT * data.shape[0])

x_train = data[:-num_validation_samples]
y_train = labels[:-num_validation_samples]
x_val = data[-num_validation_samples:]
y_val = labels[-num_validation_samples:]

# prepare embedding matrix
num_words = min(MAX_NB_WORDS, len(Word_index))
embedding_matrix = np.zeros((num_words + 1, EMBEDDING_DIM))
print('Preparing embedding matrix. :', embedding_matrix.shape)
for Word, i in Word_index.items():
    embedding_vector = embeddings_index.get(Word)
    if embedding_vector is not None:
        # words not found in embedding index will be all-zeros.
        embedding_matrix[i] = embedding_vector

# load pre-trained Word embeddings into an Embedding layer
# note that we set trainable = False so as to keep the embeddings fixed
embedding_layer = Embedding(embedding_matrix.shape[0],
                            embedding_matrix.shape[1],
                            weights=[embedding_matrix],
                            input_length=MAX_SEQUENCE_LENGTH,
                            mask_zero=True,
                            trainable=False)

print('Training model.')

csv_file = "logs/training_log_" + strftime("%Y-%m-%d %H-%M", time.localtime()) + ".csv"
model_file = "models/Model_" + strftime("%Y-%m-%d %H-%M", time.localtime()) + ".mdl"
print("Model file:" + model_file)
csv_logger = CSVLogger(csv_file)

# train a 1D convnet with global maxpooling
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)

rate_drop_lstm = 0.15 + np.random.Rand() * 0.25
num_lstm = np.random.randint(175, 275)
rate_drop_dense = 0.15 + np.random.Rand() * 0.25

x = LSTM(num_lstm, return_sequences=True, W_regularizer=l2(0.001))(embedded_sequences)
x = Dropout(0.5)(x)
x = LSTM(64)(x)
x = Dropout(0.25)(x)
x = ActivityRegularization(l1=0.01, l2=0.001)(x)
preds = Dense(len(labels_index), activation='softmax')(x)

model = Model(sequence_input, preds)
model.compile(loss='categorical_crossentropy',
              optimizer='adam',
              metrics=['acc'])

model_checkpoint = ModelCheckpoint(model_file, monitor='val_loss', verbose=0, save_best_only=True,
                                   save_weights_only=False, mode='auto')

model.fit(x_train, y_train,
          batch_size=1,
          nb_Epoch=600,
          validation_data=(x_val, y_val), callbacks=[csv_logger, model_checkpoint])

score = model.evaluate(x_val, y_val, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])

t_end = time.time()
total = t_end - t_start
ret_str = "Time needed(s): " + str(total)
print(ret_str)
10
Somnath Kadam

Le décrochage et le BN sont très efficaces avec les NN avec anticipation. Cependant, ils peuvent causer des problèmes avec les RNN (Il existe de nombreux articles sur ce sujet)

Le meilleur moyen de mieux généraliser votre modèle RNN consiste à augmenter la taille du jeu de données. Dans votre cas (LSTM avec environ 200 cellules), vous souhaitez probablement disposer de l'ordre de 100 000 échantillons étiquetés ou plus sur lesquels vous entraîner.

8
MaxB

En plus de simplement réduire les paramètres tels que la taille d’incorporation et la quantité d’unités dans certaines couches, il existe également la possibilité d’ajuster les abandons récurrents dans les LSTM.

Les LSTM semblent suralimenter assez facilement (c'est ce que j'ai lu).

Ensuite, vous pouvez voir dans la documentation Keras l’utilisation de dropout et recurrent_dropout en tant que paramètres de chaque couche LSTM

Exemple avec des nombres arbitraires:

x = LSTM(num_lstm, return_sequences=True, W_regularizer=l2(0.001), recurrent_dropout=0.4)(embedded_sequences)
x = Dropout(0.5)(x)
x = LSTM(64,dropout=0,5, recurrent_dropout=0,3)(x)

D'autres causes peuvent être des données erronées ou insuffisantes:

  • Avez-vous essayé de mélanger le test et les données de validation et de créer un nouveau train et un nouvel ensemble de validation?

  • Combien de phrases avez-vous dans les données d'entraînement? Est-ce que vous essayez avec de petits ensembles? Utilisez l’ensemble ou essayez d’augmenter dada (créer de nouvelles phrases et leurs classifications, mais cela peut être très délicat avec du texte). 

6
Daniel Möller

Ce que vous décrivez ressemble beaucoup à un surajustement . Sans plus d'informations sur les données, la meilleure suggestion est d'essayer des méthodes de régularisation plus strictes . @ Daniel vous a déjà suggéré d'utiliser les paramètres d'abandon que vous n'avez pas utilisés - dropout et recurrent_dropout. Vous pouvez également essayer d’augmenter le rapport des couches supprimées, utilisez une régularisation plus stricte avec le paramètre W_regularizer.

D'autres options pourraient être ouvertes avec davantage d'informations, par exemple si vous avez essayé la suggestion de Daniel et quels en ont été les résultats.

3
ginge

Les méthodes de formation contradictoire (en tant que moyen de régularisation) mériteraient peut-être d’être explorées . Méthodes de formation contradictoire pour la classification de texte semi-supervisée

0
MARK