Создание полнофункциональной системы рекомендаций фильмов

1. Прежде чем начать

От рекомендаций фильмов или ресторанов до выделения развлекательных видеороликов — системы рекомендаций, также известные как рекомендательные системы, являются очень важным применением машинного обучения. Рекомендательные системы помогают вам находить привлекательный контент среди большого количества кандидатов для ваших пользователей. Например, Google Play Store предлагает миллионы приложений для установки, а YouTube — миллиарды видеороликов для просмотра. И каждый день добавляются новые приложения и видео.

В этом практическом занятии вы научитесь создавать полнофункциональную рекомендательную систему, используя следующие инструменты:

  • TensorFlow Recommenders используется для обучения модели поиска и ранжирования фильмов в целях их рекомендации.
  • TensorFlow Serving используется для обслуживания моделей.
  • Flutter для создания кроссплатформенного приложения для отображения рекомендованных фильмов.

Предварительные требования

  • Базовые знания разработки на Flutter с использованием Dart.
  • Базовые знания машинного обучения с использованием TensorFlow, например, различий между обучением и развертыванием.
  • Базовые знания рекомендательных систем.
  • Базовые знания Python, работы с терминалом и Docker.

Что вы узнаете

  • Как обучить модели поиска и ранжирования с помощью TensorFlow Recommenders
  • Как запустить обученные модели рекомендаций с помощью TensorFlow Serving
  • Как создать кроссплатформенное Flutter-приложение для отображения рекомендуемых товаров

Что вам понадобится

2. Настройте среду разработки Flutter.

Для разработки на Flutter вам понадобятся два программных компонента для выполнения этого практического задания — Flutter SDK и редактор .

Вы можете запустить интерфейсную часть Codelab, используя любое из этих устройств:

  • Симулятор iOS (требуется установка инструментов Xcode).
  • Эмулятор Android (требуется настройка в Android Studio).
  • Для работы требуется браузер (для отладки необходим Chrome).
  • Если вы разрабатываете настольное приложение для Windows , Linux или macOS , вам необходимо работать на той платформе, на которой вы планируете его развернуть. Таким образом, если вы хотите разработать настольное приложение для Windows, вам необходимо использовать Windows для доступа к соответствующей цепочке сборки. Существуют специфические требования к операционной системе, которые подробно описаны в документации docs.flutter.dev/desktop .

Для бэкэнда вам потребуется:

  • Компьютер под управлением Linux или Mac на базе процессора Intel.

3. Подготовка к работе

Чтобы скачать код для этого практического занятия:

  1. Перейдите в репозиторий GitHub , содержащий этот практический урок.
  2. Нажмите «Код» > «Скачать zip-архив» , чтобы загрузить весь код для этого практического занятия.

2cd45599f51fb8a2.png

  1. Распакуйте загруженный zip-файл, чтобы получить корневую папку codelabs-main со всеми необходимыми ресурсами.

Для выполнения этого практического задания вам понадобятся только файлы из подкаталога tfrs-flutter/ в репозитории, который содержит несколько папок:

  • В папках step0step5 содержится исходный код, на основе которого вы будете строить каждый шаг в этом практическом занятии.
  • В папке finished содержится готовый код для тестового приложения.
  • Каждая папка содержит подпапку backend , в которой находится код бэкэнда системы рекомендаций, и подпапку frontend , в которой находится код фронтенда на Flutter.

4. Загрузите зависимости для проекта.

Бэкенд

Для создания бэкенда мы будем использовать Flask . Откройте терминал и выполните следующую команду:

pip install Flask flask-cors requests numpy

Внешний интерфейс

  1. В VS Code нажмите «Файл» > «Открыть папку» , а затем выберите папку 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. Пользовательский интерфейс довольно прост. Есть текстовое поле, куда пользователь может ввести свой ID. Приложение Flutter отправит запрос на бэкэнд, который запустит две модели рекомендаций и вернет ранжированный список рекомендуемых фильмов. После получения ответа фронтенд отобразит результат в пользовательском интерфейсе.

d21427db9587560f.png73e8272a5ce8dfbc.png

Если вы нажмете «Рекомендовать сейчас», ничего не произойдет, потому что приложение еще не может связаться с бэкэндом.

6. Шаг 1: Создайте модели поиска и ранжирования для системы рекомендаций.

В реальных системах рекомендаций часто используются несколько этапов:

  1. Этап поиска отвечает за выбор начального набора из сотен кандидатов из всех возможных вариантов. Главная цель этой модели — эффективно отсеять всех кандидатов, которые не интересуют пользователя. Поскольку модель поиска может обрабатывать миллионы кандидатов, она должна быть вычислительно эффективной.
  2. На этапе ранжирования результаты работы поисковой модели уточняются для выбора наилучшего возможного набора рекомендаций. Его задача — сузить набор элементов, которые могут заинтересовать пользователя, до короткого списка вероятных кандидатов, насчитывающего сотни вариантов.
  3. Этап после ранжирования помогает обеспечить разнообразие, актуальность и справедливость, а также реорганизует варианты в набор полезных рекомендаций, состоящий из десятков пунктов.

70dfc0d7e989164f.png

В этом практическом задании вы обучите модель поиска и модель ранжирования, используя популярный набор данных 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.

Фронтенд-приложение довольно простое. В нём есть только текстовое поле, которое принимает идентификатор пользователя и отправляет запрос (в функции 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.pnga0d2d4020aebfb0a.png

9. Шаг 4: Запустите приложение Flutter на настольных платформах

Помимо Android и iOS, Flutter также поддерживает настольные платформы, включая Linux, Mac и Windows.

Linux

  1. Убедитесь, что целевое устройство настроено на 86cba523de82b4f9.png в строке состояния VSCode.
  2. Нажмите a19a0c68bc4046e6.png Начните отладку , а затем дождитесь загрузки приложения.
  3. Введите идентификатор пользователя (например, 42), а затем выберите «Рекомендовать» .

2665514231033f1.png

Мак

  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. Вы легко сможете применить полученные знания в других областях (например, в электронной коммерции, еде и коротких видеороликах).

Узнать больше