Anwendung zur Verwendung eines Spamfiltermodells für maschinelles Lernen aktualisieren

1. Hinweis

In diesem Codelab aktualisieren Sie die App, die Sie in den vorherigen Codelabs zum Thema „Erste Schritte mit der mobilen Textklassifizierung“ erstellt haben.

Vorbereitung

  • Dieses Codelab richtet sich an erfahrene Entwickler, die neu im Bereich Machine Learning sind.
  • Dieses Codelab ist Teil eines sequenziellen Lernpfads. Wenn Sie „Einfache Messaging-App erstellen“ oder „Machine-Learning-Modell für Kommentarspam erstellen“ noch nicht abgeschlossen haben, sollten Sie dies jetzt tun.

[Erstellen oder lernen]

  • Sie erfahren, wie Sie Ihr benutzerdefiniertes Modell in Ihre App einbinden, die Sie in den vorherigen Schritten erstellt haben.

Voraussetzungen

2. Vorhandene Android-App öffnen

Den Code dafür finden Sie in Codelab 1 oder indem Sie dieses Repository klonen und die App aus TextClassificationStep1 laden.

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

Sie finden sie unter TextClassificationOnMobile->Android.

Der fertige Code ist auch als TextClassificationStep2 verfügbar.

Wenn sie sich geöffnet hat, kannst du mit Schritt 2 fortfahren.

3. Modelldatei und Metadaten importieren

Im Codelab „Modell für maschinelles Lernen zum Erkennen von Kommentarspam erstellen“ haben Sie ein .TFLITE-Modell erstellt.

Sie sollten die Modelldatei heruntergeladen haben. Falls Sie es noch nicht haben, können Sie es aus dem Repository für dieses Codelab herunterladen. Das Modell ist hier verfügbar.

Fügen Sie es Ihrem Projekt hinzu, indem Sie ein Assets-Verzeichnis erstellen.

  1. Achten Sie darauf, dass oben in der Projektnavigation Android ausgewählt ist.
  2. Klicken Sie mit der rechten Maustaste auf den Ordner App. Wählen Sie Neu > Verzeichnis aus.

d7c3e9f21035fc15.png

  1. Wählen Sie im Dialogfeld Neues Verzeichnis die Option src/main/assets aus.

2137f956a1ba4ef0.png

In der App ist jetzt ein neuer Ordner assets verfügbar.

ae858835e1a90445.png

  1. Klicken Sie mit der rechten Maustaste auf Assets.
  2. Im Menü, das sich öffnet, sehen Sie (auf dem Mac) Im Finder anzeigen. Wählen Sie sie aus. Unter Windows wird Im Explorer anzeigen und unter Ubuntu In Dateien anzeigen angezeigt.

e61aaa3b73c5ab68.png

Der Finder wird geöffnet und zeigt den Speicherort der Dateien an (Datei-Explorer unter Windows, Dateien unter Linux).

  1. Kopieren Sie die Dateien labels.txt, model.tflite und vocab in dieses Verzeichnis.

14f382cc19552a56.png

  1. Kehren Sie zu Android Studio zurück. Die Assets sind jetzt im Ordner assets verfügbar.

150ed2a1d2f7a10d.png

4. build.gradle zur Verwendung von TensorFlow Lite aktualisieren

Wenn Sie TensorFlow Lite und die zugehörigen TensorFlow Lite-Taskbibliotheken verwenden möchten, müssen Sie Ihre build.gradle-Datei aktualisieren.

Android-Projekte haben oft mehrere. Achten Sie darauf, dass Sie die App-Ebene finden. Suchen Sie im Projekt-Explorer in der Android-Ansicht im Abschnitt Gradle Scripts (Gradle-Skripts) danach. Die richtige Datei ist mit .app gekennzeichnet, wie hier zu sehen:

6426051e614bc42f.png

Sie müssen zwei Änderungen an dieser Datei vornehmen. Die erste befindet sich unten im Abschnitt dependencies. Fügen Sie einen Text-implementation für die TensorFlow Lite-Task-Bibliothek hinzu, z. B. so:

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

Die Versionsnummer hat sich seit dem Schreiben dieses Dokuments möglicherweise geändert. Die aktuelle Version finden Sie unter https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier.

Für die Aufgabenbibliotheken ist außerdem mindestens SDK-Version 21 erforderlich. Sie finden diese Einstellung unter android > default config. Ändern Sie sie in „21“:

c100b68450b8812f.png

Jetzt haben Sie alle Abhängigkeiten und können mit dem Programmieren beginnen.

5. Hilfsklasse hinzufügen

Um die Inferenzlogik, in der Ihre App das Modell verwendet, von der Benutzeroberfläche zu trennen, erstellen Sie eine weitere Klasse für die Modellinferenz. Nennen Sie diese Klasse „helper“.

  1. Klicken Sie mit der rechten Maustaste auf den Paketnamen, in dem sich Ihr MainActivity-Code befindet.
  2. Wählen Sie Neu > Paket aus.

d5911ded56b5df35.png

  1. In der Mitte des Bildschirms wird ein Dialogfeld angezeigt, in dem Sie den Paketnamen eingeben müssen. Fügen Sie ihn am Ende des aktuellen Paketnamens hinzu. (Hier werden sie als Helfer bezeichnet.)

3b9f1f822f99b371.png

  1. Klicken Sie dann im Projektexplorer mit der rechten Maustaste auf den Ordner helpers.
  2. Wählen Sie Neu > Java-Klasse aus und nennen Sie sie TextClassificationClient. Sie bearbeiten die Datei im nächsten Schritt.

Ihre TextClassificationClient-Helferklasse sieht so aus (Ihr Paketname kann jedoch abweichen):

package com.google.devrel.textclassificationstep1.helpers;

public class TextClassificationClient {
}
  1. Aktualisieren Sie die Datei mit diesem Code:
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;
    }

}

Diese Klasse stellt einen Wrapper für den TensorFlow Lite-Interpreter bereit, lädt das Modell und abstrahiert die Komplexität der Verwaltung des Datenaustauschs zwischen Ihrer App und dem Modell.

In der Methode load() wird ein neuer NLClassifier-Typ aus dem Modellpfad instanziiert. Der Modellpfad ist einfach der Name des Modells: model.tflite. Der Typ NLClassifier ist Teil der Bibliotheken für Textaufgaben. Er unterstützt Sie, indem er Ihren String in Tokens umwandelt, die richtige Sequenzlänge verwendet, den String an das Modell übergibt und die Ergebnisse parst.

Weitere Informationen dazu finden Sie unter „Modell für maschinelles Lernen zum Erkennen von Kommentar-Spam erstellen“.

Die Klassifizierung erfolgt in der Methode „classify“. Sie übergeben ihr einen String und sie gibt ein List zurück. Wenn Sie Machine-Learning-Modelle verwenden, um Inhalte zu klassifizieren und festzustellen, ob ein String Spam ist oder nicht, werden in der Regel alle Antworten mit zugewiesenen Wahrscheinlichkeiten zurückgegeben. Wenn Sie beispielsweise eine Nachricht übergeben, die wie Spam aussieht, erhalten Sie eine Liste mit zwei Antworten: eine mit der Wahrscheinlichkeit, dass es sich um Spam handelt, und eine mit der Wahrscheinlichkeit, dass es sich nicht um Spam handelt. „Spam“ und „Kein Spam“ sind Kategorien. Die zurückgegebenen List enthalten daher diese Wahrscheinlichkeiten. Sie werden das später analysieren.

Nachdem Sie die Hilfsklasse erstellt haben, kehren Sie zu MainActivity zurück und aktualisieren Sie sie, damit sie zum Klassifizieren Ihres Texts verwendet wird. Das sehen Sie im nächsten Schritt.

6. Text klassifizieren

Importieren Sie zuerst die gerade erstellten Helfer in MainActivity.

  1. Fügen Sie oben in MainActivity.kt zusammen mit den anderen Importen Folgendes hinzu:
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
  1. Als Nächstes müssen Sie die Helfer laden. Fügen Sie in onCreate direkt nach der Zeile setContentView die folgenden Zeilen hinzu, um die Hilfsklasse zu instanziieren und zu laden:
val client = TextClassificationClient(applicationContext)
client.load()

Derzeit sollte der onClickListener Ihres Buttons so aussehen:

btnSendText.setOnClickListener {
     var toSend:String = txtInput.text.toString()
     txtOutput.text = toSend
 }
  1. Aktualisieren Sie sie so:
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()
}

Dadurch ändert sich die Funktionalität von der reinen Ausgabe der Nutzereingabe zur vorherigen Klassifizierung.

  1. Mit dieser Zeile übergeben Sie den vom Nutzer eingegebenen String an das Modell und erhalten Ergebnisse zurück:
var results:List<Category> = client.classify(toSend)

Es gibt nur zwei Kategorien: False und True.

. (TensorFlow sortiert sie alphabetisch. „False“ ist also Element 0 und „True“ ist Element 1.)

  1. Um die Bewertung für die Wahrscheinlichkeit zu erhalten, dass der Wert True ist, können Sie sich results[1].score so ansehen:
    val score = results[1].score
  1. Sie haben einen Schwellenwert (in diesem Fall 0,8) festgelegt. Wenn der Wert für die Kategorie „Wahr“ über dem Schwellenwert (0,8) liegt, wird die Nachricht als Spam eingestuft. Andernfalls handelt es sich nicht um Spam und die Nachricht kann sicher gesendet werden:
    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. Hier können Sie sich das Modell in Aktion ansehen. Die Nachricht „Besuchen Sie meinen Blog, um etwas zu kaufen!“ wurde als sehr wahrscheinlich Spam eingestuft:

1fb0b5de9e566e.png

Umgekehrt wurde bei „Hey, fun tutorial, thanks!“ (Hey, tolles Tutorial, danke!) eine sehr geringe Wahrscheinlichkeit für Spam festgestellt:

73f38bdb488b29b3.png

7. iOS-App für die Verwendung des TensorFlow Lite-Modells aktualisieren

Den Code dafür finden Sie in Codelab 1 oder indem Sie dieses Repository klonen und die App aus TextClassificationStep1 laden. Sie finden sie unter TextClassificationOnMobile->iOS.

Der fertige Code ist auch als TextClassificationStep2 verfügbar.

Im Codelab „Machine-Learning-Modell für Kommentar-Spam erstellen“ haben Sie eine sehr einfache App erstellt, in der der Nutzer eine Nachricht in ein UITextView eingeben und ohne Filterung an eine Ausgabe weiterleiten lassen konnte.

Nun aktualisieren Sie die App, damit ein TensorFlow Lite-Modell verwendet wird, um Kommentar-Spam im Text zu erkennen, bevor er gesendet wird. Simulieren Sie das Senden in dieser App, indem Sie den Text in einem Ausgabelabel rendern. Eine echte App hätte jedoch möglicherweise ein Bulletin Board, einen Chat oder Ähnliches.

Für den Einstieg benötigen Sie die App aus Schritt 1, die Sie aus dem Repository klonen können.

Um TensorFlow Lite einzubinden, verwenden Sie CocoaPods. Falls Sie diese noch nicht installiert haben, können Sie dies anhand der Anleitung unter https://cocoapods.org/ tun.

  1. Nachdem Sie CocoaPods installiert haben, erstellen Sie eine Datei mit dem Namen Podfile im selben Verzeichnis wie die .xcproject für die TextClassification-App. Der Inhalt dieser Datei sollte so aussehen:
target 'TextClassificationStep2' do
  use_frameworks!

  # Pods for NLPClassifier
    pod 'TensorFlowLiteSwift'

end

Der Name Ihrer App sollte in der ersten Zeile stehen, nicht „TextClassificationStep2“.

Wechseln Sie im Terminal zu diesem Verzeichnis und führen Sie pod install aus. Wenn der Vorgang erfolgreich ist, wird ein neues Verzeichnis mit dem Namen Pods und eine neue .xcworkspace-Datei erstellt. Sie verwenden es in Zukunft anstelle von .xcproject.

Wenn der Vorgang fehlgeschlagen ist, prüfen Sie, ob sich die Podfile im selben Verzeichnis wie .xcproject befindet. In der Regel liegt es daran, dass sich die Podfile im falschen Verzeichnis befindet oder der falsche Zielname verwendet wird.

8. Modell- und Vokabeldateien hinzufügen

Als Sie das Modell mit TensorFlow Lite Model Maker erstellt haben, konnten Sie das Modell (als model.tflite) und den Wortschatz (als vocab.txt) ausgeben.

  1. Fügen Sie sie Ihrem Projekt hinzu, indem Sie sie aus dem Finder in Ihr Projektfenster ziehen. Achten Sie darauf, dass Zu Zielen hinzufügen angeklickt ist:

1ee9eaa00ee79859.png

Wenn Sie fertig sind, sollten Sie sie in Ihrem Projekt sehen:

b63502b23911fd42.png

  1. Prüfen Sie noch einmal, ob sie dem Bundle hinzugefügt wurden (damit sie auf einem Gerät bereitgestellt werden). Wählen Sie dazu Ihr Projekt aus (im Screenshot oben das blaue Symbol TextClassificationStep2) und sehen Sie sich den Tab Build Phases an:

20b7cb603d49b457.png

9. Vokabular laden

Bei der NLP-Klassifizierung wird das Modell mit Wörtern trainiert, die in Vektoren codiert sind. Das Modell codiert Wörter mit einer bestimmten Gruppe von Namen und Werten, die während des Trainings des Modells gelernt werden. Die meisten Modelle haben unterschiedliche Vokabulare. Es ist wichtig, dass Sie das Vokabular für Ihr Modell verwenden, das zum Zeitpunkt des Trainings generiert wurde. Dies ist die Datei vocab.txt, die Sie Ihrer App gerade hinzugefügt haben.

Sie können die Datei in Xcode öffnen, um die Codierungen zu sehen. Wörter wie „song“ werden mit 6 und „love“ mit 12 codiert. Die Reihenfolge ist tatsächlich die Häufigkeitsreihenfolge. „I“ war also das häufigste Wort im Datensatz, gefolgt von „check“.

Wenn Ihr Nutzer Wörter eingibt, müssen Sie sie mit diesem Vokabular codieren, bevor Sie sie zur Klassifizierung an das Modell senden.

Sehen wir uns diesen Code an. Laden Sie zuerst das Vokabular.

  1. Definieren Sie eine Variable auf Klassenebene, um das Dictionary zu speichern:
var words_dictionary = [String : Int]()
  1. Erstellen Sie dann eine func in der Klasse, um das Vokabular in dieses Dictionary zu laden:
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. Sie können sie aus viewDidLoad heraus aufrufen:
override func viewDidLoad() {
    super.viewDidLoad()
    txtInput.delegate = self
    loadVocab()
}

10. Einen String in eine Folge von Tokens umwandeln

Ihre Nutzer geben Wörter als Satz ein, der zu einem String wird. Jedes Wort im Satz, sofern es im Wörterbuch vorhanden ist, wird in den Schlüsselwert für das Wort codiert, wie im Vokabular definiert.

Ein NLP-Modell akzeptiert in der Regel eine feste Sequenzlänge. Es gibt Ausnahmen bei Modellen, die mit ragged tensors erstellt wurden, aber in den meisten Fällen ist das Problem behoben. Sie haben diese Länge beim Erstellen des Modells angegeben. Achten Sie darauf, dass Sie in Ihrer iOS-App dieselbe Länge verwenden.

Der Standardwert im Colab für TensorFlow Lite Model Maker, das Sie zuvor verwendet haben, war 20. Legen Sie ihn also auch hier fest:

let SEQUENCE_LENGTH = 20

Fügen Sie diesen func hinzu, um den String in Kleinbuchstaben zu konvertieren und alle Satzzeichen zu entfernen:

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
}

Die Sequenz besteht aus Int32-Werten. Das ist bewusst so gewählt, da Sie beim Übergeben von Werten an TensorFlow Lite mit Low-Level-Speicher arbeiten und TensorFlow Lite die Ganzzahlen in einer Stringsequenz als 32-Bit-Ganzzahlen behandelt. Das macht es etwas einfacher, Strings an das Modell zu übergeben.

11. Klassifizierung vornehmen

Um einen Satz zu klassifizieren, muss er zuerst in eine Folge von Tokens umgewandelt werden, die auf den Wörtern im Satz basieren. Das haben Sie in Schritt 9 bereits erledigt.

Sie übergeben den Satz nun an das Modell, lassen das Modell eine Inferenz für den Satz durchführen und parsen die Ergebnisse.

Dazu wird der TensorFlow Lite-Interpreter verwendet, den Sie importieren müssen:

import TensorFlowLite

Beginnen Sie mit einem func, das Ihre Sequenz entgegennimmt. Das war ein Array vom Typ „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
  }

Dadurch wird die Modelldatei aus dem Bundle geladen und ein Interpreter damit aufgerufen.

Im nächsten Schritt wird der zugrunde liegende Speicher, der in der Sequenz gespeichert ist, in einen Puffer namens myData, kopiert, damit er an einen Tensor übergeben werden kann. Bei der Implementierung des TensorFlow Lite-Pods sowie des Interpreters haben Sie Zugriff auf einen Tensortyp erhalten.

So starten Sie den Code (immer noch in der Funktion „classify“ func):

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

Wenn Sie auf copyingBufferOf eine Fehlermeldung erhalten, ist das kein Grund zur Sorge. Dies wird später als Erweiterung implementiert.

Jetzt ist es an der Zeit, Tensoren für den Interpreter zuzuweisen, den gerade erstellten Datenpuffer in den Eingabetensor zu kopieren und dann den Interpreter aufzurufen, um die Inferenz durchzuführen:

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()

Nach Abschluss des Aufrufs können Sie sich die Ausgabe des Interpreters ansehen, um die Ergebnisse zu sehen.

Das sind Rohwerte (4 Bytes pro Neuron), die Sie dann einlesen und konvertieren müssen. Da dieses spezielle Modell zwei Ausgabeneuronen hat, müssen Sie acht Byte einlesen, die zum Parsen in Float32-Werte konvertiert werden. Es geht um Speicher auf niedriger Ebene, daher das 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) ?? []

Jetzt ist es relativ einfach, die Daten zu analysieren, um die Spam-Qualität zu bestimmen. Das Modell hat zwei Ausgaben: die erste mit der Wahrscheinlichkeit, dass die Nachricht kein Spam ist, die zweite mit der Wahrscheinlichkeit, dass sie Spam ist. Sie können also results[1] aufrufen, um den Spam-Wert zu ermitteln:

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

Hier ist die vollständige Methode:

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. Swift-Erweiterungen hinzufügen

Im obigen Code wurde eine Erweiterung des Datentyps verwendet, damit Sie die Rohbits eines Int32-Arrays in ein Data kopieren können. Hier ist der Code für diese Erweiterung:

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)
  }
}

Wenn Sie mit Speicher auf niedriger Ebene arbeiten, verwenden Sie „unsichere“ Daten. Für den oben genannten Code müssen Sie ein Array mit unsicheren Daten initialisieren. Diese Erweiterung macht Folgendes möglich:

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. iOS-App ausführen

App ausführen und testen

Wenn alles geklappt hat, sollte die App auf Ihrem Gerät so aussehen:

74cbd28d9b1592ed.png

Wenn die Nachricht „Buy my book to learn online trading!“ (Kaufen Sie mein Buch, um Onlinehandel zu lernen!) gesendet wird, gibt die App eine Spam-Warnung mit einer Wahrscheinlichkeit von 99 % zurück.

14. Glückwunsch!

Sie haben jetzt eine sehr einfache App erstellt, die Text mithilfe eines Modells, das mit Daten zum Spamming von Blogs trainiert wurde, nach Kommentarspam filtern kann.

Der nächste Schritt im typischen Entwicklerlebenszyklus besteht dann darin, zu untersuchen, wie das Modell auf Grundlage von Daten aus Ihrer eigenen Community angepasst werden kann. Wie das geht, erfahren Sie in der nächsten Pathway-Aktivität.