Mengupdate aplikasi untuk menggunakan model Machine Learning pemfilteran spam

1. Sebelum memulai

Dalam codelab ini, Anda akan mengupdate aplikasi yang Anda buat di codelab Memulai klasifikasi teks seluler sebelumnya.

Prasyarat

  • Codelab ini dirancang untuk developer yang baru mengenal machine learning.
  • Codelab adalah bagian dari jalur berurutan. Jika Anda belum menyelesaikan pembuatan aplikasi gaya pesan dasar atau Membuat model machine learning spam komentar, harap hentikan dan lakukan sekarang.

Yang akan Anda [buat atau pelajari]

  • Anda akan mempelajari cara mengintegrasikan model kustom ke dalam aplikasi, yang telah dibuat pada langkah sebelumnya.

Yang Anda butuhkan

2. Buka Aplikasi Android yang Ada

Anda bisa mendapatkan kode untuk cara ini dengan mengikuti Codelab 1, atau dengan membuat clone repositori ini dan memuat aplikasi dari TextClassificationStep1.

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

Anda dapat menemukannya di jalur TextClassificationOnMobile->Android.

Kode yang selesai juga tersedia untuk Anda sebagai TextClassificationStep2.

Setelah dibuka, Anda siap melanjutkan ke langkah 2.

3 Mengimpor File dan Metadata Model

Dalam codelab Membuat model machine learning spam komentar, Anda membuat model .TFLITE.

Anda seharusnya telah mendownload file model. Jika Anda tidak memilikinya, Anda bisa mendapatkannya dari repo untuk codelab ini, dan modelnya tersedia di sini.

Tambahkan ke project Anda dengan membuat direktori aset.

  1. Dengan menggunakan navigator project, pastikan Android dipilih di bagian atas.
  2. Klik kanan folder app. Pilih New > Directory.

d7c3e9f21035fc15.png

  1. Pada dialog Direktori Baru, pilih src/main/assets.

2137f956a1ba4ef0.png

Anda akan melihat folder assets baru kini tersedia di aplikasi.

ae858835e1a90445.png

  1. Klik kanan assets.
  2. Pada menu yang terbuka, Anda akan melihat (pada Mac) Reveal in Finder. Pilih. (Di Windows, akan tertulis Tampilkan di Explorer, di Ubuntu akan tertulis Tampilkan di File.)

e61aaa3b73c5ab68.png

Finder akan diluncurkan untuk menampilkan lokasi file (File Explorer di Windows, Files di Linux).

  1. Salin file labels.txt, model.tflite, dan vocab ke direktori ini.

14f382cc19552a56.png

  1. Kembali ke Android Studio, dan Anda akan melihatnya tersedia di folder assets Anda.

150ed2a1d2f7a10d.png

4. Mengupdate build.gradle untuk menggunakan TensorFlow Lite

Untuk menggunakan TensorFlow Lite, dan library tugas TensorFlow Lite yang mendukungnya, Anda harus memperbarui file build.gradle.

Project Android sering kali memiliki lebih dari satu project, jadi pastikan untuk menemukan aplikasi level satu. Di penjelajah project dalam tampilan Android, temukan di bagian Gradle Scripts. Yang benar akan diberi label .app seperti yang ditunjukkan di sini:

6426051e614bc42f.png

Anda harus membuat dua perubahan pada file ini. Yang pertama ada di bagian dependensi di bagian bawah. Tambahkan teks implementation untuk library tugas TensorFlow Lite, seperti ini:

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

Nomor versi mungkin telah berubah sejak ditulis, jadi pastikan Anda memeriksa https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier untuk mengetahui informasi terbaru.

Library tugas juga memerlukan versi SDK minimum 21. Temukan setelan ini di android > default config, dan ubah ke 21:

c100b68450b8812f.png

Sekarang Anda memiliki semua dependensi, jadi saatnya untuk memulai coding.

5. Menambahkan Class Helper

Untuk memisahkan logika inferensi, tempat aplikasi Anda menggunakan model, dari antarmuka pengguna, buat class lain untuk menangani inferensi model. Beri nama class ini "helper".

  1. Klik kanan nama paket tempat kode MainActivity Anda berada.
  2. Pilih New > Package.

d5911ded56b5df35.png

  1. Anda akan melihat dialog di bagian tengah layar yang meminta Anda untuk memasukkan nama paket. Tambahkan di akhir nama paket saat ini. (Di sini disebut helper.)

3b9f1f822f99b371.png

  1. Setelah selesai, klik kanan folder helpers di penjelajah project.
  2. Pilih New > Java Class, dan beri nama TextClassificationClient. Anda akan mengedit file di langkah berikutnya.

Class helper TextClassificationClient Anda akan terlihat seperti ini (meskipun nama paket Anda mungkin berbeda.)

package com.google.devrel.textclassificationstep1.helpers;

public class TextClassificationClient {
}
  1. Perbarui file dengan kode ini:
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;
    }

}

Class ini akan memberikan wrapper ke penafsir TensorFlow Lite, yang memuat model dan memisahkan kompleksitas pengelolaan pertukaran data antara aplikasi Anda dan model.

Dalam metode load(), instance NLClassifier jenis baru akan dibuat dari jalur model. Jalur model hanyalah nama model, model.tflite. Jenis NLClassifier adalah bagian dari library tugas teks, dan membantu Anda dengan mengonversi string menjadi token, menggunakan panjang urutan yang benar, meneruskannya ke model, dan menguraikan hasilnya.

(Untuk mengetahui detail selengkapnya, kunjungi kembali Membuat model machine learning spam komentar.)

Klasifikasi dilakukan dalam metode klasifikasi, tempat Anda meneruskan string kepadanya dan akan menampilkan List. Saat menggunakan model Machine Learning untuk mengklasifikasikan konten tempat Anda ingin menentukan apakah string merupakan spam atau bukan, biasanya semua jawaban akan ditampilkan, dengan probabilitas yang ditetapkan. Misalnya, jika Anda meneruskan pesan yang tampak seperti spam, Anda akan mendapatkan daftar berisi 2 jawaban; satu dengan probabilitas bahwa itu adalah spam, dan satu dengan probabilitas bahwa bukan spam. Spam/Bukan Spam adalah kategori, jadi List yang ditampilkan akan berisi kemungkinan ini. Anda akan menguraikannya nanti.

Setelah Anda memiliki class helper, kembali ke MainActivity dan update untuk menggunakannya guna mengklasifikasikan teks Anda. Anda akan melihatnya di langkah berikutnya.

6. Mengklasifikasi Teks

Di MainActivity, Anda harus mengimpor helper yang baru saja dibuat!

  1. Di bagian atas MainActivity.kt, bersama dengan impor lainnya, tambahkan:
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
  1. Berikutnya, Anda perlu memuat helper. Di onCreate, segera setelah baris setContentView, tambahkan baris ini untuk membuat instance dan memuat class bantuan:
val client = TextClassificationClient(applicationContext)
client.load()

Untuk saat ini, onClickListener tombol Anda akan terlihat seperti ini:

btnSendText.setOnClickListener {
     var toSend:String = txtInput.text.toString()
     txtOutput.text = toSend
 }
  1. Perbarui agar terlihat seperti ini:
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()
}

Fungsi ini mengubah fungsi, dari hanya menghasilkan input pengguna, hingga mengklasifikasikan terlebih dahulu.

  1. Dengan baris ini, Anda akan mengambil string yang dimasukkan pengguna dan meneruskannya ke model, mendapatkan kembali hasil:
var results:List<Category> = client.classify(toSend)

Hanya ada 2 kategori, False dan True

. (TensorFlow mengurutkannya berdasarkan abjad, sehingga False akan menjadi item 0, dan True akan menjadi item 1.)

  1. Untuk mendapatkan skor probabilitas bahwa nilainya adalah True, Anda dapat melihat hasil[1].score seperti ini:
    val score = results[1].score
  1. Memilih nilai ambang batas (dalam hal ini 0,8), yang menyatakan bahwa jika skor untuk kategori Benar di atas nilai ambang (0,8), maka pesannya adalah spam. Jika tidak, email tersebut bukan spam dan pesan tersebut aman untuk dikirim:
    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. Lihat cara kerja model di sini. Pesan "Kunjungi blog saya untuk membeli barang!" ditandai sebagai kemungkinan spam yang tinggi:

1fb0b5de9e566e.png

Sebaliknya, "Ok tutorial yang menyenangkan, terima kasih!" memiliki kemungkinan sangat rendah untuk menjadi spam:

73f38bdb488b29b3.png

7. Mengupdate Aplikasi iOS untuk menggunakan Model TensorFlow Lite

Anda bisa mendapatkan kode untuk cara ini dengan mengikuti Codelab 1, atau dengan membuat clone repositori ini dan memuat aplikasi dari TextClassificationStep1. Anda dapat menemukannya di jalur TextClassificationOnMobile->iOS.

Kode yang selesai juga tersedia untuk Anda sebagai TextClassificationStep2.

Dalam codelab Model machine learning membuat komentar komentar, Anda telah membuat aplikasi sangat sederhana yang memungkinkan pengguna mengetik pesan ke dalam UITextView dan meneruskannya ke output tanpa pemfilteran apa pun.

Sekarang Anda akan mengupdate aplikasi tersebut untuk menggunakan model TensorFlow Lite guna mendeteksi spam komentar dalam teks sebelum mengirim. Cukup simulasikan pengiriman dalam aplikasi ini dengan merender teks dalam label output (tetapi aplikasi sebenarnya mungkin memiliki papan buletin, chat, atau sejenisnya).

Untuk memulai, Anda memerlukan aplikasi dari langkah 1, yang dapat Anda clone dari repo.

Untuk menggabungkan TensorFlow Lite, Anda perlu menggunakan CocoaPods. Jika belum menginstalnya, Anda dapat melakukannya dengan petunjuk di https://cocoapods.org/.

  1. Setelah Anda menginstal CocoaPods, buat file dengan nama Podfile dalam direktori yang sama seperti .xcproject untuk aplikasi TextClassification. Isi file akan terlihat seperti ini:
target 'TextClassificationStep2' do
  use_frameworks!

  # Pods for NLPClassifier
    pod 'TensorFlowLiteSwift'

end

Nama aplikasi Anda harus berada di baris pertama, bukan "TextClassificationStep2".

Dengan menggunakan Terminal, buka direktori tersebut dan jalankan pod install. Jika berhasil, Anda akan memiliki direktori baru bernama Pods dan file .xcworkspace baru yang akan dibuat untuk Anda. Anda akan menggunakannya pada masa mendatang, bukan .xcproject.

Jika gagal, pastikan Anda memiliki Podfile di direktori yang sama dengan .xcproject sebelumnya. Podfile dalam direktori yang salah, atau nama target yang salah, biasanya menjadi penyebab utama.

8 Menambahkan File Model dan Vocab

Saat membuat model dengan pembuat Model TensorFlow Lite, Anda dapat menghasilkan model (sebagai model.tflite) dan vocab (sebagai vocab.txt).

  1. Tambahkan mereka ke project Anda dengan menarik lalu melepasnya dari Finder ke jendela project. Pastikan tambahkan ke target dicentang:

1ee9eaa00ee79859.png

Setelah selesai, Anda akan melihatnya di project Anda:

b63502b23911fd42.png

  1. Periksa kembali apakah paket telah ditambahkan ke paket (agar dapat diterapkan ke perangkat) dengan memilih project Anda (pada screenshot di atas, terdapat ikon biru TextClassificationStep2), dan melihat Build Phases:

20b7cb603d49b457.png

9. Muat Kosakata

Saat melakukan klasifikasi NLP, model dilatih dengan kata-kata yang dienkode menjadi vektor. Model mengenkode kata dengan serangkaian nama dan nilai tertentu yang dipelajari saat model dilatih. Perlu diketahui bahwa sebagian besar model akan memiliki kosakata yang berbeda, dan penting bagi Anda untuk menggunakan kosakata untuk model yang dihasilkan pada saat pelatihan. Ini adalah file vocab.txt yang baru saja Anda tambahkan ke aplikasi.

Anda dapat membuka file di Xcode untuk melihat encoding. Kata seperti "lagu" dienkode ke 6 dan "cinta" menjadi 12. Urutan sebenarnya adalah urutan frekuensi, jadi "I" adalah kata yang paling umum dalam set data, diikuti oleh "check".

Saat pengguna mengetik kata, Anda dapat mengenkodenya dengan kosakata ini sebelum mengirimkannya ke model untuk diklasifikasikan.

Mari jelajahi kode tersebut. Mulai dengan memuat kosakata.

  1. Tentukan variabel tingkat class untuk menyimpan kamus:
var words_dictionary = [String : Int]()
  1. Kemudian buat func di class untuk memuat vocab ke dalam kamus ini:
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. Anda dapat menjalankannya dengan memanggilnya dari dalam viewDidLoad:
override func viewDidLoad() {
    super.viewDidLoad()
    txtInput.delegate = self
    loadVocab()
}

10. Ubah string menjadi urutan token

Pengguna akan mengetik kata sebagai kalimat yang akan menjadi string. Setiap kata dalam kalimat, jika ada dalam kamus, akan dienkode ke nilai kunci untuk kata tersebut seperti yang ditetapkan dalam kosakata.

Model NLP biasanya menerima panjang urutan tetap. Ada pengecualian dengan model yang dibuat menggunakan ragged tensors, tetapi sebagian besar akan terlihat bahwa masalah tersebut telah diperbaiki. Saat membuat model, Anda menentukan panjang ini. Pastikan Anda menggunakan durasi yang sama di aplikasi iOS Anda.

Setelan default di Colab untuk TensorFlow Lite Model Maker yang Anda gunakan sebelumnya adalah 20, jadi siapkan juga di sini:

let SEQUENCE_LENGTH = 20

Tambahkan func yang akan mengambil string, mengonversinya menjadi huruf kecil, dan menghapus tanda baca:

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
}

Perhatikan bahwa urutannya adalah Int32. Ini sengaja dipilih karena dalam hal meneruskan nilai ke TensorFlow Lite, Anda akan berurusan dengan memori tingkat rendah, dan TensorFlow Lite memperlakukan bilangan bulat dalam urutan string sebagai bilangan bulat 32-bit. Ini akan membuat hidup Anda (sedikit) lebih mudah dalam hal meneruskan string ke model.

11. Melakukan Klasifikasi

Untuk mengklasifikasikan kalimat, kalimat tersebut harus dikonversi terlebih dahulu menjadi urutan token berdasarkan kata-kata dalam kalimat tersebut. Ini akan dilakukan di langkah 9.

Anda sekarang akan mengambil kalimat dan meneruskannya ke model, meminta model melakukan inferensi pada kalimat, dan menguraikan hasilnya.

Tindakan ini akan menggunakan penafsir TensorFlow Lite, yang harus Anda impor:

import TensorFlowLite

Mulai dengan func yang menggunakan urutan Anda, yang merupakan array jenis 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
  }

Tindakan ini akan memuat file model dari paket, dan memanggil penafsir dengan file tersebut.

Langkah berikutnya adalah menyalin memori yang mendasari yang disimpan dalam urutan ke dalam buffer yang disebut myData, sehingga dapat diteruskan ke tensor. Saat menerapkan pod TensorFlow Lite, serta penafsir, Anda mendapatkan akses ke Tensor Type.

Mulai kode seperti ini (masih dalam mengklasifikasikan func.):

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

Jangan khawatir jika terjadi error pada copyingBufferOf. Ini akan diimplementasikan sebagai ekstensi di lain waktu.

Sekarang saatnya mengalokasikan tensor pada penafsir, menyalin buffer data yang baru saja Anda buat ke tensor input, kemudian memanggil penafsir untuk melakukan inferensi:

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

Setelah pemanggilan selesai, Anda dapat melihat output penafsir untuk melihat hasilnya.

Ini akan menjadi nilai mentah (4 byte per neuron) yang kemudian harus Anda baca dan konversikan. Karena model tertentu ini memiliki 2 neuron output, Anda harus membaca dalam 8 byte yang akan dikonversi menjadi Float32 untuk penguraian. Anda berurusan dengan memori tingkat rendah, karenanya 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) ?? []

Mengurai data untuk menentukan kualitas spam relatif mudah. Model ini memiliki 2 output, yakni yang pertama dengan kemungkinan bahwa pesan tersebut bukan spam, yang kedua dengan probabilitas bahwa pesan tersebut bukan spam. Jadi, Anda dapat melihat results[1] untuk menemukan nilai 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

Untuk memudahkan, berikut metode lengkapnya:

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. Menambahkan Ekstensi Swift

Kode di atas menggunakan ekstensi ke Jenis data untuk memungkinkan Anda menyalin bit mentah array Int32 ke dalam Data. Berikut kode untuk ekstensi tersebut:

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

Saat menangani memori tingkat rendah, Anda menggunakan data "tidak aman", dan kode di atas mengharuskan Anda melakukan inisialisasi array data yang tidak aman. Ekstensi ini memungkinkan:

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. Menjalankan Aplikasi iOS

Jalankan dan uji aplikasi.

Jika semua berjalan lancar, Anda akan melihat aplikasi di perangkat seperti ini:

74cbd28d9b1592ed.png

Di mana pesan "Beli buku saya untuk belajar perdagangan online!" telah dikirim, aplikasi mengirimkan kembali peringatan yang terdeteksi spam dengan probabilitas 0,99%.

14. Selamat!

Sekarang Anda telah membuat aplikasi yang sangat sederhana yang memfilter teks untuk spam komentar menggunakan model yang dilatih pada data yang digunakan untuk mengirim spam ke blog.

Langkah berikutnya dalam siklus proses developer biasanya adalah mengeksplorasi apa yang diperlukan untuk menyesuaikan model berdasarkan data yang ditemukan di komunitas Anda. Anda akan melihat cara melakukannya di aktivitas jalur berikutnya.