إنشاء نظام كامل لاقتراح الأفلام

1. قبل البدء

من تطبيقات تعلُّم الآلة أهمية كبيرة، بدءًا من اقتراح الأفلام أو المطاعم وصولاً إلى إبراز الفيديوهات الترفيهية. تساعدك الاقتراحات في تسليط الضوء على المحتوى الجذاب للمستخدمين من بين مجموعة كبيرة من المرشحين. على سبيل المثال، يوفّر "متجر Google Play" ملايين التطبيقات لتثبيتها، في حين يوفّر YouTube مليارات الفيديوهات لمشاهدتها. ونضيف المزيد من التطبيقات والفيديوهات كل يوم.

في هذا الدرس التطبيقي حول الترميز، ستتعلم كيفية إنشاء توصية بحزمة كاملة باستخدام:

  • برامج التوصية TensorFlow لتدريب استرجاعية ونموذج ترتيب لتوصيات الأفلام
  • منصة TensorFlow لعرض النماذج
  • Flutter لإنشاء تطبيق من عدّة منصات لعرض الأفلام المقترَحة

المتطلبات الأساسية

  • معرفة أساسية بتطوير Flutter باستخدام Dart
  • الإلمام بأساسيات تعلُّم الآلة باستخدام TensorFlow، مثل التدريب مقابل النشر
  • الإلمام الأساسي بأنظمة التوصية
  • معرفة أساسية بلغة بايثون والمحطات الطرفية و Docker

ما ستتعرَّف عليه

  • طريقة تدريب نماذج الاسترجاع والترتيب باستخدام أدوات الاقتراحات TensorFlow
  • كيفية عرض نماذج الاقتراحات المدرَّبة باستخدام TensorFlow Display
  • كيفية إنشاء تطبيق Flutter من عدّة منصات لعرض العناصر المقترَحة

المتطلبات

2. إعداد بيئة تطوير Flutter

بالنسبة إلى تطوير Flutter، تحتاج إلى برنامجَين لإكمال هذا الدرس التطبيقي حول الترميز، وهما Flutter SDK وأداة تعديل.

يمكنك تشغيل الواجهة الأمامية للدرس التطبيقي حول الترميز باستخدام أي من الأجهزة التالية:

  • محاكي iOS (يتطلب تثبيت أدوات Xcode).
  • محاكي Android (يتطلب عملية إعداد في "استوديو Android").
  • متصفّح (يجب توفُّر متصفّح Chrome لتصحيح الأخطاء)
  • كتطبيق سطح المكتب الذي يعمل بنظام التشغيل Windows أو Linux أو macOS. يجب إجراء تطوير على النظام الأساسي الذي تخطّط لنشر الإعلان عليه. لذا، إذا كنت ترغب في تطوير تطبيق سطح مكتب Windows، ينبغي لك تطويره على Windows للوصول إلى سلسلة الإصدار المناسبة. هناك متطلبات خاصة بنظام التشغيل تم تناولها بالتفصيل على docs.flutter.dev/desktop.

بالنسبة إلى الخلفية، ستحتاج إلى:

  • جهاز Linux أو جهاز Mac مستند إلى Intel.

3- الإعداد

لتنزيل الرمز الخاص بهذا الدرس التطبيقي حول الترميز:

  1. انتقِل إلى مستودع GitHub الخاص بهذا الدرس التطبيقي حول الترميز.
  2. انقر على الرمز > نزِّل الرمز البريدي لتنزيل جميع الرموز الخاصة بهذا الدرس التطبيقي حول الترميز.

2cd45599f51fb8a2.png

  1. عليك فكّ ضغط ملف ZIP الذي تم تنزيله لفك ضغط مجلد الجذر codelabs-main الذي يتضمّن جميع الموارد اللازمة.

في هذا الدرس التطبيقي حول الترميز، تحتاج فقط إلى الملفات المتوفّرة في دليل tfrs-flutter/ الفرعي في المستودع، والذي يحتوي على مجلدات متعدّدة:

  • تحتوي المجلدات من step0 إلى step5 على رمز التفعيل الذي تعتمد عليه في كل خطوة في هذا الدرس التطبيقي حول الترميز.
  • يحتوي المجلد finished على الرمز المكتمل لنموذج التطبيق النهائي.
  • يحتوي كل مجلد على مجلد فرعي باللغة backend يتضمّن رمز الواجهة الخلفية لمحرّك الاقتراحات ومجلدًا فرعيًا على frontend يتضمّن رمز الواجهة الأمامية لتطبيق Flutter.

4. تنزيل التبعيات للمشروع

الخلفية

سنستخدم Flask لإنشاء الواجهة الخلفية. افتح الوحدة الطرفية وشغِّل ما يلي:

pip install Flask flask-cors requests numpy

الواجهة الأمامية

  1. في رمز VS، انقر على ملف > افتح المجلد، ثم اختَر المجلد step0 من رمز المصدر الذي نزّلته سابقًا.
  2. افتح ملف step0/frontend/lib/main.dart. إذا ظهر مربّع حوار رمز VS يطلب منك تنزيل الحِزم المطلوبة لتطبيق التفعيل، انقر على الحصول على الحِزم.
  3. إذا لم يظهر لك مربّع الحوار هذا، افتح الوحدة الطرفية ثم شغِّل الأمر flutter pub get في المجلد step0/frontend.

7ada07c300f166a6.png

5- الخطوة 0: تشغيل تطبيق إجراء التفعيل

  1. افتح ملف step0/frontend/lib/main.dart في VS Code، وتأكد من إعداد محاكي Android أو iOS Simulator بشكل صحيح ويظهر في شريط الحالة.

على سبيل المثال، إليك ما يظهر لك عند استخدام هاتف Pixel 5 مع "محاكي Android":

9767649231898791.png

إليك ما تراه عند استخدام iPhone 13 مع محاكي iOS:

95529e3a682268b2.png

  1. انقر على a19a0c68bc4046e6.png بدء تصحيح الأخطاء.

تشغيل التطبيق واستكشافه

يجب تشغيل التطبيق على محاكي Android أو محاكي iOS. واجهة المستخدم واضحة جدًا. يتوفّر حقل نصي يسمح للمستخدم بكتابة النص كرقم تعريف المستخدم. سيرسل تطبيق Flutter طلب البحث إلى الخلفية التي تشغِّل نموذجَين للاقتراحات وتعرض قائمة مرتّبة باقتراحات الأفلام. ستعرض الواجهة الأمامية النتيجة في واجهة المستخدم بعد تلقّي الرد.

d21427db9587560f.png 73e8272a5ce8dfbc.png

في حال النقر على اقتراح الآن، لن يحدث أي شيء لأنّه لا يمكن للتطبيق الاتصال بالخلفية حتى الآن.

6- الخطوة الأولى: إنشاء نماذج الاسترجاع والترتيب لمحرك الاقتراحات

غالبًا ما تتكون محركات التوصية الواقعية من مراحل متعددة:

  1. مرحلة الاسترجاع مسؤولة عن اختيار مجموعة أولية من مئات العناصر المرشحة من جميع المرشحين المحتملين. الهدف الرئيسي من هذا النموذج هو التخلص بكفاءة من جميع العناصر المرشحة التي لا يهتم بها المستخدم. ونظرًا لأن نموذج الاسترجاع قد يتعامل مع ملايين العناصر المرشحة، فيجب أن يكون فعالاً من الناحية الحسابية.
  2. تأخذ مرحلة الترتيب مخرجات نموذج الاسترجاع وتضبطها لتحديد أفضل مجموعة ممكنة من التوصيات. وتتمثل مهمتها في تضييق نطاق مجموعة العناصر التي قد يكون المستخدم مهتمًا بها إلى قائمة مختصرة للمرشحين المحتملين في ترتيب من المئات.
  3. تساعد مرحلة التصنيف اللاحق على ضمان التنوّع والحداثة والنزاهة، وتعيد تنظيم العناصر المرشّحة ضمن مجموعة من الاقتراحات المفيدة بترتيب العشرات.

70dfc0d7e989164f.png

وفي هذا الدرس التطبيقي حول الترميز، ستُدرِّب نموذج استرجاع ونموذج ترتيب باستخدام مجموعة بيانات 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

ستقف القارورة نقطة نهاية جديدة في 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.

تطبيق الواجهة الأمامية بسيط إلى حد ما. ولا تتضمّن سوى حقل نصي يتضمّن رقم تعريف المستخدم ويرسل الطلب (في دالة 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. تهانينا

لقد أنشأت تطبيق كامل لتوصية المستخدمين بالأفلام!

مع أنّ التطبيق يقترح مشاهدة الأفلام فقط، فقد تعلّمت سير العمل العام لإنشاء محرّك اقتراحات فعّال وأتقنت المهارة اللازمة لتنفيذ الاقتراحات في تطبيق Flutter. ويمكنك بسهولة تطبيق ما تعلمته على سيناريوهات أخرى (مثل التجارة الإلكترونية والطعام والفيديوهات القصيرة).

مزيد من المعلومات