Construire un programme de classification de texte : un didacticiel PNL

Publié: 2022-03-11

L'apprentissage en profondeur est une technologie qui est devenue un élément essentiel des flux de travail d'apprentissage automatique. En capitalisant sur les améliorations de la puissance de calcul parallèle et des outils de support, les réseaux de neurones complexes et profonds qui étaient autrefois impraticables deviennent maintenant viables.

L'émergence de bibliothèques puissantes et accessibles telles que Tensorflow, Torch et Deeplearning4j a également ouvert le développement aux utilisateurs au-delà des universités et des départements de recherche des grandes entreprises technologiques. Témoignage de son omniprésence croissante, des entreprises comme Huawei et Apple incluent désormais des processeurs dédiés et optimisés pour l'apprentissage en profondeur dans leurs nouveaux appareils pour alimenter les applications d'apprentissage en profondeur.

L'apprentissage en profondeur a prouvé sa puissance dans de nombreux domaines. Plus particulièrement, AlphaGo de Google a pu vaincre des joueurs humains dans un jeu de Go, un jeu dont la complexité époustouflante était autrefois considérée comme une barrière presque insurmontable pour les ordinateurs dans sa compétition contre les joueurs humains. Le projet Flow Machines de Sony a développé un réseau de neurones capable de composer de la musique dans le style de célèbres musiciens du passé. FaceID, une fonctionnalité de sécurité développée par Apple, utilise l'apprentissage en profondeur pour reconnaître le visage de l'utilisateur et pour suivre les modifications apportées au visage de l'utilisateur au fil du temps.

Dans cet article, nous appliquerons le deep learning à deux de mes sujets préférés : le traitement automatique du langage naturel et le vin. Nous allons construire un modèle pour comprendre les critiques de vin en langage naturel par des experts et en déduire la variété du vin qu'ils évaluent.

Apprentissage en profondeur pour la PNL

L'apprentissage en profondeur a été largement utilisé dans le traitement du langage naturel (TAL) car il est bien adapté pour apprendre la structure sous-jacente complexe d'une phrase et la proximité sémantique de divers mots. Par exemple, l'état actuel de l'art pour l'analyse des sentiments utilise l'apprentissage en profondeur afin de capturer des concepts linguistiques difficiles à modéliser tels que les négations et les sentiments mixtes.

L'apprentissage en profondeur présente plusieurs avantages par rapport aux autres algorithmes de NLP :

  1. Modèles flexibles : les modèles d'apprentissage en profondeur sont beaucoup plus flexibles que les autres modèles de ML. Nous pouvons facilement expérimenter différentes structures, en ajoutant et en supprimant des couches au besoin. Les modèles d'apprentissage en profondeur permettent également de créer des modèles avec des sorties flexibles. La flexibilité est essentielle pour développer des modèles bien adaptés à la compréhension de structures linguistiques complexes. Il est également essentiel pour développer des applications NLP telles que des traductions, des chatbots et des applications de synthèse vocale.
  2. Moins de connaissances du domaine requises : bien qu'il faille certainement une certaine connaissance du domaine et de l'intuition pour développer un bon modèle d'apprentissage en profondeur, la capacité des algorithmes d'apprentissage en profondeur à apprendre les hiérarchies de fonctionnalités par eux-mêmes signifie qu'un développeur n'a pas besoin d'autant de connaissances approfondies du espace de problèmes pour développer des algorithmes de PNL d'apprentissage en profondeur. Pour un espace de problèmes aussi complexe que le langage naturel, c'est un avantage très appréciable.
  3. Apprentissage continu plus facile : les algorithmes d'apprentissage en profondeur sont faciles à former à mesure que de nouvelles données arrivent. Certains algorithmes d'apprentissage automatique nécessitent que l'ensemble de données entier soit envoyé via le modèle pour être mis à jour, ce qui poserait un problème pour les grands ensembles de données en direct.

Le problème aujourd'hui

Aujourd'hui, nous allons construire un algorithme d'apprentissage en profondeur pour déterminer la variété du vin évalué en fonction du texte de l'avis. Nous utiliserons l'ensemble de données du magazine Wine sur https://www.kaggle.com/zynicide/wine-reviews qui est fourni par l'utilisateur Kaggle zackthoutt .

Conceptuellement, la question est, pouvons-nous prendre une critique de vin comme…

Les arômes comprennent des fruits tropicaux, du genêt, du soufre et des herbes séchées. La bouche n'est pas trop expressive, offrant des arômes de pomme non mûrie, d'agrumes et de sauge séchée accompagnés d'une vive acidité.

…et reconnaître qu'il s'agit d'un mélange blanc ? Certains amateurs de vin pourraient reconnaître les signes révélateurs des vins blancs tels que la pomme, les agrumes et une acidité prononcée, mais pouvons-nous entraîner notre réseau neuronal à reconnaître ces signaux ? De plus, pouvons-nous entraîner notre réseau de neurones à reconnaître les différences subtiles entre un examen de mélange blanc et un examen de pinot grigio ?

Algorithmes similaires

Le problème sur lequel nous travaillons aujourd'hui est essentiellement un problème de classification NLP. Il existe plusieurs algorithmes de classification NLP qui ont été appliqués à divers problèmes de NLP. Par exemple, des Bayes naïfs ont été utilisés dans divers algorithmes de détection de spam, et des machines à vecteurs de support (SVM) ont été utilisées pour classer des textes tels que des notes d'évolution dans des établissements de santé. Il serait intéressant d'implémenter une version simple de ces algorithmes pour servir de base à notre modèle d'apprentissage profond.

Bayes naïf

Une implémentation populaire de Bayes naïfs pour la PNL consiste à prétraiter le texte à l'aide de TF-IDF, puis à exécuter le Bayes naïf multinomial sur les sorties prétraitées. Cela permet à l'algorithme d'être exécuté sur les mots les plus importants d'un document. Nous pouvons implémenter le Bayes naïf comme suit :

 import numpy as np from sklearn.naive_bayes import MultinomialNB from sklearn.feature_extraction.text import CountVectorizer import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfTransformer df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() varietal_list = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = np.array(varietal_list) count_vect = CountVectorizer() x_train_counts = count_vect.fit_transform(description_list) tfidf_transformer = TfidfTransformer() x_train_tfidf = tfidf_transformer.fit_transform(x_train_counts) train_x, test_x, train_y, test_y = train_test_split(x_train_tfidf, varietal_list, test_size=0.3) clf = MultinomialNB().fit(train_x, train_y) y_score = clf.predict(test_x) n_right = 0 for i in range(len(y_score)): if y_score[i] == test_y[i]: n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))

Exécutez le code ci-dessus et vous devriez voir quelque chose comme ceci : 73,56 %

Considérant que nous envisageons 10 classes, c'est un assez bon résultat.

Nous pouvons également utiliser la machine à vecteurs de support et voir comment cela se passerait. Pour voir comment il fonctionne, remplacez simplement la définition du classificateur par

 clf = SVC(kernel='linear').fit(train_x, train_y)

Exécutez ceci et vous devriez voir la sortie suivante :

Précision : 80,66 %

Pas trop moche non plus.

Voyons si nous pouvons construire un modèle d'apprentissage en profondeur qui peut surpasser ou au moins égaler ces résultats. Si nous y parvenons, ce serait une excellente indication que notre modèle d'apprentissage en profondeur est efficace pour au moins reproduire les résultats des modèles d'apprentissage automatique populaires informés par l'expertise du domaine.

Construire le modèle

Aujourd'hui, nous allons utiliser Keras avec Tensorflow pour construire notre modèle. Keras est une bibliothèque Python qui facilite la création de modèles d'apprentissage en profondeur par rapport à l'interface relativement bas niveau de l'API Tensorflow. En plus des couches denses, nous utiliserons également des couches d'intégration et de convolution pour apprendre les informations sémantiques sous-jacentes des mots et les modèles structurels potentiels dans les données.

Nettoyage des données

Premièrement, nous devrons restructurer les données de manière à ce qu'elles puissent être facilement traitées et comprises par notre réseau de neurones. Nous pouvons le faire en remplaçant les mots par des numéros d'identification uniques. Combiné avec un vecteur d'intégration, nous sommes capables de représenter les mots d'une manière à la fois flexible et sémantiquement sensible.

En pratique, nous voudrons être un peu plus intelligents sur ce prétraitement. Il serait logique de se concentrer sur les mots couramment utilisés et de filtrer également les mots les plus couramment utilisés (par exemple, le, ceci, a).

Nous pouvons implémenter cette fonctionnalité en utilisant Defaultdict et NLTK. Écrivez le code suivant dans un module Python distinct. Je l'ai placé dans lib/get_top_x_words.py .

 from nltk import word_tokenize from collections import defaultdict def count_top_x_words(corpus, top_x, skip_top_n): count = defaultdict(lambda: 0) for c in corpus: for w in word_tokenize(c): count[w] += 1 count_tuples = sorted([(w, c) for w, c in count.items()], key=lambda x: x[1], reverse=True) return [i[0] for i in count_tuples[skip_top_n: skip_top_n + top_x]] def replace_top_x_words_with_vectors(corpus, top_x): topx_dict = {top_x[i]: i for i in range(len(top_x))} return [ [topx_dict[w] for w in word_tokenize(s) if w in topx_dict] for s in corpus ], topx_dict def filter_to_top_x(corpus, n_top, skip_n_top=0): top_x = count_top_x_words(corpus, n_top, skip_n_top) return replace_top_x_words_with_vectors(corpus, top_x)

Nous sommes maintenant prêts à construire le modèle. Nous voulons une couche d'intégration, une couche convolutive et une couche dense pour tirer parti de toutes les fonctionnalités d'apprentissage en profondeur qui peuvent être utiles pour notre application. Avec Keras, on peut construire le modèle très simplement :

 from keras.models import Sequential from keras.layers import Dense, Conv1D, Flatten from keras.layers.embeddings import Embedding from keras.preprocessing import sequence from keras.utils import to_categorical import pandas as pd from collections import Counter from sklearn.model_selection import train_test_split from lib.get_top_xwords import filter_to_top_x df = pd.read_csv('data/wine_data.csv') counter = Counter(df['variety'].tolist()) top_10_varieties = {i[0]: idx for idx, i in enumerate(counter.most_common(10))} df = df[df['variety'].map(lambda x: x in top_10_varieties)] description_list = df['description'].tolist() mapped_list, word_list = filter_to_top_x(description_list, 2500, 10) varietal_list_o = [top_10_varieties[i] for i in df['variety'].tolist()] varietal_list = to_categorical(varietal_list_o) max_review_length = 150 mapped_list = sequence.pad_sequences(mapped_list, maxlen=max_review_length) train_x, test_x, train_y, test_y = train_test_split(mapped_list, varietal_list, test_size=0.3) max_review_length = 150 embedding_vector_length = 64 model = Sequential() model.add(Embedding(2500, embedding_vector_length, input_length=max_review_length)) model.add(Conv1D(50, 5)) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dense(max(varietal_list_o) + 1, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(train_x, train_y, epochs=3, batch_size=64) y_score = model.predict(test_x) y_score = [[1 if i == max(sc) else 0 for i in sc] for sc in y_score] n_right = 0 for i in range(len(y_score)): if all(y_score[i][j] == test_y[i][j] for j in range(len(y_score[i]))): n_right += 1 print("Accuracy: %.2f%%" % ((n_right/float(len(test_y)) * 100)))

Exécutez le code et vous devriez voir la sortie suivante.

Précision : 77,20 %

Rappelons que la précision pour Bayes naïf et SVC était de 73,56 % et 80,66 % respectivement. Notre réseau de neurones résiste donc très bien à certaines des méthodes de classification de texte les plus courantes.

Conclusion

Aujourd'hui, nous avons couvert la construction d'un modèle d'apprentissage en profondeur de classification pour analyser les avis sur les vins.

Nous avons constaté que nous étions capables de construire un modèle capable de rivaliser et de surpasser certains des autres algorithmes d'apprentissage automatique. Nous espérons que vous serez inspiré à utiliser ces informations pour créer des applications qui analysent des ensembles de données plus complexes et génèrent des sorties plus complexes !

Remarque : Vous pouvez trouver le code que j'ai utilisé pour cet article sur GitHub.


Lectures complémentaires sur le blog Toptal Engineering :

  • Un sens plus profond : modélisation de sujet en Python
  • Comment créer un bot d'analyse des sentiments des e-mails : un didacticiel PNL