PC & Mobile

Détecter les messages de spam avec C # et un réseau de neurones profonds CNTK

Détecter les messages de spam avec C # et un réseau de neurones profonds CNTK


C’est un fichier TSV avec seulement 2 colonnes d’informations:

  • Libellé: "spam" pour un spam et "ham" pour un message normal.
  • Message: le texte complet du message SMS.

Je vais construire un réseau de classification binaire qui lit tous les messages, puis effectue une prédiction pour chaque message s'il s'agit d'un spam ou d'un ham.

Commençons. Voici comment configurer un nouveau projet de console dans NET Core:

$ dotnet nouvelle console -o SpamDetection
$ cd SpamDetection

Ensuite, je dois installer les packages requis:

$ dotnet add package Microsoft.ML
$ dotnet add package CNTK.GPU
$ dotnet add package XPlot.Plotly
$ dotnet add package Fsharp.Core

Microsoft.ML est le package d'apprentissage automatique de Microsoft. Nous allons utiliser pour charger et traiter les données de l'ensemble de données.

le CNTK.GPU La bibliothèque est la boîte à outils cognitive de Microsoft qui permet de former et d’exécuter des réseaux neuronaux profonds.

Et Xplot.Plotly est une bibliothèque de traçage impressionnante basée sur Plotly. La bibliothèque est conçue pour F #, nous devons donc également tirer le Fsharp.Core bibliothèque.

le CNTK.GPU Le package formera et exécutera des réseaux de neurones profonds à l’aide de votre GPU Pour que cela fonctionne, vous aurez besoin d’un pilote graphique NVidia et d’un pilote graphique Cuda.

Si vous n’avez pas de GPU NVidia ou de pilotes appropriés, la bibliothèque se repliera et utilisera plutôt le processeur. Cela fonctionnera mais la formation des réseaux de neurones prendra beaucoup plus de temps.

CNTK est une bibliothèque de tenseurs de bas niveau destinée à la construction, à la formation et à la gestion de réseaux de neurones profonds. Le code pour construire un réseau de neurones profonds peut être un peu verbeux, alors j’ai développé un petit wrapper appelé CNTKUtil cela vous aidera à écrire du code plus rapidement.

Vous pouvez télécharger les fichiers CNTKUtil et les enregistrer dans un nouveau CNTKUtil dossier au même niveau que votre dossier de projet.

Assurez-vous ensuite que vous êtes dans le dossier de projet de la console et créez une référence de projet comme celle-ci:

$ dotnet add reference ..  CNTKUtil  CNTKUtil.csproj

Je suis maintenant prêt à commencer à écrire du code. Je vais éditer le fichier Program.cs avec le code Visual Studio et ajouter le code suivant:

le SpamData La classe contient toutes les données pour un seul spam. Notez comment chaque champ est marqué avec un LoadColumn attribut qui indiquera au code de chargement des données TSV à partir de quelle colonne importer les données.

Malheureusement, je ne peux pas former directement un réseau de neurones profonds sur des données textuelles. Je dois d'abord convertir le texte en chiffres.

J'arriverai à cette conversion plus tard. Pour le moment, j’ajouterai ici une classe qui contiendra le texte converti:

Il y a le Étiquette encore une fois, mais remarquez comment le message a maintenant été converti en VBuffer et stocké dans le Caractéristiques champ.

le VBuffer le type est un vecteur clairsemé. Il va stocker un très grand vecteur avec principalement des zéros et seulement quelques valeurs non nulles. La bonne chose à propos du type VBuffer est qu'il ne stocke que les valeurs non nulles. Les zéros ne sont pas stockés et n'occupent aucun espace en mémoire.

le GetFeatures appels de méthode DenseValues renvoyer le vecteur complet et le renvoie sous forme de flotte[] que notre réseau de neurones comprend.

Et il y a un GetLabel méthode qui renvoie 1 si le message est un spam (indiqué par le champ Étiquette contenant le mot «spam») et 0 si le message n'est pas du spam.

Les caractéristiques représentent le texte converti en un vecteur fragmenté sur lequel nous allons utiliser le réseau de neurones, et l’étiquette est la variable de sortie que nous essayons de prédire. Nous nous entraînons donc sur le texte codé pour prédire si ce texte est du spam ou non.

Il est maintenant temps de commencer à écrire la méthode du programme principal:

Lorsque vous utilisez la bibliothèque ML.NET, vous devez toujours définir un contexte d’apprentissage automatique représenté par le MLContext classe.

Le code appelle le LoadFromTextFile méthode pour charger les données CSV en mémoire. Noter la SpamData type argument qui indique à la méthode la classe à utiliser pour charger les données.

J'utilise alors TrainTestSplit diviser les données dans une partition d’apprentissage contenant 70% des données et une partition d’essai contenant 30% des données.

Notez que je dévie de la répartition habituelle 80–20 ici. Cela est dû au fait que le fichier de données est assez petit et que 20% des données ne suffisent donc pas pour tester le réseau de neurones.

Il est maintenant temps de créer un pipeline pour convertir le texte en données rares codées en vecteur. Je vais utiliser le FeaturizeText composant de la bibliothèque d'apprentissage machine ML.NET:

Les canalisations d’apprentissage automatique dans ML.NET sont construites en empilant des composants de transformation. Ici, j'utilise un seul composant, FeaturizeText, qui convertit les messages texte en SpamData.Message données fragmentées codées par des vecteurs dans une nouvelle colonne intitulée «Caractéristiques».

le FeaturizeText composant est une très bonne solution pour gérer les données d’entrée de texte. Le composant effectue un certain nombre de transformations sur le texte pour le préparer à la formation de modèle:

Le résultat est que chaque message est converti en un vecteur de valeurs numériques pouvant être facilement traitées par un réseau de neurones profonds.

J'appelle le En forme méthode pour initialiser le pipeline, puis appelez Transformer deux fois pour transformer le texte dans les partitions d'apprentissage et de test.

Enfin j'appelle CreateEnumerable convertir les données de formation et de test en une énumération de ProcessedData les instances. Alors maintenant, j'ai les données de formation dans entraînement et les données de test dans essai. Les deux sont des énumérations de ProcessedData les instances.

Mais CNTK ne peut pas s’entraîner à une énumération d’instances de classe. Il nécessite un flotte[][] pour les fonctionnalités et flotte[] pour les étiquettes.

Je dois donc configurer quatre tableaux de flotteurs:

Ces expressions LINQ configurent quatre tableaux contenant les caractéristiques et les données d'étiquette pour les partitions d'apprentissage et de test.

Maintenant, je dois dire à CNTK quelle est la forme des données d'entrée sur lesquelles je vais entraîner le réseau neuronal et quelle forme auront les données de sortie du réseau neuronal:

Je ne sais pas à l'avance combien de dimensions le FeaturizeText composant va créer, donc je vérifie simplement la largeur du données d'entraînement tableau.

La première Var méthode dit CNTK que mon réseau de neurones utilisera un tenseur à 1 dimension de nodeCount valeurs flottantes en entrée. Cette forme correspond au tableau retourné par le ProcessedData.GetFeatures méthode.

Et le deuxième Var La méthode indique au CNTK que je souhaite que mon réseau de neurones génère une seule valeur float. Cette forme correspond à la valeur unique renvoyée par le ProcessedData.GetLabel méthode.

Ma prochaine étape consiste à concevoir le réseau de neurones.

J'utiliserai un réseau neuronal profond avec une couche d'entrée à 16 nœuds, une couche cachée à 16 nœuds et une couche de sortie à un nœud. Je vais utiliser le ReLU fonction d'activation pour les couches d'entrée et cachées, et Sigmoïde activation pour la couche de sortie.

La fonction sigmoïde force la sortie d'un réseau de régression dans une plage de 0..1, ce qui signifie que je peux traiter le nombre comme une probabilité de classification binaire. Nous pouvons donc transformer n'importe quel réseau de régression en réseau de classification binaire en ajoutant simplement la fonction d'activation sigmoïde à la couche en sortie.

Voici comment construire ce réseau de neurones:

Chaque Dense call ajoute une nouvelle couche de densité directe dense au réseau. Je suis empiler deux couches, à la fois en utilisant ReLU activation, puis ajoutez une dernière couche avec un seul nœud en utilisant Sigmoïde Activation.

Puis j'utilise le Pour résumer méthode pour sortir une description de l’architecture du réseau de neurones sur la console.

Maintenant, je dois décider quelle fonction de perte utiliser pour entraîner le réseau de neurones et comment je vais suivre l'erreur de prédiction du réseau à chaque époque de formation.

j'utiliserai BinaryCrossEntropy fonction de perte, car il s’agit de la métrique standard de mesure de la perte de classification binaire.

Et je vais suivre l’erreur avec le BinaryClassificationError métrique. C'est le nombre de fois (exprimé en pourcentage) que les prédictions du modèle sont fausses. Une erreur de 0 signifie que les prédictions sont correctes tout le temps et une erreur de 1 signifie que les prédictions sont fausses tout le temps.

Ensuite, je dois décider quel algorithme utiliser pour entraîner le réseau de neurones. Il existe de nombreux algorithmes dérivés de la descente de gradient que nous pouvons utiliser ici.

Je vais utiliser le AdamLearner. Vous pouvez en apprendre plus sur l'algorithme Adam ici: https: //machinelearningmastery.com/adam ...

Ces valeurs de configuration constituent un bon point de départ pour de nombreux scénarios d’apprentissage automatique, mais vous pouvez les modifier si vous souhaitez essayer d’améliorer la qualité des prévisions.

Nous sommes presque prêts à nous entraîner. Ma dernière étape consiste à mettre en place un formateur et un évaluateur pour calculer la perte et l’erreur à chaque époque d’entraînement:

le GetTrainer met en place un entraîneur qui suivra la perte et l’erreur pour la partition d’entraînement. Et GetEvaluator mettra en place un évaluateur qui suit l’erreur dans la partition de test.

Maintenant, je suis enfin prêt à commencer à former le réseau de neurones!

J'ai besoin d'ajouter le code suivant:

Je forme le réseau sur 10 périodes en utilisant une taille de lot de 64. Pendant la formation, je vais suivre les pertes et les erreurs du perte, formationError et testingError tableaux.

Une fois que la formation est terminée, je montre l'erreur de test final sur la console. Il s'agit du pourcentage d'erreurs commises par le réseau lors de la prévision des messages de spam.

Notez que l'erreur et la précision sont liées: précision = 1 - erreur. Donc, je rapporte également la précision finale du réseau de neurones.

Voici le code pour former le réseau de neurones. Cela devrait aller dans la boucle for:

le Index (). Aléatoire (). Batch () La séquence randomise les données et les divise en une collection de lots de 64 enregistrements. Le deuxième argument à Lot() est une fonction qui sera appelée pour chaque lot.

Dans la fonction batch, j'appelle GetBatch deux fois pour obtenir un lot de fonctionnalités et un lot d'étiquettes correspondant. Alors j'appelle TrainBatch former le réseau de neurones sur ces deux lots de données d’entraînement.

le TrainBatch La méthode retourne la perte et l'erreur, mais uniquement pour l'apprentissage du lot de 64 enregistrements. Je additionne donc simplement toutes ces valeurs et les divise par le nombre de lots dans le jeu de données. Cela me donne la perte moyenne et les erreurs pour les prédictions sur la partition d’entraînement pendant l’époque actuelle, et je le signale à la console.

Alors maintenant, je connais la perte et l’erreur d’entraînement pour une seule époque d’entraînement. L'étape suivante consiste à tester le réseau en faisant des prédictions sur les données de la partition de test et à calculer l'erreur de test.

Ce code va dans la boucle d'époque et juste en dessous du code de formation:

Je n’ai pas besoin de mélanger les données pour les tester, alors je peux appeler Lot directement. Encore une fois j'appelle GetBatch pour obtenir des lots de fonctionnalités et d’étiquettes, mais notez que je fournis maintenant la données_test et étiquettes_test tableaux.

J'appelle TestBatch pour tester le réseau de neurones sur le lot de test de 64 enregistrements. La méthode retourne l'erreur pour le lot et j'additionne à nouveau les erreurs pour chaque lot et divise par le nombre de lots.

Cela me donne l'erreur moyenne dans les prédictions du réseau de neurones sur la partition de test pour cette époque.

Une fois la formation terminée, les erreurs de formation et de test pour chaque époque seront disponibles dans formationError et testingError tableaux. Utilisons XPlot pour créer un joli graphique des deux courbes d’erreur afin de vérifier le surajustement:

Ce code crée un Terrain avec deux Dispersion graphiques. Le premier parcourt la formationError les valeurs et le second parcelles la testingError valeurs.

Enfin j'utilise File.WriteAllText écrire le tracé sur le disque en tant que fichier HTML.

Je suis maintenant prêt à construire et à exécuter l'application!

Premièrement, je dois construire la bibliothèque CNTKUtil en exécutant cette commande dans le dossier CNTKUtil:

$ dotnet build -o bin / Debug / netcoreapp3.0 -p: Plate-forme = x64

Cela construira le projet CNKTUtil. Notez que je spécifie la plate-forme x64 car la bibliothèque CNTK nécessite une version 64 bits.

Maintenant, je dois exécuter cette commande dans le dossier SpamDetection:

$ dotnet build -o bin / Debug / netcoreapp3.0 -p: Plate-forme = x64

Cela construira l'application. Notez que je spécifie à nouveau la plate-forme x64.

Maintenant je peux lancer l'application:

$ dotnet run

L'application crée le réseau de neurones, charge l'ensemble de données, forme le réseau sur les données et crée un graphique de la formation et vérifie les erreurs pour chaque époque.

Voici le réseau de neurones en cours de formation sur mon ordinateur portable:

Et voici les résultats:

L'erreur finale de classification est 0 lors de l'entraînement et 0,010 lors des tests. Cela correspond à une précision finale sur les tests de 0,99. Cela signifie que le réseau de neurones effectue 99 prédictions correctes pour 100 messages.

Celles-ci semblent être des résultats étonnants. Vous remarquez que les courbes d’entraînement et de test commencent à diverger à l’époque 2? L'erreur d'apprentissage continue de converger vers zéro tandis que l'erreur de test est à plat à 0,01. C'est classique surapprentissage.

Un surajustement signifie que les messages sont trop complexes pour être traités par le modèle. Le mode n'est pas assez sophistiqué pour saisir la complexité des modèles dans les données.

Et c'est à prévoir. Le traitement du texte anglais est un problème formidable et un domaine de recherche active, même aujourd'hui. Un simple réseau de neurones à 32 nœuds ne pourra pas générer de prédictions de spam précises.

Et si nous augmentions la complexité du réseau de neurones? Doublons le nombre de nœuds des calques d’entrée et masqués:

Le réseau de neurones dispose désormais de 766 881 paramètres configurables à former à chaque époque. C'est un réseau massif, mais à quoi ressembleront les résultats?

Eh bien, vérifiez-le:

Rien n'a changé. Je reçois toujours une erreur d’entraînement de zéro et une erreur d’essai de 0,01. Et les courbes divergent encore, maintenant à l'époque 1.

Allons de l'avant et augmentons le nombre de nœuds à 512:

Le réseau de neurones a maintenant 12 515 841 paramètres pouvant être entraînés.

Et voici les résultats:

Encore pas de changement. Que se passe t-il ici?

Cela ne fonctionne pas parce que le réseau de neurones d'origine était déjà assez grand. Les 16 nœuds d'entrée peuvent vérifier la présence de 16 mots différents dans un message pour déterminer si le message est un spam ou non. C’est en fait plus que suffisant pour faire le travail.

La raison pour laquelle j’obtiens de piètres résultats est que la signification d’une phrase anglaise est déterminée par la séquence précise des mots de la phrase.

Par exemple, dans le fragment de texte «pas très bien», la signification de «bien» est inversée par la présence de «pas très». Si je vérifie simplement la présence du mot «bien», j'obtiens une image totalement incorrecte du sens de la phrase.

Mon réseau de neurones examine tous les mots d'un message à la fois, ignore leur ordre et teste simplement le spam en vérifiant si certains mots apparaissent n'importe où ou pas. Cette approche ne suffit pas pour le traitement du langage.

Alors qu'est-ce que tu en penses?

Êtes-vous prêt à commencer à écrire des applications d'apprentissage machine C # avec CNTK?

Afficher plus

SupportIvy

SupportIvy.com : Un lieu pour partager le savoir et mieux comprendre le monde. Meilleure plate-forme de support gratuit pour vous, Documentation &Tutoriels par les experts.

Articles similaires

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Bouton retour en haut de la page
Fermer