1. Trước khi bắt đầu
Từ việc đề xuất phim hoặc nhà hàng cho đến việc làm nổi bật các video giải trí, công cụ đề xuất (còn gọi là hệ thống đề xuất) là một ứng dụng rất quan trọng của học máy. Hệ thống đề xuất giúp bạn giới thiệu nội dung hấp dẫn cho người dùng từ một nhóm lớn các ứng cử viên. Ví dụ: Cửa hàng Google Play cung cấp hàng triệu ứng dụng để cài đặt, trong khi YouTube cung cấp hàng tỷ video để xem. Mỗi ngày, chúng tôi đều bổ sung thêm nhiều ứng dụng và video.
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách tạo một hệ thống đề xuất toàn ngăn xếp bằng cách sử dụng:
- TensorFlow Recommenders để huấn luyện một mô hình truy xuất và xếp hạng cho các đề xuất về phim
- TensorFlow Serving để phân phát các mô hình
- Flutter để tạo một ứng dụng nhiều nền tảng nhằm hiển thị các bộ phim được đề xuất
Điều kiện tiên quyết
- Kiến thức cơ bản về cách phát triển Flutter bằng Dart
- Kiến thức cơ bản về học máy bằng TensorFlow, chẳng hạn như huấn luyện so với triển khai
- Hiểu biết cơ bản về hệ thống đề xuất
- Kiến thức cơ bản về Python, thiết bị đầu cuối và Docker
Kiến thức bạn sẽ học được
- Cách huấn luyện mô hình truy xuất và xếp hạng bằng TensorFlow Recommenders
- Cách phân phát các mô hình đề xuất đã huấn luyện bằng TensorFlow Serving
- Cách tạo một ứng dụng Flutter nhiều nền tảng để hiển thị các mục được đề xuất
Bạn cần có
- SDK Flutter
- Thiết lập Android và iOS cho Flutter
- Thiết lập máy tính cho Flutter
- Thiết lập web cho Flutter
- Thiết lập Visual Studio Code (VS Code) cho Flutter và Dart
- Docker
- Bash
- Python 3.7 trở lên
- Quyền truy cập vào Colab
2. Thiết lập môi trường phát triển Flutter
Để phát triển bằng Flutter, bạn cần có 2 phần mềm để hoàn tất lớp học lập trình này: Flutter SDK và một trình chỉnh sửa.
Bạn có thể chạy giao diện người dùng của lớp học lập trình bằng bất kỳ thiết bị nào sau đây:
- Trình mô phỏng iOS (bạn cần cài đặt các công cụ Xcode).
- Trình mô phỏng Android (cần thiết lập trong Android Studio).
- Một trình duyệt (bạn cần có Chrome để gỡ lỗi).
- Dưới dạng ứng dụng máy tính cho Windows, Linux hoặc macOS. Bạn phải phát triển trên nền tảng mà bạn dự định triển khai. Vì vậy, nếu muốn phát triển một ứng dụng máy tính cho Windows, bạn phải phát triển trên Windows để truy cập vào chuỗi bản dựng thích hợp. Có những yêu cầu cụ thể theo hệ điều hành được đề cập chi tiết trên docs.flutter.dev/desktop.
Đối với phần phụ trợ, bạn sẽ cần:
- Máy Linux hoặc máy Mac chạy chip Intel.
3. Bắt đầu thiết lập
Cách tải mã xuống cho lớp học lập trình này:
- Chuyển đến kho lưu trữ GitHub cho lớp học lập trình này.
- Nhấp vào Code > Download zip (Mã > Tải xuống tệp ZIP) để tải tất cả mã cho lớp học lập trình này xuống.

- Giải nén tệp zip đã tải xuống để giải nén một thư mục gốc
codelabs-maincó tất cả tài nguyên bạn cần.
Đối với lớp học lập trình này, bạn chỉ cần các tệp trong thư mục con tfrs-flutter/ trong kho lưu trữ. Thư mục này chứa nhiều thư mục:
- Các thư mục
step0đếnstep5chứa mã khởi đầu mà bạn sẽ dùng để tạo cho từng bước trong lớp học lập trình này. - Thư mục
finishedchứa mã hoàn chỉnh cho ứng dụng mẫu đã hoàn thành. - Mỗi thư mục đều chứa một thư mục con
backend(chứa mã phụ trợ của công cụ đề xuất) và một thư mục confrontend(chứa mã giao diện người dùng Flutter)
4. Tải các phần phụ thuộc cho dự án xuống
Phụ trợ
Chúng ta sẽ sử dụng Flask để tạo phần phụ trợ. Mở cửa sổ dòng lệnh rồi chạy lệnh sau:
pip install Flask flask-cors requests numpy
Giao diện người dùng
- Trong VS Code, hãy nhấp vào File > Open folder (Tệp > Mở thư mục), sau đó chọn thư mục
step0trong mã nguồn mà bạn đã tải xuống trước đó. - Mở tệp
step0/frontend/lib/main.dart. Nếu bạn thấy hộp thoại VS Code xuất hiện và nhắc bạn tải các gói cần thiết cho ứng dụng khởi đầu xuống, hãy nhấp vào Get packages (Tải gói xuống). - Nếu bạn không thấy hộp thoại này, hãy mở thiết bị đầu cuối rồi chạy lệnh
flutter pub gettrong thư mụcstep0/frontend.

5. Bước 0: Chạy ứng dụng khởi đầu
- Mở tệp
step0/frontend/lib/main.darttrong VS Code, đảm bảo rằng Trình mô phỏng Android hoặc Trình mô phỏng iOS được thiết lập đúng cách và xuất hiện trên thanh trạng thái.
Ví dụ: sau đây là những gì bạn thấy khi sử dụng Pixel 5 với Trình mô phỏng Android:

Sau đây là những gì bạn thấy khi sử dụng iPhone 13 với Trình mô phỏng iOS:

- Nhấp vào
Bắt đầu gỡ lỗi.
Chạy và khám phá ứng dụng
Ứng dụng sẽ chạy trên Trình mô phỏng Android hoặc Trình mô phỏng iOS. Giao diện người dùng khá đơn giản. Có một trường văn bản cho phép người dùng nhập văn bản làm mã nhận dạng người dùng. Ứng dụng Flutter sẽ gửi yêu cầu truy vấn đến phần phụ trợ, chạy 2 mô hình đề xuất và trả về danh sách đề xuất phim được xếp hạng. Giao diện người dùng sẽ hiển thị kết quả trong giao diện người dùng sau khi nhận được phản hồi.

Nếu bạn nhấp vào Recommend (Đề xuất) ngay bây giờ, sẽ không có gì xảy ra vì ứng dụng chưa thể giao tiếp với phần phụ trợ.
6. Bước 1: Tạo các mô hình truy xuất và xếp hạng cho công cụ đề xuất
Công cụ đề xuất ngoài đời thực thường bao gồm nhiều giai đoạn:
- Giai đoạn truy xuất chịu trách nhiệm chọn một nhóm ban đầu gồm hàng trăm đề xuất trong số tất cả các đề xuất có thể có. Mục tiêu chính của mô hình này là loại bỏ hiệu quả tất cả những ứng viên mà người dùng không quan tâm. Vì mô hình truy xuất có thể xử lý hàng triệu đề xuất, nên mô hình này phải có hiệu quả về mặt tính toán.
- Giai đoạn xếp hạng lấy kết quả đầu ra của mô hình truy xuất và tinh chỉnh các kết quả đó để chọn ra một số ít đề xuất phù hợp nhất có thể. Nhiệm vụ của nó là thu hẹp tập hợp các mặt hàng mà người dùng có thể quan tâm thành một danh sách ngắn gồm hàng trăm ứng cử viên tiềm năng.
- Giai đoạn sau khi xếp hạng giúp đảm bảo tính đa dạng, mới mẻ và công bằng, đồng thời sắp xếp lại các mặt hàng đề xuất thành một nhóm gồm hàng chục đề xuất hữu ích.

Trong lớp học lập trình này, bạn sẽ huấn luyện một mô hình truy xuất và một mô hình xếp hạng bằng cách sử dụng tập dữ liệu MovieLens phổ biến. Bạn có thể mở mã huấn luyện bên dưới thông qua Colab và làm theo hướng dẫn:
7. Bước 2: Tạo phần phụ trợ của công cụ đề xuất
Giờ đây, bạn có thể triển khai và tạo một phần phụ trợ sau khi huấn luyện các mô hình truy xuất và xếp hạng.
Bắt đầu TensorFlow Serving
Vì bạn cần sử dụng cả mô hình truy xuất và mô hình xếp hạng để tạo danh sách phim được đề xuất, nên bạn sẽ triển khai cả hai mô hình cùng một lúc bằng cách sử dụng TensorFlow Serving.
- Trong thiết bị đầu cuối, hãy chuyển đến thư mục
step2/backendtrên máy tính rồi khởi động TensorFlow Serving bằng Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config
Trước tiên, Docker sẽ tự động tải hình ảnh TensorFlow Serving xuống. Quá trình này mất một phút. Sau đó, TensorFlow Serving sẽ bắt đầu. Nhật ký sẽ có dạng như đoạn mã sau:
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 ...
Tạo điểm cuối mới
Vì TensorFlow Serving không hỗ trợ "liên kết" nhiều mô hình tuần tự, nên bạn cần tạo một dịch vụ mới kết nối các mô hình truy xuất và xếp hạng.
- Thêm mã này vào hàm
get_recommendations()trong tệpstep2/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)
Khởi động dịch vụ Flask
Bây giờ, bạn có thể bắt đầu dịch vụ Flask.
- Trong cửa sổ dòng lệnh, hãy chuyển đến thư mục
step2/backend/rồi chạy lệnh sau:
FLASK_APP=recommender.py FLASK_ENV=development flask run
Flask sẽ thiết lập một điểm cuối mới tại http://localhost:5000/recommend. Bạn sẽ thấy nhật ký như bên dưới:
* 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 -
Bạn có thể gửi một yêu cầu mẫu đến điểm cuối để đảm bảo điểm cuối hoạt động như mong đợi:
curl -X POST -H "Content-Type: application/json" -d '{"user_id":"42"}' http://localhost:5000/recommend
Điểm cuối sẽ trả về danh sách các bộ phim được đề xuất cho người dùng 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)"
]
}
Vậy là xong! Bạn đã tạo thành công một phần phụ trợ để đề xuất phim dựa trên mã nhận dạng người dùng.
8. Bước 3: Tạo ứng dụng Flutter cho Android và iOS
Phần phụ trợ đã sẵn sàng. Bạn có thể bắt đầu gửi yêu cầu đến máy chủ này để truy vấn các đề xuất về phim từ ứng dụng Flutter.
Ứng dụng giao diện người dùng khá đơn giản. Nó chỉ có một TextField nhận mã nhận dạng người dùng và gửi yêu cầu (trong hàm recommend()) đến phần phụ trợ mà bạn vừa tạo. Sau khi nhận được phản hồi, giao diện người dùng của ứng dụng sẽ hiển thị các bộ phim được đề xuất trong một ListView.
- Thêm mã này vào hàm
recommend()trong tệpstep3/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,
}),
);
Sau khi ứng dụng nhận được phản hồi từ phần phụ trợ, bạn sẽ cập nhật giao diện người dùng để hiển thị danh sách phim được đề xuất cho người dùng cụ thể.
- Thêm mã này ngay bên dưới mã ở trên:
if (response.statusCode == 200) {
return List<String>.from(jsonDecode(response.body)['movies']);
} else {
throw Exception('Error response');
}
Chạy ứng dụng
- Nhấp vào
Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải. - Nhập mã nhận dạng người dùng (tức là 42) rồi chọn Đề xuất.

9. Bước 4: Chạy ứng dụng Flutter trên các nền tảng máy tính
Ngoài Android và iOS, Flutter còn hỗ trợ các nền tảng máy tính, bao gồm Linux, Mac và Windows.
Linux
- Đảm bảo rằng thiết bị mục tiêu được đặt thành
trong thanh trạng thái của VSCode. - Nhấp vào
Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải. - Nhập mã nhận dạng người dùng (tức là 42) rồi chọn Đề xuất.

Mac
- Đối với máy Mac, bạn cần thiết lập các quyền thích hợp vì ứng dụng sẽ gửi yêu cầu HTTP đến phần phụ trợ. Vui lòng tham khảo bài viết Quyền và Hộp cát ứng dụng để biết thêm thông tin chi tiết.
Thêm mã này vào step4/frontend/macOS/Runner/DebugProfile.entitlements và step4/frontend/macOS/Runner/Release.entitlements tương ứng:
<key>com.apple.security.network.client</key>
<true/>
- Đảm bảo rằng thiết bị mục tiêu được đặt thành
trong thanh trạng thái của VSCode. - Nhấp vào
Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải. - Nhập mã nhận dạng người dùng (tức là 42) rồi chọn Đề xuất.

Windows
- Đảm bảo rằng thiết bị mục tiêu được đặt thành
trong thanh trạng thái của VSCode. - Nhấp vào
Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải. - Nhập mã nhận dạng người dùng (tức là 42) rồi chọn Đề xuất.

10. Bước 5: Chạy ứng dụng Flutter trên nền tảng web
Một việc khác bạn có thể làm là thêm tính năng hỗ trợ web vào ứng dụng Flutter. Theo mặc định, nền tảng web sẽ tự động được bật cho các ứng dụng Flutter, vì vậy, bạn chỉ cần chạy ứng dụng đó.
- Đảm bảo rằng thiết bị mục tiêu được đặt thành
trong thanh trạng thái của VSCode. - Nhấp vào
Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải trong trình duyệt Chrome. - Nhập mã nhận dạng người dùng (tức là 42) rồi chọn Đề xuất.

11. Xin chúc mừng
Bạn đã tạo một ứng dụng fullstack để đề xuất phim cho người dùng!
Mặc dù ứng dụng này chỉ đề xuất phim, nhưng bạn đã tìm hiểu được quy trình tổng thể để xây dựng một công cụ đề xuất mạnh mẽ và nắm vững kỹ năng sử dụng các đề xuất trong một ứng dụng Flutter. Bạn có thể dễ dàng áp dụng những gì đã học vào các trường hợp khác (ví dụ: thương mại điện tử, thực phẩm và video ngắn).