1. ข้อควรทราบก่อนที่จะเริ่มต้น
ใน Codelab นี้ คุณดูวิธีเรียกใช้การจําแนกประเภทข้อความจากแอป Flwer ที่มี TensorFlow Serving ผ่าน REST และ gRPC ได้
สิ่งที่ต้องมีก่อน
- ความรู้เบื้องต้นเกี่ยวกับการพัฒนา Flash ด้วย Dart
- ความรู้เบื้องต้นเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกอบรมเทียบกับการทําให้ใช้งานได้
- ความรู้เบื้องต้นเกี่ยวกับเทอร์มินัลและ Docker
- ฝึกโมเดลการตรวจจับสแปมความคิดเห็นด้วย Codelab การประมาณโมเดล TensorFlow Lite
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างแอป Flwer แบบง่ายและจัดประเภทข้อความผ่าน TensorFlow Serving (REST และ gRPC)
- วิธีแสดงผลลัพธ์ใน UI
สิ่งที่ต้องมี
- SDK ของ Flutter
- การตั้งค่า Android หรือ iOS สําหรับ Flitter
- การตั้งค่า Visual Studio Code (VS Code) สําหรับ Flitter และ Dart
- Docker
- Bash
- ปลั๊กอินบัฟเฟอร์บัฟเฟอร์โปรโตคอลและปลั๊กอิน gRPC Dart สําหรับคอมไพเลอร์โปรโตคอล (จําเป็นเมื่อคุณต้องการสร้างค่า sRPC อีกครั้งด้วยตนเอง)
2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์ Flash
ในการพัฒนาฟลัดไลท์ คุณต้องมีซอฟต์แวร์ 2 ชิ้นที่ต้องใช้ในห้องทดลองนี้ ซึ่งได้แก่ Flutter SDK และตัวแก้ไข
คุณเรียกใช้ Codelab ได้โดยใช้อุปกรณ์ใดก็ได้ต่อไปนี้
- เครื่องจําลอง iOS (ต้องติดตั้งเครื่องมือ Xcode)
- โปรแกรมจําลอง Android (ต้องตั้งค่าใน Android Studio)
- เบราว์เซอร์ (ต้องใช้ Chrome เพื่อแก้ไขข้อบกพร่อง)
- เป็นแอปพลิเคชันบนเดสก์ท็อป Windows, Linux หรือ macOS คุณต้องพัฒนาบนแพลตฟอร์มที่คุณวางแผนจะทําให้ใช้งานได้ ดังนั้นหากต้องการพัฒนาแอปบนเดสก์ท็อปของ Windows คุณต้องพัฒนาใน Windows เพื่อเข้าถึงเชนบิลด์ที่เหมาะสม มีข้อกําหนดด้านระบบปฏิบัติการที่เฉพาะเจาะจงซึ่งระบุไว้ใน docs.flwer.dev/desktop
3. ตั้งค่า
วิธีดาวน์โหลดโค้ดสําหรับ Codelab นี้
- ไปที่ที่เก็บ GitHub สําหรับ Codelab นี้
- คลิก Code > Download ZIP เพื่อดาวน์โหลดโค้ดทั้งหมดสําหรับ Codelab นี้
- แตกไฟล์ ZIP ที่ดาวน์โหลดเพื่อคลายโฟลเดอร์ราก
codelabs-main
ที่มีทรัพยากรทั้งหมดที่คุณต้องการ
Codelab นี้ต้องการเฉพาะไฟล์ในไดเรกทอรีย่อย tfserving-flutter/codelab2
ในที่เก็บ ซึ่งมี 2 โฟลเดอร์ดังนี้
- โฟลเดอร์
starter
มีโค้ดเริ่มต้นที่คุณสร้างสําหรับ Codelab นี้ - โฟลเดอร์
finished
มีโค้ดที่สมบูรณ์สําหรับแอปตัวอย่างที่สมบูรณ์
4. ดาวน์โหลดทรัพยากร Dependency สําหรับโปรเจ็กต์
- ใน VS Code ให้คลิก File > Openfolder แล้วเลือกโฟลเดอร์
starter
จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้ - หากคุณเห็นกล่องโต้ตอบที่แจ้งให้ดาวน์โหลดแพ็กเกจที่จําเป็นสําหรับแอปเริ่มต้น ให้คลิกรับแพ็กเกจ
- หากไม่เห็นกล่องโต้ตอบนี้ ให้เปิดเทอร์มินัลแล้วเรียกใช้คําสั่ง
flutter pub get
ในโฟลเดอร์starter
5. เรียกใช้แอปเริ่มต้น
- ใน VS Code ให้ตรวจสอบว่าตั้งค่าโปรแกรมจําลอง Android หรือ iOS Simulator อย่างถูกต้องและปรากฏในแถบสถานะ
ตัวอย่างเช่น ต่อไปนี้คือสิ่งที่คุณจะเห็นเมื่อใช้ Pixel 5 กับโปรแกรมจําลอง Android
สิ่งที่คุณจะเห็นเมื่อใช้ iPhone 13 กับเครื่องจําลอง iOS มีดังนี้
- คลิกเริ่มแก้ไขข้อบกพร่อง
เรียกใช้และสํารวจแอป
แอปควรเปิดตัวบนโปรแกรมจําลอง Android หรือ iOS Simulator UI มีความตรงไปตรงมา จะมีช่องข้อความที่อนุญาตให้ผู้ใช้พิมพ์ข้อความดังกล่าว ผู้ใช้สามารถเลือกว่าจะส่งข้อมูลไปยังแบ็กเอนด์ด้วย REST หรือ gRPC หรือไม่ แบ็กเอนด์ใช้โมเดล TensorFlow ในการแยกประเภทข้อความกับอินพุตที่มีการประมวลผลล่วงหน้าและแสดงผลผลการค้นหาการแยกประเภทในแอปไคลเอ็นต์ซึ่งจะอัปเดต UI
หากคุณคลิกแยกประเภท ไม่มีอะไรเกิดขึ้นเนื่องจากยังสื่อสารกับแบ็กเอนด์ไม่ได้
6. ทําให้โมเดลการจัดประเภทข้อความใช้งานได้ด้วยการแสดงผล TensorFlow
การแยกประเภทข้อความเป็นงานแมชชีนเลิร์นนิงที่ใช้กันทั่วไปและแยกประเภทข้อความออกเป็นหมวดหมู่ที่กําหนดไว้ล่วงหน้า ใน Codelab นี้ คุณจะต้องทําให้โมเดลที่ฝึกล่วงหน้าแล้วใช้งานได้จากฝึกโมเดลการตรวจจับสแปมด้วย TensorFlow Lite Model Makerlab ด้วย TensorFlow Serving และเรียกแบ็กเอนด์จากฟรอนท์เอนด์ของฟรอนท์เอนด์ให้แยกประเภทข้อความอินพุตเป็นสแปมหรือไม่ใช่สแปม
เริ่มแสดงโฆษณา TensorFlow
- ในเทอร์มินัล ให้เริ่มแสดงโฆษณา TensorFlow ด้วย Docker แต่แทนที่ตัวยึดตําแหน่ง
PATH/TO/SAVEDMODEL
ด้วยเส้นทางสัมบูรณ์ของโฟลเดอร์mm_spam_savedmodel
ในคอมพิวเตอร์
docker pull tensorflow/serving docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/spam-detection" -e MODEL_NAME=spam-detection tensorflow/serving
Docker จะดาวน์โหลดอิมเมจการแสดงผล TensorFlow โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น TensorFlow Serving ควรจะเริ่มแสดง บันทึกควรมีลักษณะเหมือนข้อมูลโค้ดนี้
2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle. 2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz 2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123 2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds. 2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests 2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: spam-detection version: 123} 2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models 2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled 2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ... [warn] getaddrinfo: address family for nodename not supported 2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ... [evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
7. ทําให้ข้อความที่ป้อนเป็นโทเค็น
แบ็กเอนด์พร้อมให้บริการแล้ว ตอนนี้คุณเกือบพร้อมที่จะส่งคําขอไคลเอ็นต์ไปยังการแสดงผล TensorFlow แล้ว แต่ก่อนอื่นคุณต้องเข้ารหัสประโยคอินพุตก่อน หากตรวจสอบ Tensor อินพุตของโมเดล คุณจะพบว่าโมเดลต้องการรายการจํานวนเต็ม 20 ตัวแทนที่จะเป็นสตริงดิบ การทําให้เป็นโทเค็นคือเมื่อคุณจับคู่คําที่พิมพ์ในแอปกับรายการจํานวนเต็มตามพจนานุกรม ก่อนที่จะส่งคําเหล่านั้นไปยังแบ็กเอนด์เพื่อจัดประเภท เช่น หากพิมพ์ buy book online to learn more
กระบวนการสร้างโทเค็นจะแมปกับ [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
ตัวเลขเฉพาะอาจแตกต่างกันไปตามพจนานุกรมคําศัพท์
- ในไฟล์
lib/main.dart
ให้เพิ่มโค้ดนี้ลงในเมธอดpredict()
เพื่อสร้างพจนานุกรมคําศัพท์_vocabMap
// Build _vocabMap if empty.
if (_vocabMap.isEmpty) {
final vocabFileString = await rootBundle.loadString(vocabFile);
final lines = vocabFileString.split('\n');
for (final l in lines) {
if (l != "") {
var wordAndIndex = l.split(' ');
(_vocabMap)[wordAndIndex[0]] = int.parse(wordAndIndex[1]);
}
}
}
- หลังข้อมูลโค้ดก่อนหน้า ให้เพิ่มโค้ดนี้เพื่อนําโทเค็นไปใช้:
// Tokenize the input sentence.
final inputWords = _inputSentenceController.text
.toLowerCase()
.replaceAll(RegExp('[^a-z ]'), '')
.split(' ');
// Initialize with padding token.
_tokenIndices = List.filled(maxSentenceLength, 0);
var i = 0;
for (final w in inputWords) {
if ((_vocabMap).containsKey(w)) {
_tokenIndices[i] = (_vocabMap)[w]!;
i++;
}
// Truncate the string if longer than maxSentenceLength.
if (i >= maxSentenceLength - 1) {
break;
}
}
โค้ดนี้เป็นตัวพิมพ์เล็กเป็นสตริงประโยค นําอักขระที่ไม่ใช่ตัวอักษรออก แล้วแมปคํากับดัชนีจํานวนเต็ม 20 รายการตามตารางคําศัพท์
8. เชื่อมต่อแอป Flใช้งานด้วย TensorFlow Serving ผ่าน REST
คุณส่งคําขอไปยังการแสดง TensorFlow ได้ 2 วิธีดังนี้
- REST
- gRPC
ส่งคําขอและรับการตอบกลับผ่าน REST
มี 3 ขั้นตอนง่ายๆ ในการส่งคําขอและรับการตอบกลับผ่าน REST
- สร้างคําขอ REST
- ส่งคําขอ REST ไปยังการแสดงผล TensorFlow
- ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ REST และแสดง UI
คุณทําตามขั้นตอนเหล่านี้ในไฟล์ main.dart
ได้
สร้างและส่งคําขอ REST ไปยังการแสดงโฆษณา TensorFlow
- ขณะนี้ฟังก์ชัน
predict()
ไม่ได้ส่งคําขอ REST ไปยังการแสดงผล TensorFlow คุณต้องใช้สาขา REST เพื่อสร้างคําขอ REST โดยทําดังนี้
if (_connectionMode == ConnectionModeType.rest) {
// TODO: Create and send the REST request.
}
- เพิ่มโค้ดนี้ลงในสาขา REST
//Create the REST request.
final response = await http.post(
Uri.parse('http://' +
_server +
':' +
restPort.toString() +
'/v1/models/' +
modelName +
':predict'),
body: jsonEncode(<String, List<List<int>>>{
'instances': [_tokenIndices],
}),
);
ประมวลผลการตอบกลับ REST จาก TensorFlow Serving
- เพิ่มโค้ดนี้หลังข้อมูลโค้ดก่อนหน้าเพื่อจัดการการตอบกลับ REST
// Process the REST response.
if (response.statusCode == 200) {
Map<String, dynamic> result = jsonDecode(response.body);
if (result['predictions']![0][1] >= classificationThreshold) {
return 'This sentence is spam. Spam score is ' +
result['predictions']![0][1].toString();
}
return 'This sentence is not spam. Spam score is ' +
result['predictions']![0][1].toString();
} else {
throw Exception('Error response');
}
โค้ดหลังการประมวลผลจะแยกความน่าจะเป็นที่ประโยคอินพุตเป็นข้อความสแปมออกจากการตอบกลับ และแสดงผลลัพธ์การแยกประเภทใน UI
เรียกใช้
- คลิกเริ่มแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด
- ป้อนข้อความแล้วเลือก REST > จัดประเภท
9. เชื่อมต่อแอป Flใช้งานด้วย TensorFlow Serving ผ่าน gRPC
นอกจาก REST แล้ว TensorFlow Serving ยังรองรับ gRPC อีกด้วย
gRPC เป็นเฟรมเวิร์ก Call Procedure Call (RPC) แบบโอเพนซอร์สที่มีประสิทธิภาพสูงและใช้งานได้กับทุกสภาพแวดล้อม เครื่องมือนี้จะเชื่อมบริการอย่างมีประสิทธิภาพทั่วทั้งศูนย์ข้อมูลต่างๆ ที่รองรับความสามารถในการจัดสรรภาระงาน การติดตาม การตรวจสอบประสิทธิภาพการทํางาน และการตรวจสอบสิทธิ์แบบเสียบปลั๊กได้ พบว่า gRPC มีประสิทธิภาพมากกว่า REST ในทางปฏิบัติ
ส่งคําขอและรับการตอบกลับด้วย gRPC
มี 4 ขั้นตอนง่ายๆ ในการส่งคําขอและรับการตอบกลับด้วย gRPC
- ไม่บังคับ: สร้างโค้ดไคลเอ็นต์ gRPC
- สร้างคําขอ gRPC
- ส่งคําขอ gRPC ไปยัง TensorFlow Serving
- ดึงผลลัพธ์ที่คาดการณ์ไว้จากการตอบกลับของ gRPC และแสดง UI
คุณทําตามขั้นตอนเหล่านี้ในไฟล์ main.dart
ได้
ไม่บังคับ: สร้างโค้ดไคลเอ็นต์ gRPC
หากต้องการใช้ gRPC กับการให้บริการ TensorFlow คุณต้องทําตามเวิร์กโฟลว์ gRPC ดูข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียดได้ที่เอกสารประกอบ gRPC
TensorFlow Serving และ TensorFlow จะกําหนดไฟล์ .proto
ให้คุณ เมื่อคํานึงถึง TensorFlow และ TensorFlow Serving 2.8 จึงต้องมีไฟล์ .proto
รายการต่อไปนี้
tensorflow/core/example/example.proto
tensorflow/core/example/feature.proto
tensorflow/core/protobuf/struct.proto
tensorflow/core/protobuf/saved_object_graph.proto
tensorflow/core/protobuf/saver.proto
tensorflow/core/protobuf/trackable_object_graph.proto
tensorflow/core/protobuf/meta_graph.proto
tensorflow/core/framework/node_def.proto
tensorflow/core/framework/attr_value.proto
tensorflow/core/framework/function.proto
tensorflow/core/framework/types.proto
tensorflow/core/framework/tensor_shape.proto
tensorflow/core/framework/full_type.proto
tensorflow/core/framework/versions.proto
tensorflow/core/framework/op_def.proto
tensorflow/core/framework/graph.proto
tensorflow/core/framework/tensor.proto
tensorflow/core/framework/resource_handle.proto
tensorflow/core/framework/variable.proto
tensorflow_serving/apis/inference.proto
tensorflow_serving/apis/classification.proto
tensorflow_serving/apis/predict.proto
tensorflow_serving/apis/regression.proto
tensorflow_serving/apis/get_model_metadata.proto
tensorflow_serving/apis/input.proto
tensorflow_serving/apis/prediction_service.proto
tensorflow_serving/apis/model.proto
google/protobuf/any.proto
google/protobuf/wrappers.proto
- จากนั้นไปที่โฟลเดอร์
starter/lib/proto/
แล้วสร้างเทอร์มินัลไปที่เทอร์มินัล
bash generate_grpc_stub_dart.sh
สร้างคําขอ gRPC
คุณสร้างคําขอ gRPC ใน gRPC ได้เช่นเดียวกับคําขอ REST
if (_connectionMode == ConnectionModeType.rest) {
} else {
// TODO: Create and send the gRPC request.
}
- เพิ่มโค้ดนี้เพื่อสร้างคําขอ gRPC ดังนี้
//Create the gRPC request.
final channel = ClientChannel(_server,
port: grpcPort,
options:
const ChannelOptions(credentials: ChannelCredentials.insecure()));
_stub = PredictionServiceClient(channel,
options: CallOptions(timeout: const Duration(seconds: 10)));
ModelSpec modelSpec = ModelSpec(
name: 'spam-detection',
signatureName: 'serving_default',
);
TensorShapeProto_Dim batchDim = TensorShapeProto_Dim(size: Int64(1));
TensorShapeProto_Dim inputDim =
TensorShapeProto_Dim(size: Int64(maxSentenceLength));
TensorShapeProto inputTensorShape =
TensorShapeProto(dim: [batchDim, inputDim]);
TensorProto inputTensor = TensorProto(
dtype: DataType.DT_INT32,
tensorShape: inputTensorShape,
intVal: _tokenIndices);
// If you train your own model, update the input and output tensor names.
const inputTensorName = 'input_3';
const outputTensorName = 'dense_5';
PredictRequest request = PredictRequest(
modelSpec: modelSpec, inputs: {inputTensorName: inputTensor});
หมายเหตุ: ชื่อ Tensor อินพุตและเอาต์พุตอาจแตกต่างกันไปในแต่ละรุ่น แม้ว่าสถาปัตยกรรมของโมเดลจะเหมือนกันก็ตาม อย่าลืมอัปเดตโมเดลหากคุณฝึกโมเดลของคุณเอง
ส่งคําขอ gRPC ไปยังการแสดงผล TensorFlow
- เพิ่มโค้ดนี้หลังจากข้อมูลโค้ดก่อนหน้าเพื่อส่งคําขอ gRPC ไปที่บริการ TensorFlow
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);
ประมวลผลการตอบสนอง gRPC จาก TensorFlow Serving
- เพิ่มโค้ดนี้หลังข้อมูลโค้ดก่อนหน้าเพื่อใช้ฟังก์ชันเรียกกลับเพื่อจัดการการตอบกลับ
// Process the response.
if (response.outputs.containsKey(outputTensorName)) {
if (response.outputs[outputTensorName]!.floatVal[1] >
classificationThreshold) {
return 'This sentence is spam. Spam score is ' +
response.outputs[outputTensorName]!.floatVal[1].toString();
} else {
return 'This sentence is not spam. Spam score is ' +
response.outputs[outputTensorName]!.floatVal[1].toString();
}
} else {
throw Exception('Error response');
}
ตอนนี้โค้ดหลังการประมวลผลจะแยกผลลัพธ์ที่ได้จากการตอบกลับ และแสดงใน UI
เรียกใช้
- คลิกเริ่มแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด
- ป้อนข้อความแล้วเลือก gRPC > จัดประเภท
10. ยินดีด้วย
คุณใช้ TensorFlow Serving เพื่อเพิ่มความสามารถในการจัดประเภทข้อความในแอปแล้ว
ใน Codelab ถัดไป คุณจะปรับปรุงโมเดลเพื่อให้ตรวจจับข้อความสแปมแบบเจาะจงที่แอปปัจจุบันตรวจไม่พบ