יצירת אפליקציה ל-iOS כדי לחזות ערכים

יצירת אפליקציה ל-iOS כדי לחזות ערכים

מידע על Codelab זה

subjectהעדכון האחרון: אפר׳ 8, 2022
account_circleנכתב על ידי Wei Wei

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

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

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

  • ידע בסיסי בפיתוח iOS עם Swift
  • ידע בסיסי על למידה חישובית עם TensorFlow, כמו הדרכה ופריסה
  • ידע בסיסי בנושא Colaboratory
  • ידע בסיסי בנוגע למסופים, ל-Python ול-Docker

מה תלמדו

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

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

2.‏ להגדרה

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

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

a72f2bb4caa9a96.png

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

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

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

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

הורדת ה-pods הדרושים

  • בתיקייה starter/iOS, יש להריץ:
pod install

Cocoapods יתקין את כל הספריות הדרושות וייצור קובץ regression.xcworkspace חדש.

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

  • יש ללחוץ לחיצה כפולה על הקובץ regression.xcworkspace כדי לפתוח את Xcode.

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

  1. משנים את יעד המכשיר לכל מכשיר iPhone, כמו iPhone 13.

a57198a4f21f970.png

  1. לוחצים על cacc15c5638260ed.png ‘Run' ומחכים ש-Xcode ירכיב את הפרויקט ויפעיל את האפליקציה למתחילים בסימולטור.

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

d2976072474ce0b1.png

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

5.‏ אימון מודל רגרסיה פשוט עם TensorFlow

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

אימון מודל רגרסיה

  1. יש לפתוח את הקישור הזה בדפדפן.

Colab טוען את הפנקס של Python.

  1. בפנקס של Python, מייבאים את הספריות TensorFlow ו-NumPy ואז יוצרים שישה זוגות של נתוני אימונים עם xs כקלט ו-ys כתוויות.

אם מציגים את הנקודות על הגרף, הן למעשה ממוקמות בקו ישר כי הן נוצרות ממשוואה y = 2x -1.

56d05252cfc9df9d.png

  1. להשתמש ב-Keras API כדי ליצור רשת נוירונים פשוטה דו-שכבתית כדי לחזות את הערך y על סמך הקלט x, ולאחר מכן להרכיב ולהתאים את המודל.
xs = np.array([-1.0,  0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys
= np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model
= tf.keras.Sequential([
   tf
.keras.layers.Dense(units=10, input_shape=[1]),
   tf
.keras.layers.Dense(units=1),
   
])

model
.compile(optimizer='sgd',
             loss
='mean_squared_error')

history
= model.fit(xs, ys, epochs=500, verbose=0)

print("Finished training the model")

print(model.predict([10.0]))

המודל לוקח מספר שניות, וניתן לראות את הערך החזוי של קלט 10 הוא 18.999996, שהוא חיזוי טוב למדי מאחר שאמת הקרקע היא 2 * 10 -1 = 19.

  1. ייצוא המודל:
model_dir = './regression/'
version
= 123
export_path
= os.path.join(model_dir, str(version))
model
.save(export_path, save_format="tf")
print('\nexport_path = {}'.format(export_path))
!ls -l {export_path}
  1. יש ליצור כיווץ של המודל השמור שמיוצא לקובץ regression.zip יחיד:
!zip -r regression.zip ./regression
  1. לוחצים על Runtime > Run all בתפריט ההפעלה כדי להריץ את הפנקס ואז ממתינים עד לסיום ההפעלה.
  2. לוחצים על c55600d42359f901.png קבצים ואז מורידים את הקובץ regression.zip.

bceda15d86571583.png

6.‏ פריסת מודל רגרסיה באמצעות TensorFlow serving

  • כדי לפרוס את המודל ב-TensorFlow הגשה, יש לבטל את הדחיסה של קובץ ה-regression.zip שהורדת באמצעות כלי לביטול הדחיסה, כמו 7-Zip.

מבנה התיקייה אמור להיראות כך:

7faeb4f03af39646.png

אפשר להתייחס לתיקייה regression כתיקייה של SavedModel. 123 הוא מספר גרסה לדוגמה. אפשר לבחור מספר אחר.

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

  • במסוף, מפעילים את TensorFlow serving עם Docker, אבל מחליפים את ה-placeholder PATH/TO/SAVEDMODEL בנתיב המוחלט של תיקיית regression במחשב.
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/regression" -e MODEL_NAME=regression 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: regression 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.‏ חיבור של אפליקציית iOS עם TensorFlow serving דרך REST

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

  • REST
  • gRPC

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

יש שלושה שלבים פשוטים:

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

עליך להשיג את השלבים האלה בקובץ iOS/regression/ViewController.swift.

יצירה של בקשת REST

  1. נכון לעכשיו, הפונקציה doInference() לא שולחת את הבקשה ל-REST להצגת TensorFlow. כדי ליצור בקשת REST, יש להטמיע את הסניף של REST:
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
   
print("Using REST")
   
// TODO: Add code to send a REST request to TensorFlow Serving.
   
}

בשירות TensorFlow יש בקשת POST שמכילה ערך יחיד, ולכן עליכם להטמיע את ערך הקלט בקובץ JSON, שהוא המטען הייעודי של הבקשה.

  1. מוסיפים את הקוד הזה לסניף של REST:
//Create the REST request.
let json
: [String: Any] = ["signature_name" : "serving_default", "instances" : [[value]]]

let jsonData
= try? JSONSerialization.data(withJSONObject: json)

let url
= URL(string: "http://localhost:8501/v1/models/regression:predict")!
var request = URLRequest(url: url)
request
.httpMethod = "POST"

// Insert JSON data into the request.
request
.httpBody = jsonData

שליחת בקשת REST להצגת TensorFlow

  • מוסיפים את הקוד הזה מיד אחרי הקוד בסניף של REST:
// Send the REST request.
let task
= URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data
= data, error == nil else {
       
print(error?.localizedDescription ?? "No data")
       
return
   
}
   
   
// TODO: Add code to process the response.
}

task
.resume()

עיבוד התגובה ל-REST מ-TensorFlow serving

  • יש להוסיף את הקוד לקטע הקוד הקודם מיד לאחר התגובה TODO: Add code to process the response.:
// Process the REST response.
let results
: RESTResults = try! JSONDecoder().decode(RESTResults.self, from: data)
DispatchQueue.main.async{
   
self.txtOutput.text = String(results.predictions[0][0])
}

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

הפעלה

  1. לוחצים על cacc15c5638260ed.png ‘Run' ומחכים ש-Xcode יפעיל את האפליקציה בסימולטור.
  2. מזינים מספר בתיבת הטקסט ולוחצים על מסקנות.

עכשיו מופיע ערך חזוי בממשק המשתמש.

df9bcb9aa21bb30e.png

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

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

b6f4449c2c850b0e.png

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

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

יש ארבעה שלבים פשוטים:

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

עליך להשיג את השלבים האלה בקובץ iOS/regression/ViewController.swift.

אופציונלי: יצירת קוד 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

כדי ליצור את קוד הברכה של לקוח gRPC:

  1. במסוף שלך, עליך להיכנס לתיקייה starter/src/proto/ וליצור את ה-stub:
bash generate_grpc_stub_swift.sh

מספר .swift קבצים נוצרים בתיקייה starter/src/proto/generated/import.

  1. אם הם עדיין לא מועתקים לפרויקט, גוררים את כל קובצי .swift שנוצרו לפרויקט ב-Xcode.

9e65705cf6be7aac.png

יצירת בקשת gRPC

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

if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
   
}
else {
   
print("Using gRPC")
   
// TODO: add code to send a gRPC request to TF Serving
   
}
  • כדי ליצור את בקשת ה-gRPC, מוסיפים את הקוד לסניף של gRPC:
//Create the gRPC request.
let
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let channel
= ClientConnection.insecure(group: group).connect(host: "localhost", port: 8500)
let stub
= Tensorflow_Serving_PredictionServiceClient(channel: channel)

var modelSpec = Tensorflow_Serving_ModelSpec()
modelSpec
.name = "regression"
modelSpec
.signatureName = "serving_default"

// Prepare the input tensor.
var batchDim = Tensorflow_TensorShapeProto.Dim()
batchDim
.size = 1
var inputDim = Tensorflow_TensorShapeProto.Dim()
inputDim
.size = 1
var inputTensorShape = Tensorflow_TensorShapeProto()
inputTensorShape
.dim = [batchDim, inputDim]
var inputTensor = Tensorflow_TensorProto()
inputTensor
.dtype = Tensorflow_DataType.dtFloat
inputTensor
.tensorShape = inputTensorShape
inputTensor
.floatVal = [Float(value)]

var request = Tensorflow_Serving_PredictRequest()
request
.modelSpec = modelSpec
request
.inputs = ["dense_input" : inputTensor]

let callOptions
= CallOptions(timeLimit: .timeout(.seconds(15)))

שליחת בקשת gRPC לשירות TensorFlow

  • מוסיפים את הקוד לסניף gRPC מיד אחרי הקוד בקטע הקוד הקודם:
// Send the gRPC request.
let call
= stub.predict(request, callOptions: callOptions)

מעבד את תגובת ה-gRPC מ-TensorFlow serving

  • מוסיפים את הקוד הזה מייד אחרי הקוד בקטע הקוד הקודם:
// Process the response.
call
.response.whenSuccess { response in
    let result
= response.outputs["dense_1"]?.floatVal[0]
   
DispatchQueue.main.async{
       
self.txtOutput.text = String(describing: result!)
   
}
}
call
.response.whenFailure { error in
   
print("Call failed with error\n\(error)")
}

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

הפעלה

  1. לוחצים על cacc15c5638260ed.png ‘Run' בתפריט הניווט ומחכים ש-Xcode יפעיל את האפליקציה בסימולטור.
  2. מזינים מספר בתיבת הטקסט ולוחצים על מסקנות.

עכשיו מופיע ערך חזוי בממשק המשתמש.

9.‏ מזל טוב

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

מידע נוסף