1
votes

Formation de classification de texte CNN overfits

J'essaie d'utiliser une architecture CNN pour classer les phrases de texte. L'architecture du réseau est la suivante:

text_input = Input(shape=X_train_vec.shape[1:], name = "Text_input")

conv2 = Conv1D(filters=128, kernel_size=5, activation='relu')(text_input)
drop21 = Dropout(0.5)(conv2)
conv22 = Conv1D(filters=64, kernel_size=5, activation='relu')(drop21)
drop22 = Dropout(0.5)(conv22)

lstm1 = Bidirectional(LSTM(128, return_sequences = True))(drop22)
lstm2 = Bidirectional(LSTM(64, return_sequences = True))(lstm1)

flat = Flatten()(lstm2)
dense = Dense(128, activation='relu')(flat)
out = Dense(32, activation='relu')(dense)

outputs = Dense(y_train.shape[1], activation='softmax')(out)

model = Model(inputs=text_input, outputs=outputs)
# compile
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

J'ai quelques rappels comme early_stopping et reductionLR pour arrêter la formation et réduire le taux d'apprentissage lorsque la perte de validation ne s'améliore pas (diminue).

norm = BatchNormalization()(conv2)

Une fois le modèle entraîné, l'historique de la formation se déroule comme suit: entrez la description de l'image ici

Nous pouvons observer ici que la perte de validation ne s'améliore pas à partir de l'époque 5 et que la perte d'entraînement est surajustée à chaque étape.

J'aimerais savoir si je fais quelque chose de mal dans l'architecture de CNN? Les couches de décrochage ne sont-elles pas suffisantes pour éviter le surajustement? Quels sont les autres moyens de réduire le surajustement?

Une suggestion?

Merci d'avance.


Modifier:

J'ai essayé aussi avec la régularisation et le résultat où encore pire:

kernel_regularizer=l2(0.01), bias_regularizer=l2(0.01)

 entrez la description de l'image ici


Modifier 2 :

J'ai essayé d'appliquer des couches BatchNormalization après chaque convolution et le résultat est le suivant:

early_stopping = EarlyStopping(monitor='val_loss', 
                               patience=5)
model_checkpoint = ModelCheckpoint(filepath=checkpoint_filepath,
                                   save_weights_only=False,
                                   monitor='val_loss',
                                   mode="auto",
                                   save_best_only=True)
learning_rate_decay = ReduceLROnPlateau(monitor='val_loss', 
                                        factor=0.1, 
                                        patience=2, 
                                        verbose=1, 
                                        mode='auto',
                                        min_delta=0.0001, 
                                        cooldown=0,
                                        min_lr=0)

 entrez la description de l'image ici


Edit 3:

Après avoir appliqué l'architecture LSTM:

text_input = Input(shape=X_train_vec.shape[1:], name = "Text_input")

conv2 = Conv1D(filters=128, kernel_size=5, activation='relu')(text_input)
drop21 = Dropout(0.5)(conv2)
pool1 = MaxPooling1D(pool_size=2)(drop21)
conv22 = Conv1D(filters=64, kernel_size=5, activation='relu')(pool1)
drop22 = Dropout(0.5)(conv22)
pool2 = MaxPooling1D(pool_size=2)(drop22)
dense = Dense(16, activation='relu')(pool2)

flat = Flatten()(dense)
dense = Dense(128, activation='relu')(flat)
out = Dense(32, activation='relu')(dense)

outputs = Dense(y_train.shape[1], activation='softmax')(out)

model = Model(inputs=text_input, outputs=outputs)
# compile
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

 entrez la description de l'image ici


16 commentaires

La question la plus importante est: "Quelle est la taille de votre ensemble de données?" Cela semble être un très petit ensemble de données. Si tel est le cas, votre première réaction devrait être de collecter plus de données.


Ce n'est pas petit. J'ai environ 40000 échantillons.


Ensuite, il doit y avoir un autre problème. Puisque la perte de validation diminue à peine, cela n'apprend rien d'utile. Combien de cours avez-vous? Vos cours sont-ils équilibrés?


Il y a deux classes et la répartition est de 58%, 42%


Hmm. C'est difficile à deviner sans plus d'informations, mais je suppose toujours que quelque chose ne va pas avec les données. Est-ce un projet personnalisé? Qu'essayez-vous de prédire?


Oui, c'est un projet personnalisé. J'essaie de prédire la catégorie d'un incident en fonction du texte d'entrée de l'utilisateur.


Continuons cette discussion dans le chat .


L'ajout de Conv Layer vous a-t-il aidé?


Pouvez-vous spécifier X_train_vec.shape [1:] et y_train.shape [1]?


X_train_vec [1:] est de (1000,1) et y_train [1] est de 2


À quoi ressemblent les images? S'agit-il d'une image contenant plusieurs lignes de texte ou une ligne par image? Peut-être que la segmentation des lignes aiderait. Et puis en effet inclure des couches récurrentes pour préserver les informations structurelles du passé tout en itérant à travers le reste de l'image


Il semble que les ensembles de données de formation et de validation soient de nature complètement différente. Nous obtenons ces types de graphiques lorsque nous essayons de transférer l'apprentissage avec une seule ou au maximum deux couches pouvant être entraînées. Je suggérerais donc de mélanger les données, puis de diviser les données de train et de validation.


Il n'y a pas d'images @DanielB. l'ensemble de données est constitué de texte et le but est la classification.


Les ensembles de données de test et de train sont tirés des mêmes données @jarryjafery, j'ai également essayé de valider la formation du NN en fractionnant l'ensemble de formation et les résultats étaient les mêmes.


Mais pour quelle raison avez-vous choisi d'employer un CNN? Puisqu'il s'agit de séquences de texte, je m'attendrais à ce que les RNN fonctionnent mieux sur la tâche. Et en plus: comment le texte de l'ensemble de données est-il représenté? Intégration de mots clairsemés ou denses?


@DanielB. Il a été utilisé dans une autre expérience avec le même objectif de classification de texte. Même ainsi, j'ai également utilisé RNN en utilisant des cellules LSTM et la sortie était la même.


4 Réponses :


2
votes

Le surajustement peut être causé par de nombreux facteurs, cela se produit lorsque votre modèle s'adapte trop bien à l'ensemble d'entraînement.

Pour le gérer, vous pouvez procéder de plusieurs manières:

  1. Ajouter plus de données
  2. Utiliser l'augmentation des données
  3. Utilisez des architectures qui se généralisent bien
  4. Ajouter une régularisation (principalement des abandons, des régularisations L1 / L2 sont également possibles)
  5. Réduisez la complexité de l'architecture

pour plus de clarté, vous pouvez lire dans https: //towardsdatascience.com/deep-learning-3-more-on-cnns-handling-overfitting-2bd5d99abe5d


0 commentaires

0
votes

Je pense que puisque vous faites une classification de texte, l'ajout de 1 ou 2 couches LSTM pourrait aider le réseau à mieux apprendre, car il pourra mieux s'associer au contexte des données. Je suggère d'ajouter le code suivant avant la couche d'aplatissement.

lstm1 = Bidirectional(LSTM(128, return_sequence = True))
lstm2 = Bidirectional(LSTM(64))

Les couches LSTM peuvent aider le réseau neuronal à apprendre l'association entre certains mots et pourraient améliorer la précision de votre réseau.

I Suggérer également de supprimer les couches de regroupement maximal, car le regroupement maximal, en particulier dans la classification de texte, peut amener le réseau à abandonner certaines des fonctionnalités utiles. Gardez simplement les couches convolutives et le décrochage. Supprimez également le calque Dense avant d'aplatir et ajoutez les LSTM susmentionnés.


3 commentaires

J'ai essayé l'architecture que vous avez présentée, mais les résultats étaient pires qu'avec des circonvolutions. La perte de validation n'a commencé à diminuer qu'à la 12e époque et, une fois qu'elle a commencé à diminuer, elle ne s'est améliorée que de 1% de 0,5754 à 0,5913. De plus, val_loss était toujours plus élevé que la perte de train (la précision était également plus élevée). Je suppose que c'est une situation étrange, j'attache le chiffre en tant que modification à la question.


Essayez d'ajouter un calque d'intégration.


J'ai essayé d'ajouter un calque d'intégration de texte rapide. Et les résultats étaient également mauvais.



1
votes

Cela crie Apprentissage par transfert . google-universal-phrase-encoder est parfait pour ce cas d'utilisation. Remplacez votre modèle par

import tensorflow_hub as hub 
import tensorflow_text

text_input = Input(shape=X_train_vec.shape[1:], name = "Text_input")

# this next layer might need some tweaking dimension wise, to correctly fit
# X_train in the model
text_input = tf.keras.layers.Lambda(lambda x: tf.squeeze(x))(text_input)
# conv2 = Conv1D(filters=128, kernel_size=5, activation='relu')(text_input)
# drop21 = Dropout(0.5)(conv2)
# pool1 = MaxPooling1D(pool_size=2)(drop21)
# conv22 = Conv1D(filters=64, kernel_size=5, activation='relu')(pool1)
# drop22 = Dropout(0.5)(conv22)
# pool2 = MaxPooling1D(pool_size=2)(drop22)

# 1) you might need `text_input = tf.expand_dims(text_input, axis=0)` here
# 2) If you're classifying English only, you can use the link to the normal `google-universal-sentence-encoder`, not the multilingual one
# 3) both the English and multilingual have a `-large` version. More accurate but slower to train and infer. 
embedded = hub.KerasLayer('https://tfhub.dev/google/universal-sentence-encoder-multilingual/3')(text_input) 

# this layer seems out of place, 
# dense = Dense(16, activation='relu')(embedded) 

# you don't need to flatten after a dense layer (in your case) or a backbone (in my case (google-universal-sentence-encoder))
# flat = Flatten()(dense)

dense = Dense(128, activation='relu')(flat)
out = Dense(32, activation='relu')(dense)

outputs = Dense(y_train.shape[1], activation='softmax')(out)

model = Model(inputs=text_input, outputs=outputs)


11 commentaires

Merci, je vais essayer et je vais vous dire.


cela n'a-t-il pas fonctionné pour vous? Sinon, je supprimerai à nouveau la réponse.


J'ai des problèmes pour l'exécuter: ValueError: La forme doit être de rang 1 mais est de rang 2 pour 'text_preprocessor / tokenize / StringSplit / StringSplit' (op: 'StringSplit') avec des formes d'entrée: [?, 1], [].


avez-vous essayé text_input = tf.expand_dims (text_input, axis = 0) ou text_input = tf.squeeze (text_input) juste avant le code tf.KerasLayer ?


les deux se terminent par cette erreur: AttributeError: l'objet 'tuple' n'a pas d'attribut 'layer'


ah oui vous devez l'envelopper dans une couche tf.keras.layers.Lambda , j'ai mis à jour ma réponse


Maintenant, nous avons la même erreur que précédemment avec une autre dimension: ValueError: Shape doit être de rang 1 mais est de rang 3 pour 'text_preprocessor / tokenize / StringSplit / StringSplit' (op: 'StringSplit') avec des formes d'entrée: [1,?, 1], [].


Presque là - je pense que maintenant c'est squeeze au lieu de expand_dims . J'ai de nouveau mis à jour ma réponse.


Avec squeeze, nous sommes avec la même erreur: AttributeError: l'objet 'tuple' n'a pas d'attribut 'layer'


avez-vous des exemples de données pour X_train_vec ?


Enfin, j'ai intégré d'abord le train et les ensembles de test, puis j'ai démarré le réseau. Les résultats étaient comme les expériences précédentes, le réseau n'apprenait pas et j'ai essayé différentes architectures de réseau avec.



0
votes

La manière dont vous insérez le texte dans votre modèle n'est pas claire. Je suppose que vous tokenisez le texte pour le représenter sous la forme d'une séquence d'entiers, mais utilisez-vous un mot incorporé avant de l'introduire dans votre modèle? Sinon, je vous suggère de lancer un tensorflow entraînable Embedding au début de votre modèle. Il existe une technique intelligente appelée Embedding Lookup pour accélérer sa formation, mais vous pouvez la sauvegarder pour plus tard. Essayez d'ajouter cette couche à votre modèle. Ensuite, votre couche Conv1D aurait beaucoup plus de facilité à travailler sur une séquence de flottants. Aussi, je vous suggère de lancer BatchNormalization après chaque Conv1D , cela devrait aider à accélérer la convergence et la formation.


1 commentaires

J'ai ajouté une couche d'intégration de texte rapide et une normalisation par lots, mais les résultats étaient comme le reste.