אפשר ליצור אפליקציה של Flutter כדי לסווג טקסטים

1. לפני שמתחילים

בשיעור ה-Lab הזה תלמדו איך להריץ מסקנות לסיווג טקסט באמצעות אפליקציה של Fluter עם הצגת TensorFlow דרך REST ו-gRPC.

דרישות מוקדמות

מה תלמדו

  • איך לבנות אפליקציה פשוטה של Flutter ולסווג טקסטים באמצעות TensorFlow הגשה (REST ו-gRPC).
  • איך להציג את התוצאות בממשק המשתמש.

מה תצטרך להכין

2. הגדרת סביבת הפיתוח של Flutter

כדי לפתח את Fluter, תצטרכו שתי תוכנות כדי להשלים את שיעור ה-Lab הזה - Fluter SDK ו-Editor.

ניתן להריץ את קוד Lab באמצעות אחד מהמכשירים הבאים:

  • הסימולטור של iOS (נדרש התקנה של כלי Xcode).
  • האמולטור של Android (נדרש הגדרה ב-Android Studio).
  • דפדפן (כדי לנפות באגים צריך להשתמש ב-Chrome).
  • כאפליקציה של Windows , Linux או macOS. עליכם לפתח בפלטפורמה שבה אתם מתכננים לפרוס. לכן, אם ברצונך לפתח אפליקציה ל-Windows Desktop, עליך לפתח ב-Windows כדי לגשת לשרשרת הבנייה המתאימה. הדרישות הספציפיות למערכת הפעלה מפורטות במאמר docs.flutter.dev/desktop.

3. להגדרה

כדי להוריד את הקוד של Lab Lab זה:

  1. עוברים אל מאגר GitHub עבור מעבדת קוד זו.
  2. לוחצים על Code > הורדת zip כדי להוריד את כל הקוד של מעבדת הקוד הזו.

2cd45599f51fb8a2.png

  1. יש לבטל את הדחיסה של קובץ ה-ZIP שהורדת כדי לפתוח את תיקיית הבסיס של codelabs-main עם כל המשאבים הדרושים.

ב-codelab זה נדרשים רק הקבצים בספריית המשנה tfserving-flutter/codelab2 במאגר, המכיל שתי תיקיות:

  • התיקייה starter מכילה את הקוד למתחילים שעליו כדאי לבנות את מעבדת הקוד הזו.
  • התיקייה finished מכילה את הקוד המלא לאפליקציה לדוגמה שהושלמה.

4. להוריד את התלות של הפרויקט

  1. בקוד VS, לוחצים על קובץ > פתיחת תיקייה ולאחר מכן בוחרים את התיקייה starter בקוד המקור שהורדתם בעבר.
  2. אם מופיעה תיבת דו-שיח שבה מתבקשים להוריד את החבילות הדרושות לאפליקציה למתחילים, לוחצים על קבלת חבילות.
  3. אם תיבת הדו-שיח לא מופיעה, יש לפתוח את המסוף ואז להריץ את הפקודה flutter pub get בתיקייה starter.

7ada07c300f166a6.png

5. הפעלת האפליקציה למתחילים

  1. בקוד VS, מוודאים שהאמולטור של Android או הסימולטור של iOS מוגדר כראוי ומופיע בשורת הסטטוס.

לדוגמה, מה שמוצג כשמשתמשים ב-Pixel 5 עם אמולטור Android:

9767649231898791.png

זה מה שמוצג בעת שימוש ב-iPhone 13 עם סימולטור iOS:

95529e3a682268b2.png

  1. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים.

הרצה ועיון באפליקציה

יש להפעיל את האפליקציה באמולטור Android או בסימולטור iOS. ממשק המשתמש פשוט למדי. יש שדה טקסט שמאפשר למשתמש להקליד את הטקסט. המשתמשים יכולים לבחור אם לשלוח את הנתונים לקצה העורפי באמצעות REST או gRPC. הקצה העורפי משתמש במודל TensorFlow כדי לבצע סיווג של טקסט בקלט מעובד מראש ומחזיר את תוצאת הסיווג לאפליקציית הלקוח, שמעדכנת את ממשק המשתמש.

b298f605d64dc132.png d3ef3ccd3c3331188png

אם לוחצים על סיווג, לא יקרה דבר כי עדיין לא ניתן לתקשר עם הקצה העורפי.

6. פריסת מודל של סיווג טקסט באמצעות TensorFlow serving

סיווג טקסט הוא משימה נפוצה מאוד בתחום הלמידה החישובית. הסיווג הזה מסווג את הטקסטים בקטגוריות מוגדרות מראש. ב-codelab הזה, אתם פורסים את המודל המיומן מראש מאימון מודל לזיהוי ספאם באמצעות תגובות עם הקוד של TensorFlow Lite Maker Maker, באמצעות קריאה ל-TenororFlow וקורא את הקצה העורפי של Flutter של ממשק הקצה, כדי לסווג את הטקסט שהזנת כספאם או כלא ספאם.

התחלת הצגה של TensorFlow

  • במסוף, מפעילים את TensorFlow serving עם Docker, אבל מחליפים את ה-placeholder 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

אביזר העגינה מוריד תחילה באופן אוטומטי את התמונה של TensorFlow serving. לאחר מכן, ההצגה של TensorFlow אמורה להתחיל. היומן אמור להיראות כמו קטע קוד זה:

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 serving, אבל קודם צריך לתת אסימון למשפט הקלט. אם תבדקו את טנור הקלט של המודל, תוכלו לראות שהוא מצפה לרשימה של 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]. המספרים הספציפיים עשויים להשתנות בהתאם למילון המונחים.

  1. בקובץ 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]);
    }
  }
} 
  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. חיבור של האפליקציה Flutter עם TensorFlow serving דרך REST

יש שתי דרכים לשלוח בקשות ל-TensorFlow serving:

  • REST
  • gRPC

שליחת בקשות וקבלת תשובות דרך REST

יש שלושה שלבים פשוטים לשליחת בקשות ולקבלת תשובות דרך REST:

  1. יוצרים את הבקשה ל-REST.
  2. שליחת בקשת REST להגשה של TensorFlow.
  3. מחלצים את התוצאה החזויה מתגובת ה-REST ומעבדים את ממשק המשתמש.

יש להשלים את השלבים האלה בקובץ main.dart.

יצירה ושליחה של בקשת REST ל-TensorFlow serving

  1. נכון לעכשיו, הפונקציה predict() לא שולחת את הבקשה ל-REST להצגת TensorFlow. כדי ליצור בקשת REST, צריך להטמיע את הסניף של REST:
if (_connectionMode == ConnectionModeType.rest) {
  // TODO: Create and send the REST request.

}
  1. מוסיפים את הקוד הזה לסניף של 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');
}

הקוד שמופיע לאחר העיבוד עובד ומחליק את ההסתברות שמשפט הקלט הוא הודעת ספאם מהתגובה, ומציג את תוצאת הסיווג בממשק המשתמש.

הפעלה

  1. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים וממתינים לטעינה של האפליקציה.
  2. מזינים טקסט ובוחרים באפשרות REST > Classification.

8e21d795af36d07a.png e79a0367a03c2169.png

9. חיבור של אפליקציית Flutter עם TensorFlow serving דרך gRPC

בנוסף ל-REST, שירות TensorFlow תומך גם ב-gRPC.

b6f4449c2c850b0e.png

gRPC היא מסגרת מודרנית ומודרנית של ביצועים טובים (RTT) שניתן להפעיל בכל סביבה. הוא יכול לחבר שירותים ביעילות למרכזי נתונים, ובהם בתמיכה, לאיזון עומסים, למעקב אחר נתונים, לבדיקת תקינות ולאימות. התגלה ש-gRPC מניב ביצועים טובים יותר בהשוואה ל-REST בפועל.

שליחה של בקשות וקבלת תשובות באמצעות gRPC

יש ארבעה שלבים פשוטים לשליחת בקשות ולקבלת תשובות באמצעות gRPC:

  1. אופציונלי: יצירת קוד stub של לקוח gRPC.
  2. יוצרים את בקשת ה-gRPC.
  3. שליחת בקשת gRPC לשירות TensorFlow.
  4. מחלצים את התוצאה החזויה מתגובת ה-gRPC ומעבדים את ממשק המשתמש.

יש להשלים את השלבים האלה בקובץ main.dart.

אופציונלי: יצירת קוד stub של לקוח gRPC

כדי להשתמש ב-gRPC עם TensorFlow serving, יש לפעול לפי תהליך העבודה של gRPC. למידע נוסף, ניתן לעיין בתיעוד של gRPC.

a9d0e5cb543467b4.png

TensorFlow הגשה ו-TensorFlow מגדירים את קובצי .proto עבורך. נכון ל-TensorFlow ול-TensorFlow 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

בדומה לבקשת ה-REST, יוצרים את בקשת gRPC בסניף gRPC.

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

הערה: שמות האמצעים לקלט ולפלט יכולים להיות שונים מהמודל, גם אם ארכיטקטורת המודלים זהה. הקפידו לעדכן אותם אם אתם מאמנים את המודל שלכם.

שליחת בקשת 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');
}

עכשיו הקוד אחרי העיבוד מחלץ את תוצאת הסיווג מהתגובה ומציג אותה בממשק המשתמש.

הפעלה

  1. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים וממתינים לטעינה של האפליקציה.
  2. מזינים טקסט ובוחרים באפשרות gRPC > Classification.

e44e6e9a5bde2188.png 92644d723f61968c.png

10. מזל טוב

השתמשת ב-TensorFlow serving כדי להוסיף לאפליקציה יכולות של סיווג טקסט!

באתגר הקוד הבא, תשפרו את המודל כך שתוכלו לזהות הודעות ספאם ספציפיות שהאפליקציה הנוכחית לא יכולה לזהות.

מידע נוסף