מידע על Codelab זה
1. לפני שמתחילים
בשיעור ה-Lab הזה תלמדו איך להריץ מסית רגרסיה מאפליקציה ל-iOS באמצעות TensorFlow serving עם REST ו-gRPC.
דרישות מוקדמות
- ידע בסיסי בפיתוח iOS עם Swift
- ידע בסיסי על למידה חישובית עם TensorFlow, כמו הדרכה ופריסה
- ידע בסיסי בנושא Colaboratory
- ידע בסיסי בנוגע למסופים, ל-Python ול-Docker
מה תלמדו
- איך לאמן מודל רגרסיה באמצעות TensorFlow.
- איך לבנות אפליקציה פשוטה ל-iOS ולבצע חיזויים באמצעות המודל המיומן באמצעות הצגת TensorFlow (REST ו-gRPC).
- איך להציג את התוצאה בממשק המשתמש.
מה תצטרך להכין
- גישה ל-Colab
- הגרסה האחרונה של Xcode
- CocoaPods
- אביזר עגינה
- שיט
- מהדר protocol buffer (נדרש רק אם רוצים ליצור מחדש את סקר ה-gRPC בעצמך)
- פלאגין מחולל קוד gRPC-swift (נדרש רק אם רוצים ליצור את פס ההזזה של gRPC בעצמכם)
2. להגדרה
כדי להוריד את הקוד של Lab Lab זה:
- עוברים אל מאגר GitHub עבור מעבדת קוד זו.
- לוחצים על Code > הורדת zip כדי להוריד את כל הקוד של מעבדת הקוד הזו.
- יש לבטל את הדחיסה של קובץ ה-ZIP שהורדת כדי לפתוח את תיקיית הבסיס של
codelabs
עם כל המשאבים הנחוצים.
ב-codelab זה נדרשים רק הקבצים בספריית המשנה TFServing/RegressioniOS
במאגר, המכיל שתי תיקיות:
- התיקייה
starter
מכילה את הקוד למתחילים שעליו כדאי לבנות את מעבדת הקוד הזו. - התיקייה
finished
מכילה את הקוד המלא לאפליקציה לדוגמה שהושלמה.
3. להוריד את התלות של הפרויקט
הורדת ה-pods הדרושים
- בתיקייה
starter/iOS
, יש להריץ:
pod install
Cocoapods יתקין את כל הספריות הדרושות וייצור קובץ regression.xcworkspace
חדש.
4. הפעלת האפליקציה למתחילים
- יש ללחוץ לחיצה כפולה על הקובץ
regression.xcworkspace
כדי לפתוח את Xcode.
הרצה ועיון באפליקציה
- משנים את יעד המכשיר לכל מכשיר iPhone, כמו iPhone 13.
- לוחצים על
‘Run' ומחכים ש-Xcode ירכיב את הפרויקט ויפעיל את האפליקציה למתחילים בסימולטור.
ממשק המשתמש פשוט למדי. יש תיבת טקסט שבה ניתן להקליד מספר, שיישלח לקצה העורפי של TensorFlow באמצעות REST או gRPC. הקצה העורפי מבצע רגרסיה בערך הקלט ומחזיר את הערך החזוי לאפליקציית הלקוח, שמציגה את התוצאה בממשק המשתמש שוב.
אם מזינים מספר ולוחצים על סיכום, לא יקרה דבר כי האפליקציה עדיין לא יכולה לתקשר עם הקצה העורפי.
5. אימון מודל רגרסיה פשוט עם TensorFlow
רגרסיה היא אחת ממשימות ה-ML הנפוצות ביותר. מטרתו היא לחזות כמות רציפה אחת על סמך הקלט. לדוגמה, על סמך מזג האוויר היום, ניתן לחזות את הטמפרטורה הגבוהה ביותר מחר.
אימון מודל רגרסיה
- יש לפתוח את הקישור הזה בדפדפן.
Colab טוען את הפנקס של Python.
- בפנקס של Python, מייבאים את הספריות
TensorFlow
ו-NumPy
ואז יוצרים שישה זוגות של נתוני אימונים עםxs
כקלט ו-ys
כתוויות.
אם מציגים את הנקודות על הגרף, הן למעשה ממוקמות בקו ישר כי הן נוצרות ממשוואה y = 2x -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.
- ייצוא המודל:
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}
- יש ליצור כיווץ של המודל השמור שמיוצא לקובץ
regression.zip
יחיד:
!zip -r regression.zip ./regression
- לוחצים על Runtime > Run all בתפריט ההפעלה כדי להריץ את הפנקס ואז ממתינים עד לסיום ההפעלה.
- לוחצים על
קבצים ואז מורידים את הקובץ
regression.zip
.
6. פריסת מודל רגרסיה באמצעות TensorFlow serving
- כדי לפרוס את המודל ב-TensorFlow הגשה, יש לבטל את הדחיסה של קובץ ה-
regression.zip
שהורדת באמצעות כלי לביטול הדחיסה, כמו 7-Zip.
מבנה התיקייה אמור להיראות כך:
אפשר להתייחס לתיקייה 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
יש שלושה שלבים פשוטים:
- יוצרים את הבקשה ל-REST.
- שליחת בקשת REST להגשה של TensorFlow.
- מחלצים את התוצאה החזויה מתגובת ה-REST ומעבדים את ממשק המשתמש.
עליך להשיג את השלבים האלה בקובץ iOS/regression/ViewController.swift
.
יצירה של בקשת REST
- נכון לעכשיו, הפונקציה
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, שהוא המטען הייעודי של הבקשה.
- מוסיפים את הקוד הזה לסניף של 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])
}
עכשיו, הפונקציה אחרי העיבוד מחלצת את הערכים החזויים מהתגובה ומציגה את התוצאה בממשק המשתמש.
הפעלה
- לוחצים על
‘Run' ומחכים ש-Xcode יפעיל את האפליקציה בסימולטור.
- מזינים מספר בתיבת הטקסט ולוחצים על מסקנות.
עכשיו מופיע ערך חזוי בממשק המשתמש.
8. חיבור של אפליקציית iOS עם TensorFlow serving דרך gRPC
בנוסף ל-REST, שירות TensorFlow תומך גם ב-gRPC.
gRPC היא מסגרת מודרנית ומודרנית של ביצועים טובים (RTT) שניתן להפעיל בכל סביבה. הוא יכול לחבר שירותים ביעילות למרכזי נתונים, ובהם בתמיכה, לאיזון עומסים, למעקב אחר נתונים, לבדיקת תקינות ולאימות. התגלה ש-gRPC מניב ביצועים טובים יותר בהשוואה ל-REST בפועל.
שליחה של בקשות וקבלת תשובות באמצעות gRPC
יש ארבעה שלבים פשוטים:
- אופציונלי: יצירת קוד stub של לקוח gRPC.
- יוצרים את בקשת ה-gRPC.
- שליחת בקשת gRPC לשירות TensorFlow.
- מחלצים את התוצאה החזויה מתגובת ה-gRPC ומעבדים את ממשק המשתמש.
עליך להשיג את השלבים האלה בקובץ iOS/regression/ViewController.swift
.
אופציונלי: יצירת קוד stub של לקוח gRPC
כדי להשתמש ב-gRPC עם TensorFlow serving, יש לפעול לפי תהליך העבודה של gRPC. למידע נוסף, ניתן לעיין בתיעוד של gRPC.
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:
- במסוף שלך, עליך להיכנס לתיקייה
starter/src/proto/
וליצור את ה-stub:
bash generate_grpc_stub_swift.sh
מספר .swift
קבצים נוצרים בתיקייה starter/src/proto/generated/import
.
- אם הם עדיין לא מועתקים לפרויקט, גוררים את כל קובצי
.swift
שנוצרו לפרויקט ב-Xcode.
יצירת בקשת 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)")
}
עכשיו, הפונקציה אחרי העיבוד מחלצת את הערכים החזויים מהתגובה ומציגה את התוצאה בממשק המשתמש.
הפעלה
- לוחצים על
‘Run' בתפריט הניווט ומחכים ש-Xcode יפעיל את האפליקציה בסימולטור.
- מזינים מספר בתיבת הטקסט ולוחצים על מסקנות.
עכשיו מופיע ערך חזוי בממשק המשתמש.