อัปเดตแอปเพื่อใช้โมเดลแมชชีนเลิร์นนิงสำหรับการกรองสแปม

1. ก่อนเริ่มต้น

ใน Codelab นี้ คุณจะอัปเดตแอปที่สร้างไว้ใน Codelab เริ่มต้นใช้งานการแยกประเภทข้อความบนอุปกรณ์เคลื่อนที่ก่อนหน้านี้

ข้อกำหนดเบื้องต้น

  • โค้ดแล็บนี้ออกแบบมาสำหรับนักพัฒนาซอฟต์แวร์มือโปรที่เพิ่งเริ่มศึกษาแมชชีนเลิร์นนิง
  • Codelab เป็นส่วนหนึ่งของเส้นทางที่เรียงลำดับ หากคุณยังไม่ได้สร้างแอปสไตล์การรับส่งข้อความพื้นฐานหรือสร้างโมเดลแมชชีนเลิร์นนิงสำหรับสแปมความคิดเห็น โปรดหยุดและดำเนินการดังกล่าวในตอนนี้

สิ่งที่คุณจะ [สร้างหรือเรียนรู้]

  • คุณจะได้เรียนรู้วิธีผสานรวมโมเดลที่กำหนดเองลงในแอปที่สร้างจากขั้นตอนก่อนหน้า

สิ่งที่คุณต้องมี

  • Android Studio หรือ CocoaPods สำหรับ iOS

2. เปิดแอป Android ที่มีอยู่

คุณสามารถรับโค้ดสำหรับกรณีนี้ได้โดยทำตาม Codelab 1 หรือโดยการโคลนที่เก็บนี้แล้วโหลดแอปจาก TextClassificationStep1

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

ซึ่งคุณจะพบได้ในเส้นทาง TextClassificationOnMobile->Android

คุณยังใช้รหัสที่เสร็จสิ้นแล้วได้ด้วย TextClassificationStep2

เมื่อเปิดขึ้นมาแล้ว คุณก็พร้อมที่จะทำขั้นตอนที่ 2 ต่อได้

3. นําเข้าไฟล์โมเดลและข้อมูลเมตา

ในโค้ดแล็บสร้างโมเดลแมชชีนเลิร์นนิงสำหรับสแปมความคิดเห็น คุณได้สร้างโมเดล .TFLITE

คุณควรดาวน์โหลดไฟล์โมเดลแล้ว หากยังไม่มี คุณสามารถดาวน์โหลดได้จาก repo ของโค้ดแล็บนี้ และโมเดลมีให้ที่นี่

เพิ่มลงในโปรเจ็กต์โดยสร้างไดเรกทอรีชิ้นงาน

  1. ใช้เครื่องมือนำทางโปรเจ็กต์ ตรวจสอบว่าได้เลือก Android ที่ด้านบนแล้ว
  2. คลิกขวาที่โฟลเดอร์ app เลือกใหม่ > ไดเรกทอรี

d7c3e9f21035fc15.png

  1. ในกล่องโต้ตอบไดเรกทอรีใหม่ ให้เลือก src/main/assets

2137f956a1ba4ef0.png

คุณจะเห็นโฟลเดอร์ assets ใหม่ในแอป

ae858835e1a90445.png

  1. คลิกขวาที่ชิ้นงาน
  2. ในเมนูที่เปิดขึ้น คุณจะเห็นแสดงใน Finder (บน Mac) เลือกแอป (ใน Windows จะระบุว่า Show in Explorer ส่วนใน Ubuntu จะระบุว่า Show in Files)

e61aaa3b73c5ab68.png

Finder จะเปิดขึ้นเพื่อแสดงตำแหน่งไฟล์ (File Explorer ใน Windows, Files ใน Linux)

  1. คัดลอกไฟล์ labels.txt, model.tflite และ vocab ไปยังไดเรกทอรีนี้

14f382cc19552a56.png

  1. กลับไปที่ Android Studio แล้วคุณจะเห็นไฟล์ดังกล่าวอยู่ในโฟลเดอร์ assets

150ed2a1d2f7a10d.png

4. อัปเดต build.gradle เพื่อใช้ TensorFlow Lite

หากต้องการใช้ TensorFlow Lite และไลบรารีงาน TensorFlow Lite ที่รองรับ คุณจะต้องอัปเดตไฟล์ build.gradle

โปรเจ็กต์ Android มักจะมีมากกว่า 1 โปรเจ็กต์ ดังนั้นอย่าลืมหาระดับแอปที่ 1 ในโปรแกรมสำรวจโปรเจ็กต์ในมุมมอง Android ให้ค้นหาโปรเจ็กต์ในส่วน Gradle Scripts ไฟล์ที่ถูกต้องจะมีป้ายกำกับเป็น .app ดังที่แสดงที่นี่

6426051e614bc42f.png

คุณจะต้องทำการเปลี่ยนแปลง 2 รายการในไฟล์นี้ รายการแรกอยู่ในส่วน dependencies ที่ด้านล่าง เพิ่มข้อความ implementation สำหรับคลังงาน TensorFlow Lite ดังนี้

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

หมายเลขเวอร์ชันอาจเปลี่ยนแปลงไปนับตั้งแต่ที่เขียนบทความนี้ ดังนั้นโปรดตรวจสอบเวอร์ชันล่าสุดที่ https://www.tensorflow.org/lite/inference_with_metadata/task_library/nl_classifier

ไลบรารีงานต้องมี SDK เวอร์ชัน 21 เป็นอย่างน้อยด้วย ค้นหาการตั้งค่านี้ใน android > default config แล้วเปลี่ยนเป็น 21

c100b68450b8812f.png

ตอนนี้คุณมี Dependency ทั้งหมดแล้ว ถึงเวลาเริ่มเขียนโค้ด

5. เพิ่มชั้นเรียนผู้ช่วยเหลือ

หากต้องการแยกตรรกะการอนุมานที่แอปใช้โมเดลออกจากอินเทอร์เฟซผู้ใช้ ให้สร้างคลาสอื่นเพื่อจัดการการอนุมานโมเดล เรียกชั้นเรียนนี้ว่า "ผู้ช่วย"

  1. คลิกขวาที่ชื่อแพ็กเกจที่มีรหัส MainActivity
  2. เลือกใหม่ > แพ็กเกจ

d5911ded56b5df35.png

  1. คุณจะเห็นกล่องโต้ตอบที่ตรงกลางของหน้าจอเพื่อขอให้คุณป้อนชื่อแพ็กเกจ เพิ่มต่อท้ายชื่อแพ็กเกจปัจจุบัน (ในที่นี้เรียกว่า helpers)

3b9f1f822f99b371.png

  1. เมื่อดำเนินการเสร็จแล้ว ให้คลิกขวาที่โฟลเดอร์ helpers ใน Project Explorer
  2. เลือกใหม่ > Java Class และตั้งชื่อว่า TextClassificationClient คุณจะได้แก้ไขไฟล์ในขั้นตอนถัดไป

คลาสตัวช่วย TextClassificationClient จะมีลักษณะดังนี้ (แม้ว่าชื่อแพ็กเกจอาจแตกต่างออกไป)

package com.google.devrel.textclassificationstep1.helpers;

public class TextClassificationClient {
}
  1. อัปเดตไฟล์ด้วยโค้ดนี้
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;
    }

}

คลาสนี้จะจัดเตรียม Wrapper ให้กับโปรแกรมแปลภาษา TensorFlow Lite, โหลดโมเดล และแยกความซับซ้อนของการจัดการการแลกเปลี่ยนข้อมูลระหว่างแอปกับโมเดล

ในเมธอด load() นี้จะสร้างอินสแตนซ์ NLClassifier ประเภทใหม่จากเส้นทางโมเดล เส้นทางโมเดลคือชื่อโมเดล model.tflite ประเภท NLClassifier เป็นส่วนหนึ่งของไลบรารีงานข้อความ ซึ่งจะช่วยคุณโดยแปลงสตริงเป็นโทเค็น โดยใช้ความยาวของลำดับที่ถูกต้อง ส่งไปยังโมเดล และแยกวิเคราะห์ผลลัพธ์

(ดูรายละเอียดเพิ่มเติมเกี่ยวกับฟีเจอร์เหล่านี้ได้ที่ "สร้างโมเดลแมชชีนเลิร์นนิงสำหรับสแปมความคิดเห็น")

การจัดประเภทจะดำเนินการในเมธอด classify ซึ่งคุณส่งสตริงไปให้ และเมธอดจะแสดงผล List เมื่อใช้โมเดลแมชชีนเลิร์นนิงในการแยกประเภทเนื้อหาที่คุณต้องการพิจารณาว่าสตริงหนึ่งๆ เป็นสแปมหรือไม่ เป็นเรื่องปกติที่จะมีการส่งคืนคำตอบทั้งหมด พร้อมกับความน่าจะเป็นที่กำหนดไว้ ตัวอย่างเช่น หากคุณส่งข้อความที่ดูเหมือนสแปม คุณจะได้รับการตอบกลับ 2 รายการ ได้แก่ รายการหนึ่งที่มีแนวโน้มว่าเป็นสแปมและอีกรายการหนึ่งที่มีแนวโน้มว่าไม่ใช่สแปม จดหมายขยะ/ไม่ใช่จดหมายขยะเป็นหมวดหมู่ ดังนั้น List ที่แสดงผลจะมีความน่าจะเป็นเหล่านี้ คุณจะแยกวิเคราะห์ส่วนนั้นในภายหลัง

เมื่อคุณมีคลาสตัวช่วยแล้ว ให้กลับไปที่ MainActivity แล้วอัปเดตเพื่อใช้คลาสนี้ในการจัดประเภทข้อความ คุณจะเห็นข้อมูลดังกล่าวในขั้นตอนถัดไป

6. จำแนกประเภทข้อความ

ใน MainActivity คุณจะต้องนําเข้าตัวช่วยที่เพิ่งสร้างขึ้นก่อน

  1. ที่ด้านบนของ MainActivity.kt ให้เพิ่มข้อมูลต่อไปนี้พร้อมกับการนําเข้าอื่นๆ
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
  1. ขั้นตอนถัดไปคือการโหลดตัวช่วย ใน onCreate ให้เพิ่มบรรทัดต่อไปนี้ต่อจากบรรทัด setContentView เพื่อสร้างอินสแตนซ์และโหลดคลาสตัวช่วย
val client = TextClassificationClient(applicationContext)
client.load()

ในขณะนี้ onClickListener ของปุ่มควรมีลักษณะดังนี้

btnSendText.setOnClickListener {
     var toSend:String = txtInput.text.toString()
     txtOutput.text = toSend
 }
  1. อัปเดตให้มีลักษณะดังนี้
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()
}

ซึ่งจะเปลี่ยนฟังก์ชันการทำงานจากเพียงแค่แสดงผลอินพุตของผู้ใช้เป็นการแยกประเภทก่อน

  1. บรรทัดนี้จะนำสตริงที่ผู้ใช้ป้อนและส่งไปยังโมเดลเพื่อรับผลลัพธ์
var results:List<Category> = client.classify(toSend)

โดยแบ่งออกเป็น 2 หมวดหมู่เท่านั้น ได้แก่ False และ True

. (TensorFlow จะจัดเรียงตามลำดับตัวอักษร ดังนั้น False จะเป็นรายการที่ 0 และ True จะเป็นรายการที่ 1)

  1. หากต้องการดูคะแนนความน่าจะเป็นที่ค่าจะเป็น True ให้ดูที่ results[1].score ดังนี้
    val score = results[1].score
  1. เลือกค่าเกณฑ์ (ในกรณีนี้คือ 0.8) ซึ่งคุณบอกว่าหากคะแนนสำหรับหมวดหมู่จริงสูงกว่าค่าเกณฑ์ (0.8) แสดงว่าข้อความนั้นเป็นสแปม มิฉะนั้น ข้อความจะไม่ใช่จดหมายขยะ และสามารถส่งข้อความได้อย่างปลอดภัย ดังนี้
    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. ดูโมเดลในการใช้งานจริงที่นี่ ข้อความ "ไปที่บล็อกของฉันเพื่อซื้อของ" ถูกแจ้งว่ามีโอกาสสูงที่จะเป็นสแปม

1fb0b5de9e566e.png

และในทางกลับกัน "สวัสดี บทแนะนำสนุกดี ขอบคุณ" มีแนวโน้มต่ำมากที่จะเป็นจดหมายขยะ

73f38bdb488b29b3.png

7. อัปเดตแอป iOS เพื่อใช้โมเดล TensorFlow Lite

คุณดูโค้ดสําหรับการดำเนินการนี้ได้โดยทําตาม Codelab 1 หรือทําการโคลนที่เก็บนี้และโหลดแอปจาก TextClassificationStep1 ซึ่งคุณจะพบได้ในเส้นทาง TextClassificationOnMobile->iOS

รหัสเสร็จสิ้น TextClassificationStep2 ก็มีให้ใช้งานเช่นกัน

ใน Codelab สร้างโมเดลแมชชีนเลิร์นนิงสําหรับสแปมความคิดเห็น คุณได้สร้างแอปที่เรียบง่ายมากซึ่งอนุญาตให้ผู้ใช้พิมพ์ข้อความลงใน UITextView และส่งผ่านไปยังเอาต์พุตได้โดยไม่ต้องกรอง

คุณจะต้องอัปเดตแอปนั้นเพื่อใช้โมเดล TensorFlow Lite เพื่อตรวจหาสแปมความคิดเห็นในข้อความก่อนส่ง เพียงจำลองการส่งในแอปนี้โดยการแสดงผลข้อความในป้ายกำกับเอาต์พุต (แต่แอปจริงอาจมีกระดานข่าวสาร แชท หรือข้อความที่คล้ายกัน)

ในการเริ่มต้นใช้งาน คุณจะต้องมีแอปจากขั้นตอนที่ 1 ซึ่งคุณโคลนได้จากที่เก็บ

คุณจะต้องใช้ CocoaPods เพื่อรวม TensorFlow Lite หากยังไม่ได้ติดตั้ง ให้ทำตามวิธีการที่ https://cocoapods.org/

  1. เมื่อติดตั้ง CocoaPods แล้ว ให้สร้างไฟล์ชื่อ Podfile ในไดเรกทอรีเดียวกับ .xcproject สำหรับแอป TextClassification เนื้อหาของไฟล์นี้ควรมีลักษณะดังนี้
target 'TextClassificationStep2' do
  use_frameworks!

  # Pods for NLPClassifier
    pod 'TensorFlowLiteSwift'

end

ชื่อแอปควรอยู่ในบรรทัดแรก ไม่ใช่ "TextClassificationStep2"

ใช้เทอร์มินัลเพื่อไปยังไดเรกทอรีนั้นและเรียกใช้ pod install หากดำเนินการสำเร็จ คุณจะมีไดเรกทอรีใหม่ชื่อ Pods และระบบจะสร้างไฟล์ .xcworkspace ใหม่ให้คุณ คุณจะต้องใช้ที่อยู่นั้นในอนาคตแทน .xcproject

หากดำเนินการไม่สำเร็จ โปรดตรวจสอบว่าคุณมี Podfile ในไดเรกทอรีเดียวกับที่ .xcproject อยู่ โดยปกติแล้ว ปัญหานี้มักเกิดจาก podfile อยู่ในไดเรกทอรีที่ไม่ถูกต้องหรือชื่อเป้าหมายไม่ถูกต้อง

8. เพิ่มไฟล์โมเดลและไฟล์คําศัพท์

เมื่อสร้างโมเดลด้วยเครื่องมือสร้างโมเดล TensorFlow Lite คุณส่งออกโมเดล (เป็น model.tflite) และคำศัพท์ (เป็น vocab.txt) ได้

  1. เพิ่มลงในโปรเจ็กต์โดยลากและวางจาก Finder ลงในหน้าต่างโปรเจ็กต์ ตรวจสอบว่าได้เลือกเพิ่มลงในเป้าหมายแล้ว

1ee9eaa00ee79859.png

เมื่อทําเสร็จแล้ว คุณจะเห็นรายการต่อไปนี้ในโปรเจ็กต์

b63502b23911fd42.png

  1. ตรวจสอบอีกครั้งว่าได้เพิ่มลงใน Bundle แล้ว (เพื่อให้นำไปใช้งานในอุปกรณ์ได้) โดยเลือกโปรเจ็กต์ (ในภาพหน้าจอด้านบนคือไอคอนสีน้ำเงิน TextClassificationStep2) และดูที่แท็บระยะการสร้าง

20b7cb603d49b457.png

9. โหลดคำศัพท์

เมื่อทำการจำแนกประเภท NLP โมเดลจะได้รับการฝึกด้วยคำที่เข้ารหัสเป็นเวกเตอร์ โมเดลจะเข้ารหัสคําด้วยชุดชื่อและค่าที่เฉพาะเจาะจงซึ่งเรียนรู้ขณะที่โมเดลได้รับการฝึก โปรดทราบว่าโมเดลส่วนใหญ่จะมีคําศัพท์ต่างกัน และคุณต้องใช้คําศัพท์สําหรับโมเดลที่สร้างขึ้นขณะฝึก นี่คือไฟล์ vocab.txt ที่คุณเพิ่งเพิ่มลงในแอป

คุณสามารถเปิดไฟล์ใน Xcode เพื่อดูการเข้ารหัสได้ คําอย่าง "เพลง" จะเข้ารหัสเป็น 6 และ "รัก" เป็น 12 ลําดับนี้เป็นลําดับความถี่ ดังนั้น "ฉัน" จึงเป็นคําที่พบบ่อยที่สุดในชุดข้อมูล ตามด้วย "ตรวจสอบ"

เมื่อผู้ใช้พิมพ์คำ คุณจะต้องเข้ารหัสคำเหล่านั้นด้วยคําศัพท์นี้ก่อนที่จะส่งไปยังโมเดลเพื่อจัดประเภท

มาดูโค้ดนี้กัน เริ่มด้วยการโหลดคำศัพท์

  1. กำหนดตัวแปรระดับคลาสเพื่อจัดเก็บพจนานุกรม
var words_dictionary = [String : Int]()
  1. จากนั้นสร้าง func ในชั้นเรียนเพื่อโหลดคําศัพท์ลงในพจนานุกรมนี้
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. คุณดำเนินการนี้ได้โดยเรียกใช้จากภายใน viewDidLoad:
override func viewDidLoad() {
    super.viewDidLoad()
    txtInput.delegate = self
    loadVocab()
}

10. เปลี่ยนสตริงเป็นลำดับโทเค็น

ผู้ใช้จะพิมพ์คำเป็นประโยคซึ่งจะกลายเป็นสตริง ระบบจะเข้ารหัสแต่ละคำในประโยคเป็นค่าคีย์สำหรับคำนั้นๆ ตามที่ระบุไว้ในคําศัพท์ หากคำนั้นอยู่ในพจนานุกรม

โดยปกติแล้วโมเดล NLP จะยอมรับความยาวของลำดับแบบคงที่ มีข้อยกเว้นสำหรับโมเดลที่สร้างโดยใช้ ragged tensors แต่โดยส่วนใหญ่แล้วคุณจะเห็นว่าได้รับการแก้ไขแล้ว เมื่อคุณสร้างโมเดล คุณได้ระบุความยาวนี้ ตรวจสอบว่าคุณใช้ความยาวเดียวกันในแอป iOS

ค่าเริ่มต้นใน Colab สำหรับเครื่องมือสร้างโมเดล TensorFlow Lite ที่คุณใช้ก่อนหน้านี้คือ 20 ดังนั้นให้ตั้งค่าที่นี่ด้วย

let SEQUENCE_LENGTH = 20

เพิ่ม func นี้ ซึ่งจะนำสตริงไปแปลงเป็นตัวพิมพ์เล็กและนำเครื่องหมายวรรคตอนออก

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
}

โปรดทราบว่าลําดับจะเป็น Int32 เราเลือกรูปแบบนี้อย่างจงใจเนื่องจากเมื่อต้องส่งค่าไปยัง TensorFlow Lite คุณจะต้องจัดการกับหน่วยความจำระดับล่าง และ TensorFlow Lite จะถือว่าจำนวนเต็มในลำดับสตริงเป็นจำนวนเต็ม 32 บิต ซึ่งจะช่วยให้คุณส่งสตริงไปยังโมเดลได้ง่ายขึ้น (เล็กน้อย)

11. ทำการจัดประเภท

หากต้องการจัดประเภทประโยค จะต้องแปลงประโยคเป็นลำดับโทเค็นตามคำในประโยคก่อน ซึ่งจะดำเนินการในขั้นตอนที่ 9

ตอนนี้คุณจะต้องนำประโยคไปส่งให้โมเดล ให้โมเดลทำการอนุมานประโยค และแยกวิเคราะห์ผลลัพธ์

การดำเนินการนี้จะใช้อินเทอร์พรีเตอร์ของ TensorFlow Lite ซึ่งคุณจะต้องนำเข้า

import TensorFlowLite

เริ่มต้นด้วย func ที่รับลําดับ ซึ่งเป็นอาร์เรย์ประเภท 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
  }

การดำเนินการนี้จะโหลดไฟล์โมเดลจากแพ็กเกจ และเรียกใช้ล่าม

ขั้นตอนถัดไปคือการคัดลอกหน่วยความจำที่อยู่เบื้องหลังซึ่งจัดเก็บไว้ในลำดับไปยังบัฟเฟอร์ชื่อ myData, เพื่อให้ส่งไปยังเทนเซอร์ได้ เมื่อใช้งานพ็อด TensorFlow Lite และอินเทอร์พรีเตอร์ คุณมีสิทธิ์เข้าถึง Tensor Type

เริ่มโค้ดแบบนี้ (ยังอยู่ในคลาสify func)

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

ไม่ต้องกังวลหากพบข้อผิดพลาดใน copyingBufferOf ซึ่งจะใช้เป็นส่วนขยายในภายหลัง

ตอนนี้ถึงเวลาจัดสรร Tensor ในล่ามแล้ว คัดลอกบัฟเฟอร์ข้อมูลที่คุณเพิ่งสร้างไปยัง 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()

เมื่อการเรียกใช้เสร็จสมบูรณ์แล้ว คุณสามารถดูเอาต์พุตของโปรแกรมแปลเพื่อดูผลลัพธ์

ค่าเหล่านี้จะเป็นค่าดิบ (4 ไบต์ต่อเซลล์ประสาท) ซึ่งคุณจะต้องอ่านและแปลง เนื่องจากโมเดลนี้มีเซลล์ประสาทเอาต์พุต 2 เซลล์ คุณจะต้องอ่าน 8 ไบต์ที่จะแปลงเป็น Float32 สำหรับการแยกวิเคราะห์ คุณกำลังจัดการกับหน่วยความจําระดับต่ำ นั่นคือ 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) ?? []

ตอนนี้การแยกวิเคราะห์ข้อมูลเพื่อพิจารณาคุณภาพของจดหมายขยะนั้นค่อนข้างง่าย โมเดลมีเอาต์พุต 2 รายการ รายการแรกแสดงความน่าจะเป็นที่ข้อความไม่ใช่สแปม และรายการที่ 2 แสดงความน่าจะเป็นที่ข้อความเป็นสแปม คุณจึงดู results[1] เพื่อหาค่าสแปมได้ ดังนี้

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

วิธีการแบบเต็มมีดังนี้

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

โค้ดด้านบนใช้ส่วนขยายของประเภทข้อมูลเพื่อให้คุณคัดลอกบิตดิบของอาร์เรย์ Int32 ไปยัง Data ได้ โค้ดสําหรับส่วนขยายนั้นคือ

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

เมื่อจัดการกับหน่วยความจําระดับล่าง คุณจะใช้ข้อมูลที่ "ไม่ปลอดภัย" และโค้ดด้านบนต้องการให้คุณเริ่มต้นอาร์เรย์ของข้อมูลที่ไม่ปลอดภัย ส่วนขยายนี้ช่วยให้คุณทำสิ่งต่อไปนี้ได้

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

เรียกใช้และทดสอบแอป

หากทุกอย่างเรียบร้อยดี คุณควรเห็นแอปในอุปกรณ์ดังต่อไปนี้

74cbd28d9b1592ed.png

เมื่อส่งข้อความ "ซื้อหนังสือของฉันเพื่อเรียนรู้การซื้อขายออนไลน์" แอปจะส่งการแจ้งเตือนที่ตรวจพบสแปมกลับพร้อมความน่าจะเป็น 0 .99%

14. ยินดีด้วย

ตอนนี้คุณสร้างแอปง่ายๆ ที่กรองข้อความเพื่อหาสแปมความคิดเห็นโดยใช้โมเดลที่ผ่านการฝึกด้วยข้อมูลที่ใช้สแปมบล็อกแล้ว

ขั้นตอนถัดไปในวงจรชีวิตของนักพัฒนาซอฟต์แวร์โดยทั่วไปคือการสำรวจสิ่งที่ต้องทำในการปรับแต่งโมเดลจากข้อมูลที่พบในชุมชนของคุณ คุณจะเห็นวิธีดำเนินการดังกล่าวในกิจกรรมเส้นทางถัดไป