1. ก่อนเริ่มต้น
ใน Codelab นี้ คุณจะอัปเดตแอปที่สร้างขึ้นใน 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. นำเข้าไฟล์โมเดลและข้อมูลเมตา
ใน Codelab สร้างโมเดลแมชชีนเลิร์นนิงสำหรับสแปมในความคิดเห็น คุณได้สร้างโมเดล .TFLITE
คุณควรดาวน์โหลดไฟล์โมเดล หากไม่มี คุณสามารถดาวน์โหลดได้จากที่เก็บสำหรับโค้ดแล็บนี้ และดาวน์โหลดโมเดลได้ที่นี่
เพิ่มลงในโปรเจ็กต์โดยสร้างไดเรกทอรีชิ้นงาน
- ใช้แถบนำทางของโปรเจ็กต์เพื่อให้แน่ใจว่าได้เลือก Android ที่ด้านบนแล้ว
- คลิกขวาที่โฟลเดอร์ app เลือกใหม่ > ไดเรกทอรี

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

คุณจะเห็นว่าตอนนี้มีโฟลเดอร์ชิ้นงานใหม่ในแอปแล้ว

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

Finder จะเปิดขึ้นเพื่อแสดงตำแหน่งไฟล์ (File Explorer ใน Windows, Files ใน Linux)
- คัดลอกไฟล์
labels.txt,model.tfliteและvocabไปยังไดเรกทอรีนี้

- กลับไปที่ Android Studio แล้วคุณจะเห็นว่าไฟล์พร้อมใช้งานในโฟลเดอร์ชิ้นงาน

4. อัปเดต build.gradle เพื่อใช้ TensorFlow Lite
หากต้องการใช้ TensorFlow Lite และไลบรารีงาน TensorFlow Lite ที่รองรับ คุณจะต้องอัปเดตไฟล์ build.gradle
โปรเจ็กต์ Android มักจะมีมากกว่า 1 รายการ ดังนั้นอย่าลืมหารายการระดับแอป ในโปรเจ็กต์ Explorer ในมุมมอง Android ให้ค้นหาในส่วนสคริปต์ Gradle โดยจะมีการติดป้ายกำกับ .app ที่ถูกต้องดังที่แสดงที่นี่

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

ตอนนี้คุณมีทรัพยากร Dependency ทั้งหมดแล้ว ก็ถึงเวลาเริ่มเขียนโค้ด
5. เพิ่มคลาส Helper
หากต้องการแยกตรรกะการอนุมานที่แอปใช้โมเดลออกจากอินเทอร์เฟซผู้ใช้ ให้สร้างคลาสอื่นเพื่อจัดการการอนุมานโมเดล เรียกคลาสนี้ว่าคลาส "Helper"
- คลิกขวาที่ชื่อแพ็กเกจที่มีโค้ด
MainActivity - เลือกใหม่ > แพ็กเกจ

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

- เมื่อเสร็จแล้ว ให้คลิกขวาที่โฟลเดอร์ helpers ใน Project Explorer
- เลือกใหม่ > คลาส Java แล้วตั้งชื่อว่า
TextClassificationClientคุณจะแก้ไขไฟล์ในขั้นตอนถัดไป
TextClassificationClientคลาส Helper จะมีลักษณะดังนี้ (แม้ว่าชื่อแพ็กเกจอาจแตกต่างกัน)
package com.google.devrel.textclassificationstep1.helpers;
public class TextClassificationClient {
}
- อัปเดตไฟล์ด้วยโค้ดนี้
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 ที่แสดงจะมีความน่าจะเป็นเหล่านี้ คุณจะแยกวิเคราะห์ในภายหลัง
ตอนนี้คุณมีคลาส Helper แล้ว ให้กลับไปที่ MainActivity และอัปเดตเพื่อใช้คลาสนี้ในการจัดประเภทข้อความ คุณจะเห็นตัวอย่างในขั้นตอนถัดไป
6. จัดประเภทข้อความ
ใน MainActivity คุณจะต้องนําเข้าฟังก์ชันช่วยที่เพิ่งสร้างก่อน
- ที่ด้านบนของ
MainActivity.ktให้เพิ่มรายการต่อไปนี้พร้อมกับการนำเข้าอื่นๆ
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
- จากนั้นคุณจะต้องโหลดตัวช่วย ใน
onCreateให้เพิ่มบรรทัดต่อไปนี้เพื่อสร้างอินสแตนซ์และโหลดคลาส Helper ทันทีหลังจากบรรทัดsetContentView
val client = TextClassificationClient(applicationContext)
client.load()
ในตอนนี้ onClickListener ของปุ่มควรมีลักษณะดังนี้
btnSendText.setOnClickListener {
var toSend:String = txtInput.text.toString()
txtOutput.text = toSend
}
- อัปเดตให้มีลักษณะดังนี้
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()
}
การเปลี่ยนแปลงนี้จะเปลี่ยนฟังก์ชันการทำงานจากการแสดงผลอินพุตของผู้ใช้เป็นการจัดประเภทอินพุตก่อน
- บรรทัดนี้จะนำสตริงที่ผู้ใช้ป้อนและส่งไปยังโมเดลเพื่อรับผลลัพธ์กลับมา
var results:List<Category> = client.classify(toSend)
มีเพียง 2 หมวดหมู่ ได้แก่ False และ True
. (TensorFlow จะจัดเรียงตามตัวอักษร ดังนั้น False จะเป็นรายการ 0 และ True จะเป็นรายการ 1)
- หากต้องการดูคะแนนสำหรับความน่าจะเป็นที่ค่าจะเป็น
Trueคุณสามารถดู results[1].score ได้ดังนี้
val score = results[1].score
- เลือกค่าเกณฑ์ (ในกรณีนี้คือ 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()
}
- ดูการทำงานของโมเดลได้ที่นี่ ระบบแจ้งว่าข้อความ "เข้าบล็อกของฉันเพื่อซื้อของ" มีแนวโน้มสูงที่จะเป็นสแปม

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

7. อัปเดตแอป iOS เพื่อใช้โมเดล TensorFlow Lite
คุณสามารถรับโค้ดสำหรับสิ่งนี้ได้โดยทำตาม Codelab 1 หรือโดยการโคลนที่เก็บ นี้และโหลดแอปจาก TextClassificationStep1 คุณดูได้ในเส้นทาง TextClassificationOnMobile->iOS
คุณยังสามารถดูโค้ดที่เสร็จสมบูรณ์ได้ที่ TextClassificationStep2
ใน Codelab สร้างโมเดลแมชชีนเลิร์นนิงเพื่อตรวจจับความคิดเห็นที่เป็นสแปม คุณได้สร้างแอปที่เรียบง่ายมากซึ่งอนุญาตให้ผู้ใช้พิมพ์ข้อความลงใน UITextView และส่งไปยังเอาต์พุตโดยไม่มีการกรอง
ตอนนี้คุณจะอัปเดตแอปนั้นให้ใช้โมเดล TensorFlow Lite เพื่อตรวจหาสแปมในความคิดเห็นในข้อความก่อนที่จะส่ง เพียงจำลองการส่งในแอปนี้โดยการแสดงข้อความในป้ายกำกับเอาต์พุต (แต่แอปจริงอาจมีกระดานข่าว แชท หรือสิ่งที่คล้ายกัน)
หากต้องการเริ่มต้นใช้งาน คุณจะต้องมีแอปจากขั้นตอนที่ 1 ซึ่งคุณสามารถโคลนจากที่เก็บได้
หากต้องการรวม TensorFlow Lite คุณจะต้องใช้ CocoaPods หากยังไม่ได้ติดตั้ง ให้ทำตามวิธีการที่ https://cocoapods.org/
- เมื่อติดตั้ง 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 Maker คุณจะสามารถส่งออกโมเดล (เป็น model.tflite) และคำศัพท์ (เป็น vocab.txt) ได้
- โดยเพิ่มลงในโปรเจ็กต์ด้วยการลากและวางจาก Finder ลงในหน้าต่างโปรเจ็กต์ ตรวจสอบว่าได้เลือกเพิ่มไปยังเป้าหมายแล้ว

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

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

9. โหลดคำศัพท์
เมื่อทำการแยกประเภท NLP ระบบจะฝึกโมเดลด้วยคำที่เข้ารหัสเป็นเวกเตอร์ โมเดลจะเข้ารหัสคำด้วยชุดชื่อและค่าที่เฉพาะเจาะจงซึ่งเรียนรู้ได้เมื่อโมเดลได้รับการฝึก โปรดทราบว่าโมเดลส่วนใหญ่จะมีคำศัพท์ที่แตกต่างกัน และคุณควรใช้คำศัพท์สำหรับโมเดลที่สร้างขึ้นในขณะฝึก นี่คือไฟล์ vocab.txt ที่คุณเพิ่งเพิ่มลงในแอป
คุณเปิดไฟล์ใน Xcode เพื่อดูการเข้ารหัสได้ ระบบจะเข้ารหัสคำว่า "song" เป็น 6 และ "love" เป็น 12 ลำดับที่เห็นคือลำดับความถี่ ดังนั้น "I" จึงเป็นคำที่พบบ่อยที่สุดในชุดข้อมูล ตามด้วย "check"
เมื่อผู้ใช้พิมพ์คำ คุณจะต้องเข้ารหัสคำเหล่านั้นด้วยคำศัพท์นี้ก่อนส่งไปยังโมเดลเพื่อจัดประเภท
มาดูโค้ดนั้นกัน เริ่มต้นด้วยการโหลดคำศัพท์
- กำหนดตัวแปรระดับคลาสเพื่อจัดเก็บพจนานุกรม
var words_dictionary = [String : Int]()
- จากนั้นสร้าง
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")
}
}
- คุณเรียกใช้ได้โดยเรียกจากภายใน
viewDidLoadดังนี้
override func viewDidLoad() {
super.viewDidLoad()
txtInput.delegate = self
loadVocab()
}
10. เปลี่ยนสตริงเป็นลำดับโทเค็น
ผู้ใช้จะพิมพ์คำเป็นประโยคซึ่งจะกลายเป็นสตริง คำแต่ละคำในประโยคจะได้รับการเข้ารหัสเป็นค่าคีย์สำหรับคำนั้นตามที่กำหนดไว้ในคำศัพท์ หากมีอยู่ในพจนานุกรม
โดยปกติแล้ว โมเดล NLP จะยอมรับความยาวลำดับคงที่ มีข้อยกเว้นสำหรับโมเดลที่สร้างขึ้นโดยใช้ ragged tensors แต่โดยส่วนใหญ่แล้วคุณจะเห็นว่าปัญหาได้รับการแก้ไขแล้ว คุณระบุความยาวนี้เมื่อสร้างโมเดล ตรวจสอบว่าคุณใช้ความยาวเดียวกันในแอป iOS
ค่าเริ่มต้นใน Colab สำหรับ TensorFlow Lite Model Maker ที่คุณใช้ก่อนหน้านี้คือ 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 รวมถึงอินเทอร์พรีเตอร์ คุณจะได้รับสิทธิ์เข้าถึงประเภทเทนเซอร์
เริ่มเขียนโค้ดดังนี้ (ยังอยู่ในฟังก์ชัน classify func):
let tSequence = Array(sequence)
let myData = Data(copyingBufferOf: tSequence.map { Int32($0) })
let outputTensor: Tensor
ไม่ต้องกังวลหากได้รับข้อผิดพลาดใน copyingBufferOf เราจะนำฟีเจอร์นี้มาใช้เป็นส่วนขยายในภายหลัง
ตอนนี้ได้เวลาจัดสรรเทนเซอร์ในอินเทอร์พรีเตอร์ คัดลอกบัฟเฟอร์ข้อมูลที่คุณเพิ่งสร้างไปยังเทนเซอร์อินพุต แล้วเรียกใช้อินเทอร์พรีเตอร์เพื่อทำการอนุมาน
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
เรียกใช้และทดสอบแอป
หากทุกอย่างเป็นไปด้วยดี คุณควรเห็นแอปในอุปกรณ์ดังนี้

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