פיתוח מערכת המלצות לסרטים מסוג fullstack

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

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

ב-Codelab הזה תלמדו איך לבנות שירות המלצות מסוג fullstack באמצעות:

  • שירות TensorFlow הממליץ לאמן אחזור ומודל דירוג להמלצות על סרטים
  • TensorFlow הגשה להגשה של המודלים
  • Flutter ליצירת אפליקציה בפלטפורמות שונות להצגת סרטים מומלצים

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

  • ידע בסיסי על התפתחות Flutter עם Drt
  • ידע בסיסי בלמידת מכונה עם TensorFlow, למשל אימון לעומת פריסה
  • היכרות בסיסית עם מערכות של המלצות
  • ידע בסיסי ב-Python, טרמינלים ו-Docker

מה תלמדו

  • איך לאמן מודלים של אחזור ודירוג באמצעות שירות ההמלצות של TensorFlow
  • איך להציג את המודלים של ההמלצות שעברו אימון באמצעות TensorFlow Delivery
  • איך ליצור אפליקציה של Flutter בפלטפורמות שונות כדי להציג את הפריטים המומלצים

למה תזדקק?

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

לפיתוח של Flutter, נדרשות שתי קטעי תוכנה כדי להשלים את ה-Codelab הזה – Flutter SDK ועורך.

אפשר להריץ את החזית של Codelab באמצעות כל אחד מהמכשירים הבאים:

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

בשביל הקצה העורפי צריך:

  • מחשב Linux או Mac מבוסס Intel.

3. להגדרה

כדי להוריד את הקוד ל-Codelab הזה:

  1. עוברים אל מאגר ה-GitHub של ה-Codelab הזה.
  2. לוחצים על קוד > כדי להוריד את כל הקוד ל-Codelab הזה, צריך להוריד את ה-ZIP.

2cd45599f51fb8a2.png

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

ב-Codelab הזה, צריך רק את הקבצים בספריית המשנה tfrs-flutter/ במאגר, שמכיל כמה תיקיות:

  • התיקיות step0 עד step5 מכילות את קוד הסימן לתחילת פעולה שעליו יוצרים בכל שלב ב-Codelab הזה.
  • התיקייה finished מכילה את הקוד שהושלם עבור האפליקציה לדוגמה הסופית.
  • כל תיקייה מכילה תיקיית משנה backend, שכוללת את הקוד לקצה העורפי של מנוע ההמלצות, וגם תיקיית משנה frontend, שכוללת את הקוד בקצה הקדמי של Flutter

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

קצה עורפי

נשתמש ב-Flask כדי ליצור את הקצה העורפי שלנו. פותחים את הטרמינל ומריצים את הפקודה הבאה:

pip install Flask flask-cors requests numpy

קצה קדמי

  1. ב-VS Code, לוחצים על File > (קובץ >) פותחים את התיקייה ובוחרים בתיקייה step0 מקוד המקור שהורדתם קודם.
  2. פתיחת הקובץ step0/frontend/lib/main.dart. אם מופיעה תיבת דו-שיח של VS Code, עם בקשה להוריד את החבילות הנדרשות לאפליקציה למתחילים, לוחצים על קבלת חבילות.
  3. אם תיבת הדו-שיח הזו לא מופיעה, פותחים את הטרמינל ואז מריצים את הפקודה flutter pub get בתיקייה step0/frontend.

7ada07c300f166a6.png

5. שלב 0: מפעילים את האפליקציה לתחילת הפעולה

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

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

9767649231898791.png

כשמשתמשים ב-iPhone 13 עם הסימולטור של iOS, רואים את הפרטים הבאים:

95529e3a682268b2.png

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

הפעלה וגילוי של האפליקציה

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

d21427db9587560f.png 73e8272a5ce8dfbc.png

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

6. שלב 1: יצירת מודלים לאחזור ודירוג של מנוע ההמלצות

בדרך כלל, מנועי ההמלצות בעולם האמיתי מורכבים מכמה שלבים:

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

70dfc0d7e989164f.png

בשביל ה-codelab הזה, תאמנו מודל אחזור ומודל דירוג באמצעות מערך הנתונים הפופולרי MovieLens. אפשר לפתוח את קוד האימון שלמטה דרך Colab ולפעול לפי ההוראות:

7. שלב 2: יצירת הקצה העורפי של מנוע ההמלצות

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

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

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

  • בטרמינל, נכנסים לתיקייה step2/backend במחשב ומתחילים להציג את TensorFlow באמצעות Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config

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

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' לא תומכת ב'שרשור' כמה מודלים רציפים, אתם צריכים ליצור שירות חדש שמקשר את המודלים של אחזור ודירוג.

  • מוסיפים את הקוד הבא לפונקציה 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 -

אתם יכולים לשלוח בקשה לדוגמה לנקודת הקצה (endpoint) כדי לוודא שהיא פועלת כצפוי:

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.

האפליקציה בקצה הקדמי היא פשוטה למדי. יש בו רק TextField שמקבל את מזהה המשתמש ושולח את הבקשה (בפונקציה recommend()) לקצה העורפי שיצרתם. לאחר קבלת התגובה, ממשק המשתמש של האפליקציה מציג את הסרטים המומלצים ב-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');
}

הפעלה

  1. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
  2. צריך להזין מזהה משתמש (כלומר 42) ואז בוחרים באפשרות מומלץ.

badb59d8b96959ae.png a0d2d4020aebfb0a.png

9. שלב 4: מפעילים את אפליקציית Flutter בפלטפורמות למחשבים

בנוסף ל-Android ול-iOS, אפליקציית Flutter תומכת גם בפלטפורמות למחשב, כולל Linux, Mac ו-Windows.

Linux

  1. צריך לוודא שמכשיר היעד מוגדר לערך 86cba523de82b4f9.png בשורת הסטטוס של VSCode.
  2. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
  3. צריך להזין מזהה משתמש (כלומר 42) ואז בוחרים באפשרות מומלץ.

2665514231033f1.png

Mac

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

מוסיפים את הקוד הזה אל step4/frontend/macOS/Runner/DebugProfile.entitlements ואל step4/frontend/macOS/Runner/Release.entitlements בהתאמה:

<key>com.apple.security.network.client</key>
<true/>
  1. צריך לוודא שמכשיר היעד מוגדר לערך eb4b0b5563824138.png בשורת הסטטוס של VSCode.
  2. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
  3. צריך להזין מזהה משתמש (כלומר 42) ואז בוחרים באפשרות מומלץ.

860d523a7ac537e0.png

Windows

  1. צריך לוודא שמכשיר היעד מוגדר לערך 9587be1bb375bc0f.png בשורת הסטטוס של VSCode.
  2. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען.
  3. צריך להזין מזהה משתמש (כלומר 42) ואז בוחרים באפשרות מומלץ.

7d77c1e52a5927fc.png

10. שלב 5: מפעילים את אפליקציית Flutter בפלטפורמת האינטרנט

דבר נוסף שניתן לעשות הוא להוסיף תמיכה באינטרנט לאפליקציית Flutter. כברירת מחדל, פלטפורמת האינטרנט מופעלת באופן אוטומטי עבור אפליקציות Flutter, כך שכל מה שצריך לעשות הוא להפעיל אותה.

  1. צריך לוודא שמכשיר היעד מוגדר לערך 71db93efa928d15d.png בשורת הסטטוס של VSCode.
  2. לוחצים על a19a0c68bc4046e6.png התחלת ניפוי באגים ומחכים עד שהאפליקציה תיטען בדפדפן Chrome.
  3. צריך להזין מזהה משתמש (כלומר 42) ואז בוחרים באפשרות מומלץ.

9376e1e432c18bef.png

11. מזל טוב

יצרת אפליקציית fullstack כדי להמליץ על סרטים למשתמשים שלך!

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

מידע נוסף