1. قبل البدء
من تطبيقات تعلُّم الآلة أهمية كبيرة، بدءًا من اقتراح الأفلام أو المطاعم وصولاً إلى إبراز الفيديوهات الترفيهية. تساعدك الاقتراحات في تسليط الضوء على المحتوى الجذاب للمستخدمين من بين مجموعة كبيرة من المرشحين. على سبيل المثال، يوفّر "متجر Google Play" ملايين التطبيقات لتثبيتها، في حين يوفّر YouTube مليارات الفيديوهات لمشاهدتها. ونضيف المزيد من التطبيقات والفيديوهات كل يوم.
في هذا الدرس التطبيقي حول الترميز، ستتعلم كيفية إنشاء توصية بحزمة كاملة باستخدام:
- برامج التوصية TensorFlow لتدريب استرجاعية ونموذج ترتيب لتوصيات الأفلام
- منصة TensorFlow لعرض النماذج
- Flutter لإنشاء تطبيق من عدّة منصات لعرض الأفلام المقترَحة
المتطلبات الأساسية
- معرفة أساسية بتطوير Flutter باستخدام Dart
- الإلمام بأساسيات تعلُّم الآلة باستخدام TensorFlow، مثل التدريب مقابل النشر
- الإلمام الأساسي بأنظمة التوصية
- معرفة أساسية بلغة بايثون والمحطات الطرفية و Docker
ما ستتعرَّف عليه
- طريقة تدريب نماذج الاسترجاع والترتيب باستخدام أدوات الاقتراحات TensorFlow
- كيفية عرض نماذج الاقتراحات المدرَّبة باستخدام TensorFlow Display
- كيفية إنشاء تطبيق Flutter من عدّة منصات لعرض العناصر المقترَحة
المتطلبات
- Flutter SDK
- إعداد Android وiOS لتطبيق Flutter
- إعداد الكمبيوتر المكتبي لتطبيق Flutter
- إعداد الويب في Flutter
- إعداد Visual Studio Code (VS Code) لكل من Flutter وDart
- القرّاء
- Bash
- Python 3.7+
- الوصول إلى Colab
2. إعداد بيئة تطوير Flutter
بالنسبة إلى تطوير Flutter، تحتاج إلى برنامجَين لإكمال هذا الدرس التطبيقي حول الترميز، وهما Flutter SDK وأداة تعديل.
يمكنك تشغيل الواجهة الأمامية للدرس التطبيقي حول الترميز باستخدام أي من الأجهزة التالية:
- محاكي iOS (يتطلب تثبيت أدوات Xcode).
- محاكي Android (يتطلب عملية إعداد في "استوديو Android").
- متصفّح (يجب توفُّر متصفّح Chrome لتصحيح الأخطاء)
- كتطبيق سطح المكتب الذي يعمل بنظام التشغيل Windows أو Linux أو macOS. يجب إجراء تطوير على النظام الأساسي الذي تخطّط لنشر الإعلان عليه. لذا، إذا كنت ترغب في تطوير تطبيق سطح مكتب Windows، ينبغي لك تطويره على Windows للوصول إلى سلسلة الإصدار المناسبة. هناك متطلبات خاصة بنظام التشغيل تم تناولها بالتفصيل على docs.flutter.dev/desktop.
بالنسبة إلى الخلفية، ستحتاج إلى:
- جهاز Linux أو جهاز Mac مستند إلى Intel.
3- الإعداد
لتنزيل الرمز الخاص بهذا الدرس التطبيقي حول الترميز:
- انتقِل إلى مستودع GitHub الخاص بهذا الدرس التطبيقي حول الترميز.
- انقر على الرمز > نزِّل الرمز البريدي لتنزيل جميع الرموز الخاصة بهذا الدرس التطبيقي حول الترميز.
- عليك فكّ ضغط ملف ZIP الذي تم تنزيله لفك ضغط مجلد الجذر
codelabs-main
الذي يتضمّن جميع الموارد اللازمة.
في هذا الدرس التطبيقي حول الترميز، تحتاج فقط إلى الملفات المتوفّرة في دليل tfrs-flutter/
الفرعي في المستودع، والذي يحتوي على مجلدات متعدّدة:
- تحتوي المجلدات من
step0
إلىstep5
على رمز التفعيل الذي تعتمد عليه في كل خطوة في هذا الدرس التطبيقي حول الترميز. - يحتوي المجلد
finished
على الرمز المكتمل لنموذج التطبيق النهائي. - يحتوي كل مجلد على مجلد فرعي باللغة
backend
يتضمّن رمز الواجهة الخلفية لمحرّك الاقتراحات ومجلدًا فرعيًا علىfrontend
يتضمّن رمز الواجهة الأمامية لتطبيق Flutter.
4. تنزيل التبعيات للمشروع
الخلفية
سنستخدم Flask لإنشاء الواجهة الخلفية. افتح الوحدة الطرفية وشغِّل ما يلي:
pip install Flask flask-cors requests numpy
الواجهة الأمامية
- في رمز VS، انقر على ملف > افتح المجلد، ثم اختَر المجلد
step0
من رمز المصدر الذي نزّلته سابقًا. - افتح ملف
step0/frontend/lib/main.dart
. إذا ظهر مربّع حوار رمز VS يطلب منك تنزيل الحِزم المطلوبة لتطبيق التفعيل، انقر على الحصول على الحِزم. - إذا لم يظهر لك مربّع الحوار هذا، افتح الوحدة الطرفية ثم شغِّل الأمر
flutter pub get
في المجلدstep0/frontend
.
5- الخطوة 0: تشغيل تطبيق إجراء التفعيل
- افتح ملف
step0/frontend/lib/main.dart
في VS Code، وتأكد من إعداد محاكي Android أو iOS Simulator بشكل صحيح ويظهر في شريط الحالة.
على سبيل المثال، إليك ما يظهر لك عند استخدام هاتف Pixel 5 مع "محاكي Android":
إليك ما تراه عند استخدام iPhone 13 مع محاكي iOS:
- انقر على بدء تصحيح الأخطاء.
تشغيل التطبيق واستكشافه
يجب تشغيل التطبيق على محاكي Android أو محاكي iOS. واجهة المستخدم واضحة جدًا. يتوفّر حقل نصي يسمح للمستخدم بكتابة النص كرقم تعريف المستخدم. سيرسل تطبيق Flutter طلب البحث إلى الخلفية التي تشغِّل نموذجَين للاقتراحات وتعرض قائمة مرتّبة باقتراحات الأفلام. ستعرض الواجهة الأمامية النتيجة في واجهة المستخدم بعد تلقّي الرد.
في حال النقر على اقتراح الآن، لن يحدث أي شيء لأنّه لا يمكن للتطبيق الاتصال بالخلفية حتى الآن.
6- الخطوة الأولى: إنشاء نماذج الاسترجاع والترتيب لمحرك الاقتراحات
غالبًا ما تتكون محركات التوصية الواقعية من مراحل متعددة:
- مرحلة الاسترجاع مسؤولة عن اختيار مجموعة أولية من مئات العناصر المرشحة من جميع المرشحين المحتملين. الهدف الرئيسي من هذا النموذج هو التخلص بكفاءة من جميع العناصر المرشحة التي لا يهتم بها المستخدم. ونظرًا لأن نموذج الاسترجاع قد يتعامل مع ملايين العناصر المرشحة، فيجب أن يكون فعالاً من الناحية الحسابية.
- تأخذ مرحلة الترتيب مخرجات نموذج الاسترجاع وتضبطها لتحديد أفضل مجموعة ممكنة من التوصيات. وتتمثل مهمتها في تضييق نطاق مجموعة العناصر التي قد يكون المستخدم مهتمًا بها إلى قائمة مختصرة للمرشحين المحتملين في ترتيب من المئات.
- تساعد مرحلة التصنيف اللاحق على ضمان التنوّع والحداثة والنزاهة، وتعيد تنظيم العناصر المرشّحة ضمن مجموعة من الاقتراحات المفيدة بترتيب العشرات.
وفي هذا الدرس التطبيقي حول الترميز، ستُدرِّب نموذج استرجاع ونموذج ترتيب باستخدام مجموعة بيانات 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'); }
تشغيله
- انقر على بدء تصحيح الأخطاء، ثم انتظِر إلى أن يتم تحميل التطبيق.
- أدخِل رقم تعريف المستخدم (أي 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. تهانينا
لقد أنشأت تطبيق كامل لتوصية المستخدمين بالأفلام!
مع أنّ التطبيق يقترح مشاهدة الأفلام فقط، فقد تعلّمت سير العمل العام لإنشاء محرّك اقتراحات فعّال وأتقنت المهارة اللازمة لتنفيذ الاقتراحات في تطبيق Flutter. ويمكنك بسهولة تطبيق ما تعلمته على سيناريوهات أخرى (مثل التجارة الإلكترونية والطعام والفيديوهات القصيرة).