1. לפני שמתחילים
מנועי המלצות, שנקראים גם מערכות המלצה, הם יישום חשוב מאוד של למידת מכונה. הם משמשים להמלצה על סרטים או מסעדות, להדגשה של סרטונים מבדרים ועוד. מערכות המלצה עוזרות לכם להציג למשתמשים תוכן מעניין מתוך מאגר גדול של אפשרויות. לדוגמה, בחנות Google Play יש מיליוני אפליקציות להתקנה, וב-YouTube יש מיליארדי סרטונים לצפייה. בנוסף, מדי יום מתווספים עוד אפליקציות וסרטונים.
ב-Codelab הזה תלמדו איך לבנות שירות המלצות מלא באמצעות:
- TensorFlow Recommenders כדי לאמן מודל אחזור ומודל דירוג להמלצות על סרטים
- TensorFlow Serving להצגת המודלים
- Flutter כדי ליצור אפליקציה בפלטפורמות שונות להצגת המלצות לסרטים
דרישות מוקדמות
- ידע בסיסי בפיתוח Flutter עם Dart
- ידע בסיסי בלמידת מכונה עם TensorFlow, כמו אימון לעומת פריסה
- היכרות בסיסית עם מערכות המלצות
- ידע בסיסי ב-Python, במסופים וב-Docker
מה תלמדו
- איך מאמנים מודלים של אחזור ודירוג באמצעות TensorFlow Recommenders
- איך להשתמש ב-TensorFlow Serving כדי להציג את מודלי ההמלצות שאומנו
- איך יוצרים אפליקציית Flutter שפועלת בפלטפורמות שונות ומציגה את הפריטים המומלצים
הדרישות
- Flutter SDK
- הגדרה של Android ו-iOS ל-Flutter
- הגדרה של מחשב ל-Flutter
- הגדרה של אינטרנט ל-Flutter
- הגדרה של Visual Studio Code (VS Code) ל-Flutter ול-Dart
- Docker
- Bash
- Python 3.7 ואילך
- גישה אל Colab
2. הגדרת סביבת הפיתוח של Flutter
כדי להשלים את ה-codelab הזה, צריך שני רכיבי תוכנה לפיתוח ב-Flutter: Flutter SDK ועורך.
אפשר להריץ את הקצה הקדמי של ה-Codelab באמצעות כל אחד מהמכשירים הבאים:
- סימולטור iOS (נדרשת התקנה של כלי Xcode).
- אמולטור Android (נדרשת הגדרה ב-Android Studio).
- דפדפן (חובה להשתמש ב-Chrome לצורך ניפוי באגים).
- כאפליקציה למחשב Windows, Linux או macOS. אתם צריכים לפתח בפלטפורמה שבה אתם מתכננים לבצע פריסה. לכן, אם רוצים לפתח אפליקציה למחשב שולחני עם Windows, צריך לפתח ב-Windows כדי לגשת לשרשרת הבנייה המתאימה. יש דרישות ספציפיות למערכות הפעלה שמוסברות בפירוט במאמר docs.flutter.dev/desktop.
לצד השרת, תצטרכו:
- מחשב Linux או מחשב Mac מבוסס-Intel.
3. להגדרה
כדי להוריד את הקוד של ה-Codelab הזה:
- עוברים אל מאגר GitHub של ה-Codelab הזה.
- לוחצים על Code > Download zip (קוד > הורדת קובץ zip) כדי להוריד את כל הקוד של ה-Codelab הזה.

- מבטלים את הדחיסה של קובץ ה-ZIP שהורדתם כדי לפתוח תיקיית בסיס
codelabs-mainעם כל המשאבים שאתם צריכים.
ב-Codelab הזה, צריך רק את הקבצים בספריית המשנה tfrs-flutter/ במאגר, שמכילה כמה תיקיות:
- התיקיות
step0עדstep5מכילות את קוד לתחילת הדרך שעליו תבנו בכל שלב ב-Codelab הזה. - התיקייה
finishedמכילה את הקוד המלא של האפליקציה לדוגמה. - כל תיקייה מכילה תיקיית משנה
backend, שכוללת את קוד ה-Backend של מנוע ההמלצות, ותיקיית משנהfrontend, שכוללת את קוד ה-Frontend של Flutter.
4. הורדת התלות של הפרויקט
בק-אנד
נשתמש ב-Flask כדי ליצור את הקצה העורפי. פותחים את הטרמינל ומריצים את הפקודה הבאה:
pip install Flask flask-cors requests numpy
קצה קדמי
- ב-VS Code, לוחצים על File > Open folder (קובץ > פתיחת תיקייה) ואז בוחרים את התיקייה
step0מקוד המקור שהורדתם קודם. - פותחים את הקובץ
step0/frontend/lib/main.dart. אם מופיעה תיבת דו-שיח ב-VS Code עם הנחיה להוריד את החבילות הנדרשות לאפליקציה לתחילת הדרך, לוחצים על Get packages (קבלת חבילות). - אם תיבת הדו-שיח הזו לא מופיעה, פותחים את הטרמינל ומריצים את הפקודה
flutter pub getבתיקייהstep0/frontend.

5. שלב 0: הפעלת אפליקציה לתחילת הדרך
- פותחים את הקובץ
step0/frontend/lib/main.dartב-VS Code ומוודאים שהאמולטור של Android או הסימולטור של iOS מוגדרים כראוי ומופיעים בסרגל הסטטוס.
לדוגמה, כך נראה השימוש ב-Pixel 5 עם אמולטור Android:

כך נראה השימוש ב-iPhone 13 עם סימולטור iOS:

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

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

ב-Codelab זה, תאמנו מודל אחזור ומודל דירוג באמצעות מערך הנתונים הפופולרי MovieLens. אפשר לפתוח את קוד האימון שבהמשך באמצעות Colab ולפעול לפי ההוראות:
7. שלב 2: יצירת קצה העורפי של מנוע ההמלצות
אחרי שאומנו המודלים של אחזור ודירוג, אפשר לפרוס אותם וליצור קצה עורפי.
הפעלת TensorFlow Serving
מכיוון שצריך להשתמש גם במודל השליפה וגם במודל הדירוג כדי ליצור את רשימת הסרטים המומלצים, צריך לפרוס את שניהם בו-זמנית באמצעות TensorFlow Serving.
- בטרמינל, עוברים לתיקייה
step2/backendבמחשב ומפעילים את TensorFlow Serving באמצעות Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config
מערכת Docker מורידה קודם את תמונת TensorFlow Serving, וזה לוקח דקה. לאחר מכן, TensorFlow Serving אמור להתחיל לפעול. היומן צריך להיראות כמו קטע הקוד הבא:
2022-04-24 09:32:06.461702: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models.
2022-04-24 09:32:06.461843: I tensorflow_serving/model_servers/server_core.cc:591] (Re-)adding model: retrieval
2022-04-24 09:32:06.461907: I tensorflow_serving/model_servers/server_core.cc:591] (Re-)adding model: ranking
2022-04-24 09:32:06.576920: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: retrieval version: 123}
2022-04-24 09:32:06.576993: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577011: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577848: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.583809: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.583879: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.584970: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-04-24 09:32:06.629900: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.634662: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2800000000 Hz
2022-04-24 09:32:06.672534: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.673629: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: ranking version: 123}
2022-04-24 09:32:06.673765: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: ranking version: 123}
2022-04-24 09:32:06.673786: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: ranking version: 123}
2022-04-24 09:32:06.674731: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.683557: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.683601: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.688665: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 110815 microseconds.
2022-04-24 09:32:06.690019: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/retrieval/exported-retrieval/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.693025: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: retrieval version: 123}
2022-04-24 09:32:06.702594: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.745361: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.772363: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 97633 microseconds.
2022-04-24 09:32:06.774853: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ranking/exported-ranking/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.777706: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: ranking version: 123}
2022-04-24 09:32:06.778969: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-04-24 09:32:06.779030: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-04-24 09:32:06.784217: 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-04-24 09:32:06.785748: 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 ...
יצירת נקודת קצה חדשה
מכיוון ש-TensorFlow Serving לא תומך ב'שרשור' של כמה מודלים עוקבים, צריך ליצור שירות חדש שמקשר בין מודלי האחזור והדירוג.
- מוסיפים את הקוד הזה לפונקציה
get_recommendations()בקובץstep2/backend/recommendations.py:
user_id = request.get_json()["user_id"]
retrieval_request = json.dumps({"instances": [user_id]})
retrieval_response = requests.post(RETRIEVAL_URL, data=retrieval_request)
movie_candidates = retrieval_response.json()["predictions"][0]["output_2"]
ranking_queries = [
{"user_id": u, "movie_title": m}
for (u, m) in zip([user_id] * NUM_OF_CANDIDATES, movie_candidates)
]
ranking_request = json.dumps({"instances": ranking_queries})
ranking_response = requests.post(RANKING_URL, data=ranking_request)
movies_scores = list(np.squeeze(ranking_response.json()["predictions"]))
ranked_movies = [
m[1] for m in sorted(list(zip(movies_scores, movie_candidates)), reverse=True)
]
return make_response(jsonify({"movies": ranked_movies}), 200)
הפעלת שירות Flask
עכשיו אפשר להפעיל את שירות Flask.
- במסוף, עוברים לתיקייה
step2/backend/ומריצים את הפקודה הבאה:
FLASK_APP=recommender.py FLASK_ENV=development flask run
Flask יגדיר נקודת קצה חדשה בכתובת http://localhost:5000/recommend. היומן אמור להיראות כך:
* Serving Flask app 'recommender.py' (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 705-382-264 127.0.0.1 - - [25/Apr/2022 19:44:47] "POST /recommend HTTP/1.1" 200 -
אפשר לשלוח בקשה לדוגמה לנקודת הקצה כדי לוודא שהיא פועלת כמצופה:
curl -X POST -H "Content-Type: application/json" -d '{"user_id":"42"}' http://localhost:5000/recommend
נקודת הקצה תחזיר רשימה של סרטים מומלצים למשתמש 42:
{
"movies": [
"While You Were Sleeping (1995)",
"Preacher's Wife, The (1996)",
"Michael (1996)",
"Lion King, The (1994)",
"Father of the Bride Part II (1995)",
"Sleepless in Seattle (1993)",
"101 Dalmatians (1996)",
"Bridges of Madison County, The (1995)",
"Rudy (1993)",
"Jack (1996)"
]
}
זהו! יצרתם בהצלחה קצה עורפי להמלצה על סרטים על סמך מזהה משתמש.
8. שלב 3: יצירת אפליקציית Flutter ל-Android ול-iOS
הקצה העורפי מוכן. אתם יכולים להתחיל לשלוח אליו בקשות כדי לקבל המלצות לסרטים מאפליקציית Flutter.
אפליקציית ה-Frontend די פשוטה. יש לו רק TextField שבו מזינים את מזהה המשתמש ושולחים את הבקשה (בפונקציה recommend()) אל ה-Backend שבניתם. אחרי שמקבלים את התשובה, ממשק המשתמש של האפליקציה מציג את הסרטים המומלצים ב-ListView.
- מוסיפים את הקוד הזה לפונקציה
recommend()בקובץstep3/frontend/lib/main.dart:
final response = await http.post(
Uri.parse('http://' + _server + ':5000/recommend'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
'user_id': _userIDController.text,
}),
);
אחרי שהאפליקציה מקבלת את התגובה מהקצה העורפי, מעדכנים את ממשק המשתמש כדי להציג את רשימת הסרטים המומלצים למשתמש שצוין.
- מוסיפים את הקוד הזה מיד מתחת לקוד שלמעלה:
if (response.statusCode == 200) {
return List<String>.from(jsonDecode(response.body)['movies']);
} else {
throw Exception('Error response');
}
מפעילים פתרונות חכמים
- לוחצים על
התחלת ניפוי באגים ומחכים שהאפליקציה תיטען. - מזינים מזהה משתמש (לדוגמה, 42) ואז בוחרים באפשרות המלצה.

9. שלב 4: מריצים את אפליקציית Flutter בפלטפורמות למחשב
בנוסף ל-Android ול-iOS, Flutter תומכת גם בפלטפורמות למחשבים, כולל Linux, Mac ו-Windows.
Linux
- מוודאים שמכשיר היעד מוגדר ל-
בסרגל הסטטוס של VSCode. - לוחצים על
התחלת ניפוי באגים ומחכים שהאפליקציה תיטען. - מזינים מזהה משתמש (לדוגמה, 42) ואז בוחרים באפשרות המלצה.

Mac
- ב-Mac, צריך להגדיר הרשאות מתאימות כי האפליקציה תשלח בקשות HTTP לבק-אנד. פרטים נוספים מופיעים במאמר בנושא הרשאות וארגז החול של האפליקציה.
מוסיפים את הקוד הזה ל-step4/frontend/macOS/Runner/DebugProfile.entitlements ול-step4/frontend/macOS/Runner/Release.entitlements בהתאמה:
<key>com.apple.security.network.client</key>
<true/>
- מוודאים שמכשיר היעד מוגדר ל-
בסרגל הסטטוס של VSCode. - לוחצים על
התחלת ניפוי באגים ומחכים שהאפליקציה תיטען. - מזינים מזהה משתמש (לדוגמה, 42) ואז בוחרים באפשרות המלצה.

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

10. שלב 5: מריצים את אפליקציית Flutter בפלטפורמת האינטרנט
אפשר גם להוסיף תמיכה באינטרנט לאפליקציית Flutter. כברירת מחדל, פלטפורמת האינטרנט מופעלת אוטומטית באפליקציות Flutter, כך שכל מה שצריך לעשות הוא להפעיל אותה.
- מוודאים שמכשיר היעד מוגדר ל-
בסרגל הסטטוס של VSCode. - לוחצים על
התחלת ניפוי באגים ומחכים שהאפליקציה תיטען בדפדפן Chrome. - מזינים מזהה משתמש (לדוגמה, 42) ואז בוחרים באפשרות המלצה.

11. מזל טוב
יצרתם אפליקציה fullstack להמלצה על סרטים למשתמשים שלכם.
למרות שהאפליקציה ממליצה רק על סרטים, למדתם את תהליך העבודה הכולל של בניית מנוע המלצות יעיל, ורכשתם את המיומנות של צריכת ההמלצות באפליקציית Flutter. תוכלו ליישם בקלות את מה שלמדתם בתרחישים אחרים (למשל, מסחר אלקטרוני, מזון וסרטונים קצרים).