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 ของโค้ดแล็บนี้ และโมเดลมีให้ที่นี่
เพิ่มลงในโปรเจ็กต์โดยสร้างไดเรกทอรีชิ้นงาน
- ใช้เครื่องมือนำทางโปรเจ็กต์ ตรวจสอบว่าได้เลือก Android ที่ด้านบนแล้ว
- คลิกขวาที่โฟลเดอร์ app เลือกใหม่ > ไดเรกทอรี
- ในกล่องโต้ตอบไดเรกทอรีใหม่ ให้เลือก src/main/assets
คุณจะเห็นโฟลเดอร์ assets ใหม่ในแอป
- คลิกขวาที่ชิ้นงาน
- ในเมนูที่เปิดขึ้น คุณจะเห็นแสดงใน Finder (บน Mac) เลือกแอป (ใน Windows จะระบุว่า Show in Explorer ส่วนใน Ubuntu จะระบุว่า Show in Files)
Finder จะเปิดขึ้นเพื่อแสดงตำแหน่งไฟล์ (File Explorer ใน Windows, Files ใน Linux)
- คัดลอกไฟล์
labels.txt
,model.tflite
และvocab
ไปยังไดเรกทอรีนี้
- กลับไปที่ Android Studio แล้วคุณจะเห็นไฟล์ดังกล่าวอยู่ในโฟลเดอร์ assets
4. อัปเดต build.gradle เพื่อใช้ TensorFlow Lite
หากต้องการใช้ TensorFlow Lite และไลบรารีงาน TensorFlow Lite ที่รองรับ คุณจะต้องอัปเดตไฟล์ build.gradle
โปรเจ็กต์ Android มักจะมีมากกว่า 1 โปรเจ็กต์ ดังนั้นอย่าลืมหาระดับแอปที่ 1 ในโปรแกรมสำรวจโปรเจ็กต์ในมุมมอง Android ให้ค้นหาโปรเจ็กต์ในส่วน Gradle Scripts ไฟล์ที่ถูกต้องจะมีป้ายกำกับเป็น .app ดังที่แสดงที่นี่
คุณจะต้องทำการเปลี่ยนแปลง 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
ตอนนี้คุณมี Dependency ทั้งหมดแล้ว ถึงเวลาเริ่มเขียนโค้ด
5. เพิ่มชั้นเรียนผู้ช่วยเหลือ
หากต้องการแยกตรรกะการอนุมานที่แอปใช้โมเดลออกจากอินเทอร์เฟซผู้ใช้ ให้สร้างคลาสอื่นเพื่อจัดการการอนุมานโมเดล เรียกชั้นเรียนนี้ว่า "ผู้ช่วย"
- คลิกขวาที่ชื่อแพ็กเกจที่มีรหัส
MainActivity
- เลือกใหม่ > แพ็กเกจ
- คุณจะเห็นกล่องโต้ตอบที่ตรงกลางของหน้าจอเพื่อขอให้คุณป้อนชื่อแพ็กเกจ เพิ่มต่อท้ายชื่อแพ็กเกจปัจจุบัน (ในที่นี้เรียกว่า helpers)
- เมื่อดำเนินการเสร็จแล้ว ให้คลิกขวาที่โฟลเดอร์ helpers ใน Project Explorer
- เลือกใหม่ > Java Class และตั้งชื่อว่า
TextClassificationClient
คุณจะได้แก้ไขไฟล์ในขั้นตอนถัดไป
คลาสตัวช่วย TextClassificationClient
จะมีลักษณะดังนี้ (แม้ว่าชื่อแพ็กเกจอาจแตกต่างออกไป)
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
ที่แสดงผลจะมีความน่าจะเป็นเหล่านี้ คุณจะแยกวิเคราะห์ส่วนนั้นในภายหลัง
เมื่อคุณมีคลาสตัวช่วยแล้ว ให้กลับไปที่ MainActivity
แล้วอัปเดตเพื่อใช้คลาสนี้ในการจัดประเภทข้อความ คุณจะเห็นข้อมูลดังกล่าวในขั้นตอนถัดไป
6. จำแนกประเภทข้อความ
ใน MainActivity
คุณจะต้องนําเข้าตัวช่วยที่เพิ่งสร้างขึ้นก่อน
- ที่ด้านบนของ
MainActivity.kt
ให้เพิ่มข้อมูลต่อไปนี้พร้อมกับการนําเข้าอื่นๆ
import com.google.devrel.textclassificationstep2.helpers.TextClassificationClient
import org.tensorflow.lite.support.label.Category
- ขั้นตอนถัดไปคือการโหลดตัวช่วย ใน
onCreate
ให้เพิ่มบรรทัดต่อไปนี้ต่อจากบรรทัด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 ซึ่งคุณโคลนได้จากที่เก็บ
คุณจะต้องใช้ CocoaPods เพื่อรวม TensorFlow Lite หากยังไม่ได้ติดตั้ง ให้ทำตามวิธีการที่ 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.tflite
) และคำศัพท์ (เป็น vocab.txt
) ได้
- เพิ่มลงในโปรเจ็กต์โดยลากและวางจาก Finder ลงในหน้าต่างโปรเจ็กต์ ตรวจสอบว่าได้เลือกเพิ่มลงในเป้าหมายแล้ว
เมื่อทําเสร็จแล้ว คุณจะเห็นรายการต่อไปนี้ในโปรเจ็กต์
- ตรวจสอบอีกครั้งว่าได้เพิ่มลงใน Bundle แล้ว (เพื่อให้นำไปใช้งานในอุปกรณ์ได้) โดยเลือกโปรเจ็กต์ (ในภาพหน้าจอด้านบนคือไอคอนสีน้ำเงิน TextClassificationStep2) และดูที่แท็บระยะการสร้าง
9. โหลดคำศัพท์
เมื่อทำการจำแนกประเภท NLP โมเดลจะได้รับการฝึกด้วยคำที่เข้ารหัสเป็นเวกเตอร์ โมเดลจะเข้ารหัสคําด้วยชุดชื่อและค่าที่เฉพาะเจาะจงซึ่งเรียนรู้ขณะที่โมเดลได้รับการฝึก โปรดทราบว่าโมเดลส่วนใหญ่จะมีคําศัพท์ต่างกัน และคุณต้องใช้คําศัพท์สําหรับโมเดลที่สร้างขึ้นขณะฝึก นี่คือไฟล์ vocab.txt
ที่คุณเพิ่งเพิ่มลงในแอป
คุณสามารถเปิดไฟล์ใน Xcode เพื่อดูการเข้ารหัสได้ คําอย่าง "เพลง" จะเข้ารหัสเป็น 6 และ "รัก" เป็น 12 ลําดับนี้เป็นลําดับความถี่ ดังนั้น "ฉัน" จึงเป็นคําที่พบบ่อยที่สุดในชุดข้อมูล ตามด้วย "ตรวจสอบ"
เมื่อผู้ใช้พิมพ์คำ คุณจะต้องเข้ารหัสคำเหล่านั้นด้วยคําศัพท์นี้ก่อนที่จะส่งไปยังโมเดลเพื่อจัดประเภท
มาดูโค้ดนี้กัน เริ่มด้วยการโหลดคำศัพท์
- กำหนดตัวแปรระดับคลาสเพื่อจัดเก็บพจนานุกรม
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 ที่คุณใช้ก่อนหน้านี้คือ 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
เรียกใช้และทดสอบแอป
หากทุกอย่างเรียบร้อยดี คุณควรเห็นแอปในอุปกรณ์ดังต่อไปนี้
เมื่อส่งข้อความ "ซื้อหนังสือของฉันเพื่อเรียนรู้การซื้อขายออนไลน์" แอปจะส่งการแจ้งเตือนที่ตรวจพบสแปมกลับพร้อมความน่าจะเป็น 0 .99%
14. ยินดีด้วย
ตอนนี้คุณสร้างแอปง่ายๆ ที่กรองข้อความเพื่อหาสแปมความคิดเห็นโดยใช้โมเดลที่ผ่านการฝึกด้วยข้อมูลที่ใช้สแปมบล็อกแล้ว
ขั้นตอนถัดไปในวงจรชีวิตของนักพัฒนาซอฟต์แวร์โดยทั่วไปคือการสำรวจสิ่งที่ต้องทำในการปรับแต่งโมเดลจากข้อมูลที่พบในชุมชนของคุณ คุณจะเห็นวิธีดำเนินการดังกล่าวในกิจกรรมเส้นทางถัดไป