Cập nhật ứng dụng của bạn để sử dụng mô hình Học máy lọc thư rác

1. Trước khi bắt đầu

Trong lớp học lập trình này, bạn sẽ cập nhật ứng dụng mà bạn đã tạo trong các lớp học lập trình Làm quen với phân loại văn bản trên thiết bị di động trước đây.

Điều kiện tiên quyết

  • Lớp học lập trình này dành cho các nhà phát triển có kinh nghiệm, mới làm quen với công nghệ học máy.
  • Lớp học lập trình này nằm trong một lộ trình theo trình tự. Nếu bạn chưa hoàn tất việc Xây dựng ứng dụng kiểu nhắn tin cơ bản hoặc Xây dựng mô hình học máy về bình luận rác, vui lòng dừng lại và thực hiện ngay.

Nội dung bạn sẽ [xây dựng hoặc học hỏi]

  • Bạn sẽ tìm hiểu cách tích hợp mô hình tuỳ chỉnh vào ứng dụng, được xây dựng trong các bước trước.

Bạn cần có

  • Android Studio hoặc CocoaPods dành cho iOS

2. Mở Ứng dụng Android hiện có

Bạn có thể lấy mã cho hoạt động này bằng cách làm theo Lớp học lập trình 1 hoặc bằng cách sao chép kho lưu trữ này rồi tải ứng dụng từ TextClassificationStep1.

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

Bạn có thể tìm thấy mã này trong đường dẫn TextClassificationOnMobile->Android.

Bạn cũng có thể sử dụng mã finished dưới dạng TextClassificationStep2.

Sau khi khoá này được mở, bạn đã sẵn sàng chuyển sang bước 2.

3. Nhập tệp mô hình và siêu dữ liệu

Trong lớp học lập trình tạo mô hình học máy tạo nhận xét rác, bạn đã tạo một mô hình .TFLITE.

Bạn phải tải tệp mô hình xuống. Nếu chưa có, bạn có thể lấy trong kho lưu trữ dành cho lớp học lập trình này. Mô hình này có tại đây.

Hãy thêm tài sản này vào dự án của bạn bằng cách tạo một thư mục tài sản.

  1. Sử dụng trình điều hướng dự án, đảm bảo Android được chọn ở trên cùng.
  2. Nhấp chuột phải vào thư mục app (ứng dụng). Chọn New (Mới) > Directory (Thư mục).

d7c3e9f21035fc15.png

  1. Trong hộp thoại New Directory (Thư mục mới), hãy chọn src/main/Asset (Thư mục chính/tài sản).

2137f956a1ba4ef0.png.

Bạn sẽ thấy một thư mục Assets mới hiện đã có trong ứng dụng.

ae858835e1a90445.png

  1. Nhấp chuột phải vào thành phần.
  2. Trên trình đơn mở ra, bạn sẽ thấy (trên máy Mac) Reveal in Finder (Hiển thị trong Finder). Chọn mục đó. (Trên Windows sẽ có dòng chữ Show in Explorer (Hiển thị trong Explorer), còn trên Ubuntu sẽ hiện thông báo Hiển thị trong tệp.)

e61aaa3b73c5ab68.png

Finder sẽ khởi chạy để hiển thị vị trí tệp (File Explorer trên Windows, Files trên Linux).

  1. Sao chép các tệp labels.txt, model.tflitevocab vào thư mục này.

14f382cc19552a56.pngS

  1. Quay lại Android Studio và bạn sẽ thấy các nội dung này trong thư mục Asset (tài sản).

150ed2a1d2f7a10d.pngS

4. Cập nhật build.gradle của bạn để sử dụng TensorFlow Lite

Để sử dụng TensorFlow Lite và các thư viện tác vụ TensorFlow Lite có hỗ trợ chương trình này, bạn cần cập nhật tệp build.gradle.

Các dự án Android thường có nhiều hơn một dự án, vì vậy, hãy nhớ tìm cấp ứng dụng. Trong trình khám phá dự án ở chế độ xem Android, hãy tìm mục này trong phần Gradle Scripts (Tập lệnh Gradle). URL chính xác sẽ được gắn nhãn .app như được hiển thị ở đây:

6426051e614bc42f.png.

Bạn cần thực hiện hai thay đổi đối với tệp này. Danh sách đầu tiên là trong mục phần phụ thuộc ở dưới cùng. Thêm văn bản implementation cho thư viện tác vụ TensorFlow Lite như sau:

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

Số phiên bản có thể đã thay đổi kể từ khi chúng tôi viết nội dung này, vì vậy, hãy nhớ xem thông tin mới nhất tại https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier.

Các thư viện tác vụ cũng yêu cầu phiên bản SDK tối thiểu là 21. Tìm chế độ cài đặt này trong android > default config và thay đổi thành 21:

c100b68450b8812f.png

Bây giờ, bạn đã có tất cả phần phụ thuộc, vì vậy, đã đến lúc bắt đầu lập trình!

5. Thêm lớp trợ giúp

Để tách logic suy luận (trong đó ứng dụng của bạn sử dụng mô hình) khỏi giao diện người dùng, hãy tạo một lớp khác để xử lý dự đoán mô hình. Gọi người này là "người trợ giúp" .

  1. Nhấp chuột phải vào tên gói có chứa mã MainActivity của bạn.
  2. Chọn New > (Mới >) Package (Gói).

d5911ded56b5df35.png

  1. Bạn sẽ thấy một hộp thoại ở giữa màn hình yêu cầu bạn nhập tên gói. Hãy thêm mã này vào cuối tên gói hiện tại. (Ở đây, trình duyệt được gọi là người trợ giúp.)

3b9f1f822f99b371.pngS

  1. Sau khi hoàn tất việc này, hãy nhấp chuột phải vào thư mục helpers trong trình khám phá dự án.
  2. Chọn New > (Mới >) Lớp Java và gọi lớp này là TextClassificationClient. Bạn sẽ chỉnh sửa tệp trong bước tiếp theo.

Lớp trợ giúp TextClassificationClient sẽ có dạng như sau (mặc dù tên gói có thể khác.)

package com.google.devrel.textclassificationstep1.helpers;

public class TextClassificationClient {
}
  1. Cập nhật tệp bằng mã này:
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;
    }

}

Lớp này sẽ cung cấp một trình bao bọc cho trình diễn giải TensorFlow Lite, tải mô hình và loại bỏ sự phức tạp của việc quản lý trao đổi dữ liệu giữa ứng dụng và mô hình.

Trong phương thức load(), hệ thống sẽ tạo thực thể cho một loại NLClassifier mới trong đường dẫn của mô hình. Đường dẫn mô hình chỉ đơn giản là tên của mô hình, model.tflite. Loại NLClassifier là một phần của các thư viện tác vụ văn bản và giúp bạn bằng cách chuyển đổi chuỗi của bạn thành mã thông báo, sử dụng đúng độ dài trình tự, truyền chuỗi đó đến mô hình và phân tích cú pháp kết quả.

(Để biết thêm thông tin về những đối tượng này, hãy xem lại bài viết Tạo một mô hình học máy làm phiền bình luận.)

Quá trình phân loại được thực hiện trong phương thức phân loại, trong đó bạn truyền vào phương thức này một chuỗi và trả về một List. Khi sử dụng các mô hình Học máy để phân loại nội dung mà bạn muốn xác định xem một chuỗi có phải là nội dung rác hay không, hệ thống thường trả về tất cả các câu trả lời theo xác suất được chỉ định. Ví dụ: nếu bạn chuyển tin nhắn trông giống như spam, bạn sẽ nhận được một danh sách gồm 2 câu trả lời; một giá trị có xác suất là thư rác và một giá trị có xác suất không phải là thư rác. Thư rác/Không phải thư rác là các danh mục, vì vậy, List được trả về sẽ chứa các xác suất này. Bạn sẽ phân tích cú pháp thông tin đó sau.

Bây giờ, bạn đã có lớp trợ giúp, hãy quay lại MainActivity và cập nhật lớp này để sử dụng lớp này nhằm phân loại văn bản của bạn. Bạn sẽ thấy điều đó trong bước tiếp theo!

6. Phân loại văn bản

Trong MainActivity, trước tiên, bạn cần nhập các trình trợ giúp mà mình vừa tạo!

  1. Ở đầu MainActivity.kt, cùng với các lệnh nhập khác, hãy thêm:
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
  1. Tiếp theo, bạn cần tải trình trợ giúp. Trong onCreate, ngay sau dòng setContentView, hãy thêm các dòng sau để tạo thực thể và tải lớp trình trợ giúp:
val client = TextClassificationClient(applicationContext)
client.load()

Hiện tại, onClickListener của nút sẽ có dạng như sau:

btnSendText.setOnClickListener {
     var toSend:String = txtInput.text.toString()
     txtOutput.text = toSend
 }
  1. Cập nhật mã thành như sau:
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()
}

Thao tác này sẽ thay đổi chức năng từ chỉ xuất dữ liệu đầu vào của người dùng sang phân loại trước.

  1. Với dòng này, bạn sẽ lấy chuỗi mà người dùng đã nhập và chuyển chuỗi đó vào mô hình, nhận lại kết quả:
var results:List<Category> = client.classify(toSend)

Chỉ có 2 danh mục, FalseTrue

. (TensorFlow sắp xếp theo thứ tự bảng chữ cái, nên False sẽ là mục 0, còn True sẽ là mục 1.)

  1. Để biết điểm cho xác suất giá trị là True, bạn có thể xem kết quả[1].score như sau:
    val score = results[1].score
  1. Chọn một giá trị ngưỡng (trong trường hợp này là 0,8), trong đó nếu điểm của danh mục True cao hơn giá trị ngưỡng (0,8), thì thư là thư rác. Nếu không, đó không phải là thư rác và bạn có thể gửi thư này một cách an toàn:
    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. Xem mô hình thực tế tại đây. Thông báo "Truy cập blog của tôi để mua đồ!" đã bị gắn cờ là có nhiều khả năng gửi spam:

1fb0b5de9e566e.png.

Và ngược lại, "Này, hướng dẫn thú vị đấy, cảm ơn!" có khả năng là thư rác rất thấp:

73f38bdb488b29b3.pngS

7. Cập nhật ứng dụng iOS của bạn để sử dụng Mô hình TensorFlow Lite

Bạn có thể lấy mã cho hoạt động này bằng cách làm theo Lớp học lập trình 1 hoặc bằng cách sao chép kho lưu trữ này rồi tải ứng dụng từ TextClassificationStep1. Bạn có thể tìm thấy mã này trong đường dẫn TextClassificationOnMobile->iOS.

Bạn cũng có thể sử dụng mã finished dưới dạng TextClassificationStep2.

Trong lớp học lập trình về mô hình học máy Tạo nhận xét rác, bạn đã tạo một ứng dụng rất đơn giản cho phép người dùng nhập thông báo vào UITextView và truyền thông báo đến kết quả mà không có bất kỳ bộ lọc nào.

Bây giờ, bạn sẽ cập nhật ứng dụng đó để sử dụng mô hình TensorFlow Lite nhằm phát hiện bình luận rác trong văn bản trước khi gửi. Bạn chỉ cần mô phỏng hoạt động gửi thư trong ứng dụng này bằng cách hiển thị văn bản trong nhãn đầu ra (nhưng ứng dụng thực có thể có bảng thông báo, cuộc trò chuyện hoặc nội dung tương tự).

Để bắt đầu, bạn cần có ứng dụng ở bước 1. Bạn có thể sao chép ứng dụng trong kho lưu trữ này.

Để kết hợp TensorFlow Lite, bạn sẽ sử dụng CocoaPods. Nếu chưa cài đặt những tính năng này, bạn có thể thực hiện theo hướng dẫn tại https://cocoapods.org/.

  1. Sau khi bạn cài đặt CocoaPods, hãy tạo một tệp có tên Podfile trong cùng thư mục với .xcproject cho ứng dụng Text tùng. Nội dung của tệp này sẽ có dạng như sau:
target 'TextClassificationStep2' do
  use_frameworks!

  # Pods for NLPClassifier
    pod 'TensorFlowLiteSwift'

end

Tên ứng dụng của bạn phải ở dòng đầu tiên, thay vì "TextAnalysisStep2".

Bằng cách sử dụng Terminal, hãy chuyển đến thư mục đó rồi chạy pod install. Nếu thành công, bạn sẽ có một thư mục mới tên là Pods và một tệp .xcworkspace mới được tạo cho bạn. Bạn sẽ sử dụng thuộc tính đó trong tương lai thay vì .xcproject.

Nếu không thực hiện được, hãy đảm bảo rằng bạn có Podfile trong cùng thư mục với .xcproject. Tệp podfile nằm sai thư mục hoặc tên đích đến sai thường là nguyên nhân chính!

8. Thêm Mô hình và Tệp Từ vựng

Khi tạo mô hình bằng trình tạo Mô hình TensorFlow Lite, bạn có thể tạo ra mô hình (dưới dạng model.tflite) và từ vựng (dưới dạng vocab.txt).

  1. Thêm đối tượng vào dự án của bạn bằng cách kéo và thả đối tượng từ Finder vào cửa sổ dự án. Hãy đảm bảo bạn đã chọn mục thêm vào mục tiêu:

1ee9eaa00ee79859.pngS

Sau khi hoàn tất, bạn sẽ thấy chúng trong dự án của mình:

b63502b23911fd42.png

  1. Kiểm tra kỹ xem chúng đã được thêm vào gói hay chưa (để chúng được triển khai trên thiết bị) bằng cách chọn dự án của bạn (trong ảnh chụp màn hình ở trên, đó là biểu tượng màu xanh dương TextClassificationStep2) và xem thẻ TextClassificationStep2:

20b7cb603d49b457.pngS

9. Tải từ vựng

Khi phân loại NLP, mô hình sẽ được huấn luyện bằng các từ được mã hoá thành vectơ. Mô hình mã hoá các từ có một tập hợp tên và giá trị cụ thể được học khi huấn luyện mô hình. Xin lưu ý rằng hầu hết các mô hình sẽ có từ vựng khác nhau và bạn cần phải sử dụng từ vựng cho mô hình đã được tạo tại thời điểm đào tạo. Đây là tệp vocab.txt mà bạn vừa thêm vào ứng dụng của mình.

Bạn có thể mở tệp trong Xcode để xem mã hoá. Những từ như "bài hát" được mã hoá thành 6 và "tình yêu" đến 12. Thứ tự này thực ra là thứ tự tần suất, vì vậy, "I" là từ phổ biến nhất trong tập dữ liệu, theo sau là "kiểm tra".

Khi người dùng của bạn nhập bằng từ, bạn sẽ muốn mã hoá họ bằng từ vựng này trước khi gửi chúng đến mô hình để được phân loại.

Hãy cùng khám phá mã đó. Bắt đầu bằng cách tải từ vựng.

  1. Xác định biến cấp lớp để lưu trữ từ điển:
var words_dictionary = [String : Int]()
  1. Sau đó, hãy tạo một func trong lớp để tải từ vựng vào từ điển này:
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. Bạn có thể chạy phương thức này bằng cách gọi từ trong viewDidLoad:
override func viewDidLoad() {
    super.viewDidLoad()
    txtInput.delegate = self
    loadVocab()
}

10. Biến một chuỗi thành một chuỗi mã thông báo

Người dùng sẽ nhập các từ dưới dạng câu và các từ này sẽ trở thành một chuỗi. Mỗi từ trong câu, nếu có trong từ điển, sẽ được mã hoá thành khoá-giá trị cho từ đó theo định nghĩa trong từ vựng.

Mô hình NLP thường chấp nhận độ dài trình tự cố định. Có những ngoại lệ với các mô hình được tạo bằng ragged tensors, nhưng bạn sẽ thấy hầu hết các trường hợp đều đã được khắc phục. Khi tạo mô hình, bạn đã chỉ định chiều dài này. Hãy đảm bảo bạn sử dụng cùng một thời lượng trong ứng dụng iOS của mình.

Giá trị mặc định trong Colab cho Trình tạo mô hình TensorFlow Lite mà bạn đã sử dụng trước đó là 20, vì vậy, hãy thiết lập tại đây:

let SEQUENCE_LENGTH = 20

Thêm func này để lấy chuỗi, chuyển thành chữ thường và xoá mọi dấu câu:

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
}

Lưu ý rằng chuỗi sẽ là Int32. Đây là trường hợp được chủ ý chọn vì khi truyền các giá trị vào TensorFlow Lite, bạn sẽ phải xử lý bộ nhớ cấp thấp, và TensorFlow Lite coi các số nguyên trong chuỗi là số nguyên 32 bit. Điều này sẽ giúp cuộc sống của bạn (một chút) dễ dàng hơn khi truyền các chuỗi đến mô hình.

11. Thực hiện phân loại

Để phân loại một câu, trước tiên, câu đó phải được chuyển đổi thành một chuỗi mã thông báo dựa trên các từ trong câu. Việc này sẽ được thực hiện trong bước 9.

Bây giờ, bạn sẽ lấy câu và truyền câu đó đến mô hình, yêu cầu mô hình suy luận về câu và phân tích cú pháp kết quả.

Thao tác này sẽ sử dụng trình thông dịch TensorFlow Lite mà bạn cần nhập:

import TensorFlowLite

Bắt đầu bằng một func nhận theo trình tự của bạn, vốn là một mảng gồm các kiểu 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
  }

Thao tác này sẽ tải tệp mô hình từ gói và gọi trình thông dịch bằng tệp đó.

Bước tiếp theo là sao chép bộ nhớ cơ bản được lưu trữ trong trình tự vào một vùng đệm có tên là myData, để truyền đến một tensor. Khi triển khai nhóm TensorFlow Lite cũng như trình thông dịch, bạn đã có quyền truy cập vào một Tensor Type.

Bắt đầu mã như thế này (vẫn ở phân loại func.):

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

Đừng lo lắng nếu bạn gặp lỗi trên copyingBufferOf. Sau này, khoá này sẽ được triển khai dưới dạng phần mở rộng.

Đã đến lúc phân bổ tensor trên trình thông dịch, sao chép vùng đệm dữ liệu bạn vừa tạo sang tensor đầu vào, sau đó gọi trình thông dịch để tiến hành suy luận:

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

Sau khi lệnh gọi hoàn tất, bạn có thể xem kết quả của trình phiên dịch để biết kết quả.

Đây sẽ là các giá trị thô (4 byte trên mỗi nơron) mà sau đó bạn sẽ phải đọc và chuyển đổi. Vì mô hình cụ thể này có 2 tế bào thần kinh đầu ra, bạn sẽ cần đọc trong 8 byte sẽ được chuyển đổi thành Float32 để phân tích cú pháp. Bạn đang xử lý bộ nhớ cấp thấp, do đó lỗi 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) ?? []

Bây giờ, việc phân tích cú pháp dữ liệu để xác định chất lượng spam tương đối dễ dàng. Mô hình có 2 đầu ra, đầu tiên với xác suất tin nhắn không phải là spam, đầu ra thứ hai có xác suất đúng như vậy. Bạn có thể xem results[1] để tìm giá trị của nội dung rác:

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

Để thuận tiện, sau đây là phương thức đầy đủ:

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. Thêm tiện ích Swift

Mã ở trên sử dụng phần mở rộng cho Loại dữ liệu để cho phép bạn sao chép các bit thô của mảng Int32 vào Data. Dưới đây là mã cho tiện ích đó:

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

Khi xử lý bộ nhớ cấp thấp, bạn sử dụng từ "không an toàn" và đoạn mã ở trên cần bạn khởi chạy một mảng dữ liệu không an toàn. Tiện ích này giúp bạn có thể:

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. Chạy ứng dụng iOS

Chạy và kiểm thử ứng dụng.

Nếu mọi việc đều ổn, bạn sẽ thấy ứng dụng trên thiết bị của mình như sau:

74cbd28d9b1592ed.png.

Nơi xuất hiện thông báo "Mua sách của tôi để học cách giao dịch trực tuyến!" đã gửi đi, ứng dụng sẽ gửi lại cảnh báo phát hiện tin nhắn rác với xác suất là 0,99%!

14. Xin chúc mừng!

Giờ đây, bạn đã tạo được một ứng dụng rất đơn giản có thể lọc văn bản để tìm bình luận không liên quan bằng một mô hình đã được huấn luyện dựa trên dữ liệu dùng để gửi nội dung rác trên các blog.

Bước tiếp theo trong vòng đời điển hình của nhà phát triển là tìm hiểu bạn cần làm gì để tuỳ chỉnh mô hình này dựa trên dữ liệu có trong cộng đồng của bạn. Bạn sẽ tìm hiểu cách thực hiện việc này trong hoạt động tiếp theo của lộ trình.