Mettre à jour votre application pour utiliser un modèle de machine learning avec filtrage du spam

1. Avant de commencer

Dans cet atelier de programmation, vous allez mettre à jour l'application que vous avez créée dans les ateliers de programmation précédents sur les premiers pas avec la classification de texte mobile.

Prérequis

  • Cet atelier de programmation s'adresse aux développeurs expérimentés qui ne connaissent pas le machine learning.
  • Cet atelier de programmation fait partie d'un parcours séquentiel. Si vous n'avez pas encore terminé les ateliers Créer une application de style de messagerie de base ou Créer un modèle de machine learning pour le spam dans les commentaires, veuillez les suivre maintenant.

Ce que vous allez [créer ou apprendre]

  • Vous apprendrez à intégrer votre modèle personnalisé à votre application, que vous avez créée lors des étapes précédentes.

Prérequis

2. Ouvrir l'application Android existante

Pour obtenir le code nécessaire, suivez l'atelier de programmation 1 ou clonez ce dépôt et chargez l'application à partir de TextClassificationStep1.

git clone https://github.com/googlecodelabs/odml-pathways

Vous le trouverez dans le chemin d'accès TextClassificationOnMobile->Android.

Le code finalisé est également disponible pour vous sous la forme TextClassificationStep2.

Une fois l'application ouverte, vous pouvez passer à l'étape 2.

3. Importer le fichier de modèle et les métadonnées

Dans l'atelier de programmation "Créer un modèle de machine learning pour le spam dans les commentaires", vous avez créé un modèle .TFLITE.

Vous auriez dû télécharger le fichier du modèle. Si vous ne l'avez pas, vous pouvez l'obtenir à partir du dépôt de cet atelier de programmation. Le modèle est disponible ici.

Ajoutez-le à votre projet en créant un répertoire d'éléments.

  1. Dans le navigateur de projet, assurez-vous que Android est sélectionné en haut.
  2. Effectuez un clic droit sur le dossier app. Sélectionnez New > Directory (Nouveau > Répertoire).

d7c3e9f21035fc15.png

  1. Dans la boîte de dialogue New Directory (Nouveau répertoire), sélectionnez src/main/assets.

2137f956a1ba4ef0.png

Un nouveau dossier assets est désormais disponible dans l'application.

ae858835e1a90445.png

  1. Effectuez un clic droit sur assets.
  2. Dans le menu qui s'affiche, vous verrez (sur Mac) Afficher dans le Finder. Sélectionnez-le. (Sur Windows, l'option s'intitule Afficher dans l'Explorateur, et sur Ubuntu, Afficher dans les fichiers.)

e61aaa3b73c5ab68.png

Le Finder s'ouvre pour afficher l'emplacement des fichiers (Explorateur de fichiers sous Windows, Fichiers sous Linux).

  1. Copiez les fichiers labels.txt, model.tflite et vocab dans ce répertoire.

14f382cc19552a56.png

  1. Revenez à Android Studio. Vous verrez que les éléments sont disponibles dans votre dossier assets.

150ed2a1d2f7a10d.png

4. Mettre à jour build.gradle pour utiliser TensorFlow Lite

Pour utiliser TensorFlow Lite et les bibliothèques de tâches TensorFlow Lite qui le prennent en charge, vous devez mettre à jour votre fichier build.gradle.

Les projets Android en comportent souvent plusieurs. Assurez-vous donc de trouver celui au niveau de l'application. Dans l'explorateur de projets en vue Android, recherchez-le dans la section Gradle Scripts (Scripts Gradle). Le bon fichier sera libellé .app, comme indiqué ci-dessous :

6426051e614bc42f.png

Vous devrez apporter deux modifications à ce fichier. La première se trouve dans la section dependencies (dépendances) en bas. Ajoutez un texte implementation pour la bibliothèque de tâches TensorFlow Lite, comme ceci :

implementation 'org.tensorflow:tensorflow-lite-task-text:0.1.0'

Le numéro de version peut avoir changé depuis la rédaction de cet article. Veillez donc à consulter https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier pour obtenir la dernière version.

Les bibliothèques de tâches nécessitent également une version minimale du SDK de 21. Pour accéder à ce paramètre, accédez à android > default config, puis définissez-le sur 21 :

c100b68450b8812f.png

Vous disposez maintenant de toutes vos dépendances. Il est donc temps de commencer à coder.

5. Ajouter une classe d'assistance

Pour séparer la logique d'inférence, où votre application utilise le modèle, de l'interface utilisateur, créez une autre classe pour gérer l'inférence du modèle. Appelez-la classe "helper".

  1. Effectuez un clic droit sur le nom du package dans lequel se trouve votre code MainActivity.
  2. Sélectionnez Nouveau > Package.

d5911ded56b5df35.png

  1. Une boîte de dialogue s'affiche au centre de l'écran et vous demande de saisir le nom du package. Ajoutez-le à la fin du nom de package actuel. (Ici, il s'agit de helpers.)

3b9f1f822f99b371.png

  1. Une fois cette opération effectuée, effectuez un clic droit sur le dossier helpers dans l'explorateur de projets.
  2. Sélectionnez New > Java Class (Nouveau > Classe Java), puis nommez-la TextClassificationClient. Vous modifierez le fichier à l'étape suivante.

Votre classe d'assistance TextClassificationClient se présentera comme suit (bien que le nom de votre package puisse être différent) :

package com.google.devrel.textclassificationstep1.helpers;

public class TextClassificationClient {
}
  1. Modifiez le fichier en ajoutant le code suivant :
package com.google.devrel.textclassificationstep2.helpers;

import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.util.List;

import org.tensorflow.lite.support.label.Category;
import org.tensorflow.lite.task.text.nlclassifier.NLClassifier;

public class TextClassificationClient {
    private static final String MODEL_PATH = "model.tflite";
    private static final String TAG = "CommentSpam";
    private final Context context;

    NLClassifier classifier;

    public TextClassificationClient(Context context) {
        this.context = context;
    }

    public void load() {
        try {
            classifier = NLClassifier.createFromFile(context, MODEL_PATH);
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    public void unload() {
        classifier.close();
        classifier = null;
    }

    public List<Category> classify(String text) {
        List<Category> apiResults = classifier.classify(text);
        return apiResults;
    }

}

Cette classe fournira un wrapper à l'interpréteur TensorFlow Lite, en chargeant le modèle et en résumant la complexité de la gestion de l'échange de données entre votre application et le modèle.

Dans la méthode load(), un nouveau type NLClassifier sera instancié à partir du chemin du modèle. Le chemin d'accès au modèle est simplement le nom du modèle, model.tflite. Le type NLClassifier fait partie des bibliothèques de tâches de texte. Il vous aide en convertissant votre chaîne en jetons, en utilisant la longueur de séquence appropriée, en la transmettant au modèle et en analysant les résultats.

(Pour en savoir plus, consultez "Créer un modèle de machine learning pour détecter le spam dans les commentaires".)

La classification est effectuée dans la méthode "classify", dans laquelle vous transmettez une chaîne et qui renvoie un List. Lorsque vous utilisez des modèles de machine learning pour classer du contenu et déterminer si une chaîne est du spam ou non, il est courant que toutes les réponses soient renvoyées, avec des probabilités attribuées. Par exemple, si vous lui transmettez un message qui ressemble à du spam, vous obtiendrez une liste de deux réponses : l'une indiquant la probabilité qu'il s'agisse d'un spam et l'autre indiquant la probabilité qu'il n'en soit pas un. "Spam" et "Pas spam" sont des catégories. La valeur List renvoyée contiendra donc ces probabilités. Vous l'analyserez plus tard.

Maintenant que vous avez la classe d'assistance, revenez à votre MainActivity et mettez-la à jour pour l'utiliser afin de classer votre texte. Vous le verrez à l'étape suivante.

6. Classer le texte

Dans votre MainActivity, vous devez d'abord importer les assistants que vous venez de créer.

  1. En haut de MainActivity.kt, ajoutez le code suivant aux autres importations :
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
  1. Ensuite, vous devez charger les helpers. Dans onCreate, juste après la ligne setContentView, ajoutez les lignes suivantes pour instancier et charger la classe d'assistance :
val client = TextClassificationClient(applicationContext)
client.load()

Pour le moment, le onClickListener de votre bouton devrait se présenter comme suit :

btnSendText.setOnClickListener {
     var toSend:String = txtInput.text.toString()
     txtOutput.text = toSend
 }
  1. Modifiez-le pour qu'il ressemble à ceci :
btnSendText.setOnClickListener {
    var toSend:String = txtInput.text.toString()
    var results:List<Category> = client.classify(toSend)
    val score = results[1].score
    if(score>0.8){
        txtOutput.text = "Your message was detected as spam with a score of " + score.toString() + " and not sent!"
    } else {
        txtOutput.text = "Message sent! \nSpam score was:" + score.toString()
    }
    txtInput.text.clear()
}

Cela modifie la fonctionnalité, qui ne se contente plus de générer la saisie de l'utilisateur, mais la classe d'abord.

  1. Avec cette ligne, vous allez prendre la chaîne saisie par l'utilisateur et la transmettre au modèle pour obtenir des résultats :
var results:List<Category> = client.classify(toSend)

Il n'existe que deux catégories : False et True.

. (TensorFlow les trie par ordre alphabétique. "False" sera donc l'élément 0 et "True" l'élément 1.)

  1. Pour obtenir le score de probabilité que la valeur soit True, vous pouvez examiner results[1].score comme suit :
    val score = results[1].score
  1. Choisissez une valeur de seuil (0,8 dans ce cas). Si le score de la catégorie "True" est supérieur à la valeur de seuil (0,8), le message est considéré comme du spam. Sinon, il ne s'agit pas de spam et vous pouvez envoyer le message sans risque :
    if(score>0.8){
        txtOutput.text = "Your message was detected as spam with a score of " + score.toString() + " and not sent!"
    } else {
        txtOutput.text = "Message sent! \nSpam score was:" + score.toString()
    }
  1. Découvrez le modèle en action. Le message "Consultez mon blog pour acheter des produits !" a été signalé comme spam potentiel :

1fb0b5de9e566e.png

À l'inverse, la phrase "Salut, super tutoriel, merci !" a été jugée comme ayant une très faible probabilité d'être du spam :

73f38bdb488b29b3.png

7. Mettre à jour votre application iOS pour utiliser le modèle TensorFlow Lite

Pour obtenir le code nécessaire, suivez l'atelier de programmation 1 ou clonez ce dépôt et chargez l'application à partir de TextClassificationStep1. Vous le trouverez dans le chemin d'accès TextClassificationOnMobile->iOS.

Le code finalisé est également disponible pour vous sous la forme TextClassificationStep2.

Dans l'atelier de programmation "Créer un modèle de machine learning pour le spam dans les commentaires", vous avez créé une application très simple qui permettait à l'utilisateur de saisir un message dans un UITextView et de le transmettre à une sortie sans aucun filtrage.

Vous allez maintenant mettre à jour cette application pour qu'elle utilise un modèle TensorFlow Lite afin de détecter le spam dans le texte avant l'envoi. Dans cette application, simulez simplement l'envoi en affichant le texte dans un libellé de sortie (mais une application réelle peut avoir un tableau d'affichage, un chat ou quelque chose de similaire).

Pour commencer, vous aurez besoin de l'application de l'étape 1, que vous pouvez cloner à partir du dépôt.

Pour intégrer TensorFlow Lite, vous utiliserez CocoaPods. Si vous ne les avez pas encore installés, vous pouvez le faire en suivant les instructions sur https://cocoapods.org/.

  1. Une fois CocoaPods installé, créez un fichier nommé Podfile dans le même répertoire que le fichier .xcproject de l'application TextClassification. Le contenu de ce fichier doit se présenter comme suit :
target 'TextClassificationStep2' do
  use_frameworks!

  # Pods for NLPClassifier
    pod 'TensorFlowLiteSwift'

end

Le nom de votre application doit figurer sur la première ligne, au lieu de "TextClassificationStep2".

À l'aide du terminal, accédez à ce répertoire et exécutez pod install. Si l'opération réussit, un répertoire Pods et un fichier .xcworkspace sont créés. Vous l'utiliserez à l'avenir à la place de .xcproject.

Si l'opération a échoué, assurez-vous que le fichier Podfile se trouve dans le même répertoire que .xcproject. Le fichier Podfile dans le mauvais répertoire ou le mauvais nom de cible sont généralement les principaux responsables.

8. Ajouter les fichiers de modèle et de vocabulaire

Lorsque vous avez créé le modèle avec TensorFlow Lite Model Maker, vous avez pu générer le modèle (au format model.tflite) et le vocabulaire (au format vocab.txt).

  1. Pour les ajouter à votre projet, faites-les glisser du Finder vers la fenêtre de votre projet. Assurez-vous que l'option Ajouter aux cibles est cochée :

1ee9eaa00ee79859.png

Une fois que vous avez terminé, ils devraient s'afficher dans votre projet :

b63502b23911fd42.png

  1. Vérifiez qu'ils sont bien ajoutés au bundle (afin qu'ils soient déployés sur un appareil) en sélectionnant votre projet (dans la capture d'écran ci-dessus, il s'agit de l'icône bleue TextClassificationStep2) et en consultant l'onglet Build Phases (Phases de compilation) :

20b7cb603d49b457.png

9. Charger le vocabulaire

Lors de la classification du NLP, le modèle est entraîné avec des mots encodés en vecteurs. Le modèle encode les mots avec un ensemble spécifique de noms et de valeurs qui sont appris au fur et à mesure de l'entraînement du modèle. Notez que la plupart des modèles auront des vocabulaires différents. Il est important que vous utilisiez le vocabulaire de votre modèle qui a été généré au moment de l'entraînement. Il s'agit du fichier vocab.txt que vous venez d'ajouter à votre application.

Vous pouvez ouvrir le fichier dans Xcode pour afficher les encodages. Les mots tels que "song" sont encodés en 6 et "love" en 12. L'ordre est en fait fréquentiel. "I" était donc le mot le plus courant dans l'ensemble de données, suivi de "check".

Lorsque votre utilisateur saisit des mots, vous devez les encoder avec ce vocabulaire avant de les envoyer au modèle pour qu'ils soient classés.

Explorons ce code. Commencez par charger le vocabulaire.

  1. Définissez une variable au niveau de la classe pour stocker le dictionnaire :
var words_dictionary = [String : Int]()
  1. Créez ensuite un func dans la classe pour charger le vocabulaire dans ce dictionnaire :
func loadVocab(){
    // This func will take the file at vocab.txt and load it into a has table
    // called words_dictionary. This will be used to tokenize the words before passing them
    // to the model trained by TensorFlow Lite Model Maker
    if let filePath = Bundle.main.path(forResource: "vocab", ofType: "txt") {
        do {
            let dictionary_contents = try String(contentsOfFile: filePath)
            let lines = dictionary_contents.split(whereSeparator: \.isNewline)
            for line in lines{
                let tokens = line.components(separatedBy: " ")
                let key = String(tokens[0])
                let value = Int(tokens[1])
                words_dictionary[key] = value
            }
        } catch {
            print("Error vocab could not be loaded")
        }
    } else {
        print("Error -- vocab file not found")

    }
}
  1. Vous pouvez l'exécuter en l'appelant depuis viewDidLoad :
override func viewDidLoad() {
    super.viewDidLoad()
    txtInput.delegate = self
    loadVocab()
}

10. Transformer une chaîne en séquence de jetons

Vos utilisateurs saisiront des mots sous forme de phrase, qui deviendra une chaîne. Chaque mot de la phrase, s'il est présent dans le dictionnaire, sera encodé dans la valeur clé du mot telle que définie dans le vocabulaire.

Un modèle de PNL accepte généralement une longueur de séquence fixe. Il existe des exceptions pour les modèles créés à l'aide de ragged tensors, mais la plupart du temps, vous verrez qu'il est corrigé. Vous avez spécifié cette longueur lorsque vous avez créé votre modèle. Assurez-vous d'utiliser la même durée dans votre application iOS.

La valeur par défaut dans Colab pour TensorFlow Lite Model Maker que vous avez utilisé précédemment était de 20. Définissez-la ici aussi :

let SEQUENCE_LENGTH = 20

Ajoutez func, qui prendra la chaîne, la convertira en minuscules et supprimera toute ponctuation :

func convert_sentence(sentence: String) -> [Int32]{
// This func will split a sentence into individual words, while stripping punctuation
// If the word is present in the dictionary it's value from the dictionary will be added to
// the sequence. Otherwise we'll continue

// Initialize the sequence to be all 0s, and the length to be determined
// by the const SEQUENCE_LENGTH. This should be the same length as the
// sequences that the model was trained for
  var sequence = [Int32](repeating: 0, count: SEQUENCE_LENGTH)
  var words : [String] = []
  sentence.enumerateSubstrings(
    in: sentence.startIndex..<sentence.endIndex,options: .byWords) {
            (substring, _, _, _) -> () in words.append(substring!) }
  var thisWord = 0
  for word in words{
    if (thisWord>=SEQUENCE_LENGTH){
      break
    }
    let seekword = word.lowercased()
    if let val = words_dictionary[seekword]{
      sequence[thisWord]=Int32(val)
      thisWord = thisWord + 1
    }
  }
  return sequence
}

Notez que la séquence sera de type Int32. Ce choix est délibéré, car lorsqu'il s'agit de transmettre des valeurs à TensorFlow Lite, vous devez gérer la mémoire de bas niveau. TensorFlow Lite traite les entiers d'une séquence de chaînes comme des entiers de 32 bits. Cela vous facilitera (un peu) la vie lorsqu'il s'agira de transmettre des chaînes au modèle.

11. Effectuer la classification

Pour classer une phrase, il faut d'abord la convertir en une séquence de jetons en fonction des mots qu'elle contient. Cette étape a été effectuée à l'étape 9.

Vous allez maintenant prendre la phrase et la transmettre au modèle, faire en sorte que le modèle effectue une inférence sur la phrase et analyser les résultats.

Cela utilisera l'interpréteur TensorFlow Lite, que vous devrez importer :

import TensorFlowLite

Commencez par un func qui prend votre séquence, qui était un tableau de types Int32 :

func classify(sequence: [Int32]){
  // Model Path is the location of the model in the bundle
  let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
  var interpreter: Interpreter
  do{
    interpreter = try Interpreter(modelPath: modelPath!)
  } catch _{
    print("Error loading model!")
    return
  }

Le fichier de modèle sera chargé à partir du bundle et un interpréteur sera appelé avec celui-ci.

L'étape suivante consiste à copier la mémoire sous-jacente stockée dans la séquence dans un tampon appelé myData, afin qu'elle puisse être transmise à un Tensor. Lorsque vous avez implémenté le pod TensorFlow Lite, ainsi que l'interpréteur, vous avez eu accès à un type Tensor.

Commencez le code comme suit (toujours dans la classe func) :

let tSequence = Array(sequence)
let myData = Data(copyingBufferOf: tSequence.map { Int32($0) })
let outputTensor: Tensor

Ne vous inquiétez pas si une erreur s'affiche sur copyingBufferOf. Nous l'implémenterons ultérieurement en tant qu'extension.

Il est maintenant temps d'allouer des Tensors sur l'interpréteur, de copier le tampon de données que vous venez de créer dans le Tensor d'entrée, puis d'appeler l'interpréteur pour effectuer l'inférence :

do {
  // Allocate memory for the model's input `Tensor`s.
  try interpreter.allocateTensors()

  // Copy the data to the input `Tensor`.
  try interpreter.copy(myData, toInputAt: 0)

  // Run inference by invoking the `Interpreter`.
  try interpreter.invoke()

Une fois l'appel terminé, vous pouvez examiner la sortie de l'interpréteur pour voir les résultats.

Il s'agit de valeurs brutes (4 octets par neurone) que vous devrez ensuite lire et convertir. Comme ce modèle particulier comporte deux neurones de sortie, vous devez lire huit octets qui seront convertis en Float32 pour l'analyse. Vous travaillez avec une mémoire de bas niveau, d'où le unsafeData.

// Get the output `Tensor` to process the inference results.
outputTensor = try interpreter.output(at: 0)
// Turn the output tensor into an array. This will have 2 values
// Value at index 0 is the probability of negative sentiment
// Value at index 1 is the probability of positive sentiment
let resultsArray = outputTensor.data
let results: [Float32] = [Float32](unsafeData: resultsArray) ?? []

Il est désormais relativement facile d'analyser les données pour déterminer la qualité du spam. Le modèle comporte deux sorties : la première indique la probabilité que le message ne soit pas un spam, et la seconde, la probabilité qu'il le soit. Vous pouvez donc examiner results[1] pour trouver la valeur de spam :

let positiveSpamValue = results[1]
var outputString = ""
if(positiveSpamValue>0.8){
    outputString = "Message not sent. Spam detected with probability: " + String(positiveSpamValue)
} else {
    outputString = "Message sent!"
}
txtOutput.text = outputString

Pour plus de commodité, voici la méthode complète :

func classify(sequence: [Int32]){
  // Model Path is the location of the model in the bundle
  let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
  var interpreter: Interpreter
  do{
    interpreter = try Interpreter(modelPath: modelPath!)
    } catch _{
      print("Error loading model!")
      Return
  }
  
  let tSequence = Array(sequence)
  let myData = Data(copyingBufferOf: tSequence.map { Int32($0) })
  let outputTensor: Tensor
  do {
    // Allocate memory for the model's input `Tensor`s.
    try interpreter.allocateTensors()

    // Copy the data to the input `Tensor`.
    try interpreter.copy(myData, toInputAt: 0)

    // Run inference by invoking the `Interpreter`.
    try interpreter.invoke()

    // Get the output `Tensor` to process the inference results.
    outputTensor = try interpreter.output(at: 0)
    // Turn the output tensor into an array. This will have 2 values
    // Value at index 0 is the probability of negative sentiment
    // Value at index 1 is the probability of positive sentiment
    let resultsArray = outputTensor.data
    let results: [Float32] = [Float32](unsafeData: resultsArray) ?? []

    let positiveSpamValue = results[1]
    var outputString = ""
    if(positiveSpamValue>0.8){
      outputString = "Message not sent. Spam detected with probability: " + 
                      String(positiveSpamValue)
    } else {
      outputString = "Message sent!"
    }
    txtOutput.text = outputString

  } catch let error {
    print("Failed to invoke the interpreter with error: \(error.localizedDescription)")
  }
}

12. Ajouter les extensions Swift

Le code ci-dessus utilisait une extension du type de données pour vous permettre de copier les bits bruts d'un tableau Int32 dans un Data. Voici le code de cette extension :

extension Data {
  /// Creates a new buffer by copying the buffer pointer of the given array.
  ///
  /// - Warning: The given array's element type `T` must be trivial in that it can be copied bit
  ///     for bit with no indirection or reference-counting operations; otherwise, reinterpreting
  ///     data from the resulting buffer has undefined behavior.
  /// - Parameter array: An array with elements of type `T`.
  init<T>(copyingBufferOf array: [T]) {
    self = array.withUnsafeBufferPointer(Data.init)
  }
}

Lorsque vous manipulez de la mémoire de bas niveau, vous utilisez des données "non sécurisées". Le code ci-dessus vous demande d'initialiser un tableau de données non sécurisées. Cette extension vous permet de le faire :

extension Array {
  /// Creates a new array from the bytes of the given unsafe data.
  ///
  /// - Warning: The array's `Element` type must be trivial in that it can be copied bit for bit
  ///     with no indirection or reference-counting operations; otherwise, copying the raw bytes in
  ///     the `unsafeData`'s buffer to a new array returns an unsafe copy.
  /// - Note: Returns `nil` if `unsafeData.count` is not a multiple of
  ///     `MemoryLayout<Element>.stride`.
  /// - Parameter unsafeData: The data containing the bytes to turn into an array.
  init?(unsafeData: Data) {
    guard unsafeData.count % MemoryLayout<Element>.stride == 0 else { return nil }
    #if swift(>=5.0)
    self = unsafeData.withUnsafeBytes { .init($0.bindMemory(to: Element.self)) }
    #else
    self = unsafeData.withUnsafeBytes {
      .init(UnsafeBufferPointer<Element>(
        start: $0,
        count: unsafeData.count / MemoryLayout<Element>.stride
      ))
    }
    #endif  // swift(>=5.0)
  }
}

13. Exécuter l'application iOS

Exécutez et testez l'application.

Si tout s'est bien passé, l'application devrait s'afficher sur votre appareil comme suit :

74cbd28d9b1592ed.png

Lorsque le message "Achetez mon livre pour apprendre le trading en ligne !" a été envoyé, l'application a renvoyé une alerte de spam détecté avec une probabilité de 0,99 !

14. Félicitations !

Vous avez créé une application très simple qui filtre le texte pour détecter le spam dans les commentaires à l'aide d'un modèle entraîné sur des données utilisées pour le spam dans les blogs.

L'étape suivante du cycle de vie typique d'un développeur consiste à explorer les possibilités de personnalisation du modèle en fonction des données trouvées dans votre propre communauté. Vous verrez comment procéder dans la prochaine activité du parcours.