Tạo một ứng dụng Flutter để phân loại văn bản

1. Trước khi bắt đầu

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách chạy suy luận phân loại văn bản từ một ứng dụng Flutter bằng TensorFlow Serving thông qua REST và gRPC.

Điều kiện tiên quyết

Kiến thức bạn sẽ học được

  • Cách tạo một ứng dụng Flutter đơn giản và phân loại văn bản thông qua TensorFlow Serving (REST và gRPC).
  • Cách hiển thị kết quả trong giao diện người dùng.

Bạn cần có

2. Thiết lập môi trường phát triển Flutter

Để phát triển Flutter, bạn cần có 2 phần mềm để hoàn thành bài thực hành này: Flutter SDKmột trình chỉnh sửa.

Bạn có thể chạy 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).
  • Là một ứ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 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.

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:

  1. Chuyển đến kho lưu trữ GitHub cho lớp học lập trình này.
  2. 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.

2cd45599f51fb8a2.png

  1. Giải nén tệp zip đã tải xuống để giải nén một thư mục gốc codelabs-main chứa 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 tfserving-flutter/codelab2 trong kho lưu trữ. Thư mục này chứa 2 thư mục:

  • Thư mục starter chứa mã khởi đầu mà bạn sẽ dùng để xây dựng trong lớp học lập trình này.
  • Thư mục finished chứa mã hoàn chỉnh cho ứng dụng mẫu đã hoàn thành.

4. Tải các phần phụ thuộc cho dự án xuống

  1. Trong VS Code, hãy nhấp vào File > Open folder (Tệp > Mở thư mục), sau đó chọn thư mục starter trong mã nguồn mà bạn đã tải xuống trước đó.
  2. Nếu bạn thấy một hộp thoại xuất hiện nhắc bạn tải các gói cần thiết cho ứng dụng khởi động, hãy nhấp vào Tải gói.
  3. 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 get trong thư mục starter.

7ada07c300f166a6.png

5. Chạy ứng dụng khởi đầu

  1. Trong VS Code, hãy đả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:

9767649231898791.png

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

95529e3a682268b2.png

  1. Nhấp vào a19a0c68bc4046e6.png 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. Người dùng có thể chọn gửi dữ liệu đến phần phụ trợ bằng REST hoặc gRPC. Phần phụ trợ sử dụng một mô hình TensorFlow để thực hiện việc phân loại văn bản trên dữ liệu đầu vào đã xử lý trước và trả về kết quả phân loại cho ứng dụng khách, từ đó cập nhật giao diện người dùng.

b298f605d64dc132.png d3ef3ccd3c338108.png

Nếu bạn nhấp vào Phân loại, 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. Triển khai mô hình phân loại văn bản bằng TensorFlow Serving

Phân loại văn bản là một nhiệm vụ rất phổ biến trong học máy, giúp phân loại văn bản thành các danh mục được xác định trước. Trong lớp học lập trình này, bạn sẽ triển khai mô hình được huấn luyện trước từ Lớp học lập trình Huấn luyện mô hình phát hiện bình luận rác bằng TensorFlow Lite Model Maker bằng TensorFlow Serving và gọi phần phụ trợ từ giao diện người dùng Flutter để phân loại văn bản đầu vào là nội dung rác hay không phải nội dung rác.

Bắt đầu TensorFlow Serving

  • Trong thiết bị đầu cuối, hãy bắt đầu TensorFlow Serving bằng Docker, nhưng thay thế phần giữ chỗ PATH/TO/SAVEDMODEL bằng đường dẫn tuyệt đối của thư mục mm_spam_savedmodel trên máy tính.
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/spam-detection" -e MODEL_NAME=spam-detection tensorflow/serving

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-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz
2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123
2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds.
2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests
2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: spam-detection version: 123}
2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-02-25 06:01:13.988994: 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-02-25 06:01:14.033872: 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 ...

7. Phân đoạn câu đầu vào

Phần phụ trợ hiện đã sẵn sàng, vì vậy, bạn gần như đã sẵn sàng gửi yêu cầu của ứng dụng đến TensorFlow Serving, nhưng trước tiên, bạn cần mã hoá câu đầu vào. Nếu kiểm tra tensor đầu vào của mô hình, bạn có thể thấy rằng mô hình này yêu cầu một danh sách gồm 20 số nguyên thay vì các chuỗi thô. Mã hoá là khi bạn liên kết các từ riêng lẻ mà bạn nhập trong ứng dụng với một danh sách các số nguyên dựa trên từ điển từ vựng trước khi bạn gửi chúng đến phần phụ trợ để phân loại. Ví dụ: nếu bạn nhập buy book online to learn more, quy trình mã hoá sẽ ánh xạ mã này thành [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]. Các con số cụ thể có thể thay đổi tuỳ theo từ điển từ vựng.

  1. Trong tệp lib/main.dart, hãy thêm mã này vào phương thức predict() để tạo từ điển từ vựng _vocabMap.
// Build _vocabMap if empty.
if (_vocabMap.isEmpty) {
  final vocabFileString = await rootBundle.loadString(vocabFile);
  final lines = vocabFileString.split('\n');
  for (final l in lines) {
    if (l != "") {
      var wordAndIndex = l.split(' ');
      (_vocabMap)[wordAndIndex[0]] = int.parse(wordAndIndex[1]);
    }
  }
} 
  1. Ngay sau đoạn mã trước, hãy thêm mã này để triển khai quy trình mã hoá:
// Tokenize the input sentence.
final inputWords = _inputSentenceController.text
    .toLowerCase()
    .replaceAll(RegExp('[^a-z ]'), '')
    .split(' ');
// Initialize with padding token.
_tokenIndices = List.filled(maxSentenceLength, 0);
var i = 0;
for (final w in inputWords) {
  if ((_vocabMap).containsKey(w)) {
    _tokenIndices[i] = (_vocabMap)[w]!;
    i++;
  }

  // Truncate the string if longer than maxSentenceLength.
  if (i >= maxSentenceLength - 1) {
    break;
  }
}

Đoạn mã này chuyển chuỗi câu thành chữ thường, xoá các ký tự không phải chữ cái và liên kết các từ với 20 chỉ mục số nguyên dựa trên bảng từ vựng.

8. Kết nối ứng dụng Flutter với TensorFlow Serving thông qua REST

Có hai cách để gửi yêu cầu đến TensorFlow Serving:

  • REST
  • gRPC

Gửi yêu cầu và nhận phản hồi thông qua REST

Có 3 bước đơn giản để gửi yêu cầu và nhận phản hồi thông qua REST:

  1. Tạo yêu cầu REST.
  2. Gửi yêu cầu REST đến TensorFlow Serving.
  3. Trích xuất kết quả dự đoán từ phản hồi REST và hiển thị giao diện người dùng.

Bạn hoàn tất các bước này trong tệp main.dart.

Tạo và gửi yêu cầu REST đến TensorFlow Serving

  1. Hiện tại, hàm predict() không gửi yêu cầu REST đến TensorFlow Serving. Bạn cần triển khai nhánh REST để tạo yêu cầu REST:
if (_connectionMode == ConnectionModeType.rest) {
  // TODO: Create and send the REST request.

}
  1. Thêm mã này vào nhánh REST:
//Create the REST request.
final response = await http.post(
  Uri.parse('http://' +
      _server +
      ':' +
      restPort.toString() +
      '/v1/models/' +
      modelName +
      ':predict'),
  body: jsonEncode(<String, List<List<int>>>{
    'instances': [_tokenIndices],
  }),
);

Xử lý phản hồi REST từ TensorFlow Serving

  • Thêm mã này ngay sau đoạn mã trước để xử lý phản hồi REST:
// Process the REST response.
if (response.statusCode == 200) {
  Map<String, dynamic> result = jsonDecode(response.body);
  if (result['predictions']![0][1] >= classificationThreshold) {
    return 'This sentence is spam. Spam score is ' +
        result['predictions']![0][1].toString();
  }
  return 'This sentence is not spam. Spam score is ' +
      result['predictions']![0][1].toString();
} else {
  throw Exception('Error response');
}

Đoạn mã xử lý hậu kỳ trích xuất xác suất câu đầu vào là thư rác từ phản hồi và hiển thị kết quả phân loại trong giao diện người dùng.

Chạy ứng dụng

  1. Nhấp vào a19a0c68bc4046e6.png Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải.
  2. Nhập một đoạn văn bản rồi chọn REST > Phân loại.

8e21d795af36d07a.png e79a0367a03c2169.png

9. Kết nối ứng dụng Flutter với TensorFlow Serving thông qua gRPC

Ngoài REST, TensorFlow Serving còn hỗ trợ gRPC.

b6f4449c2c850b0e.png

gRPC là một khung Lệnh gọi thủ tục từ xa (RPC) hiện đại, nguồn mở, hiệu suất cao, có thể chạy trong mọi môi trường. Nền tảng này có thể kết nối hiệu quả các dịch vụ trong và trên các trung tâm dữ liệu với khả năng hỗ trợ có thể cắm cho việc cân bằng tải, theo dõi, kiểm tra tình trạng và xác thực. Theo quan sát, gRPC hoạt động hiệu quả hơn REST trong thực tế.

Gửi yêu cầu và nhận phản hồi bằng gRPC

Có 4 bước đơn giản để gửi yêu cầu và nhận phản hồi bằng gRPC:

  1. Không bắt buộc: Tạo mã giả lập ứng dụng gRPC.
  2. Tạo yêu cầu gRPC.
  3. Gửi yêu cầu gRPC đến TensorFlow Serving.
  4. Trích xuất kết quả dự đoán từ phản hồi gRPC và hiển thị giao diện người dùng.

Bạn hoàn tất các bước này trong tệp main.dart.

Không bắt buộc: Tạo mã giả lập ứng dụng gRPC

Để sử dụng gRPC với TensorFlow Serving, bạn cần làm theo quy trình gRPC. Để tìm hiểu thêm về thông tin chi tiết, hãy xem tài liệu về gRPC.

a9d0e5cb543467b4.png

TensorFlow Serving và TensorFlow xác định các tệp .proto cho bạn. Kể từ TensorFlow và TensorFlow Serving 2.8, đây là những tệp .proto cần thiết:

tensorflow/core/example/example.proto
tensorflow/core/example/feature.proto
tensorflow/core/protobuf/struct.proto
tensorflow/core/protobuf/saved_object_graph.proto
tensorflow/core/protobuf/saver.proto
tensorflow/core/protobuf/trackable_object_graph.proto
tensorflow/core/protobuf/meta_graph.proto
tensorflow/core/framework/node_def.proto
tensorflow/core/framework/attr_value.proto
tensorflow/core/framework/function.proto
tensorflow/core/framework/types.proto
tensorflow/core/framework/tensor_shape.proto
tensorflow/core/framework/full_type.proto
tensorflow/core/framework/versions.proto
tensorflow/core/framework/op_def.proto
tensorflow/core/framework/graph.proto
tensorflow/core/framework/tensor.proto
tensorflow/core/framework/resource_handle.proto
tensorflow/core/framework/variable.proto

tensorflow_serving/apis/inference.proto
tensorflow_serving/apis/classification.proto
tensorflow_serving/apis/predict.proto
tensorflow_serving/apis/regression.proto
tensorflow_serving/apis/get_model_metadata.proto
tensorflow_serving/apis/input.proto
tensorflow_serving/apis/prediction_service.proto
tensorflow_serving/apis/model.proto

google/protobuf/any.proto
google/protobuf/wrappers.proto
  • Trong thiết bị đầu cuối, hãy chuyển đến thư mục starter/lib/proto/ rồi tạo phần giữ chỗ:
bash generate_grpc_stub_dart.sh

Tạo yêu cầu gRPC

Tương tự như yêu cầu REST, bạn tạo yêu cầu gRPC trong nhánh gRPC.

if (_connectionMode == ConnectionModeType.rest) {

} else {
  // TODO: Create and send the gRPC request.

}
  • Thêm mã này để tạo yêu cầu gRPC:
//Create the gRPC request.
final channel = ClientChannel(_server,
    port: grpcPort,
    options:
        const ChannelOptions(credentials: ChannelCredentials.insecure()));
_stub = PredictionServiceClient(channel,
    options: CallOptions(timeout: const Duration(seconds: 10)));

ModelSpec modelSpec = ModelSpec(
  name: 'spam-detection',
  signatureName: 'serving_default',
);

TensorShapeProto_Dim batchDim = TensorShapeProto_Dim(size: Int64(1));
TensorShapeProto_Dim inputDim =
    TensorShapeProto_Dim(size: Int64(maxSentenceLength));
TensorShapeProto inputTensorShape =
    TensorShapeProto(dim: [batchDim, inputDim]);
TensorProto inputTensor = TensorProto(
    dtype: DataType.DT_INT32,
    tensorShape: inputTensorShape,
    intVal: _tokenIndices);

// If you train your own model, update the input and output tensor names.
const inputTensorName = 'input_3';
const outputTensorName = 'dense_5';
PredictRequest request = PredictRequest(
    modelSpec: modelSpec, inputs: {inputTensorName: inputTensor});

Lưu ý: Tên tensor đầu vào và đầu ra có thể khác nhau giữa các mô hình, ngay cả khi cấu trúc mô hình giống nhau. Hãy nhớ cập nhật các tham số này nếu bạn huấn luyện mô hình của riêng mình.

Gửi yêu cầu gRPC đến TensorFlow Serving

  • Thêm mã này sau đoạn mã trước để gửi yêu cầu gRPC đến TensorFlow Serving:
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);

Xử lý phản hồi gRPC từ TensorFlow Serving

  • Thêm đoạn mã này sau đoạn mã trước để triển khai các hàm gọi lại nhằm xử lý phản hồi:
// Process the response.
if (response.outputs.containsKey(outputTensorName)) {
  if (response.outputs[outputTensorName]!.floatVal[1] >
      classificationThreshold) {
    return 'This sentence is spam. Spam score is ' +
        response.outputs[outputTensorName]!.floatVal[1].toString();
  } else {
    return 'This sentence is not spam. Spam score is ' +
        response.outputs[outputTensorName]!.floatVal[1].toString();
  }
} else {
  throw Exception('Error response');
}

Giờ đây, mã xử lý hậu kỳ sẽ trích xuất kết quả phân loại từ phản hồi và hiển thị kết quả đó trong giao diện người dùng.

Chạy ứng dụng

  1. Nhấp vào a19a0c68bc4046e6.png Start debugging (Bắt đầu gỡ lỗi) rồi đợi ứng dụng tải.
  2. Nhập một số văn bản rồi chọn gRPC > Classify (gRPC > Phân loại).

e44e6e9a5bde2188.png 92644d723f61968c.png

10. Xin chúc mừng

Bạn đã sử dụng TensorFlow Serving để thêm các chức năng phân loại văn bản vào ứng dụng của mình!

Trong lớp học lập trình tiếp theo, bạn sẽ cải tiến mô hình để có thể phát hiện những tin nhắn rác cụ thể mà ứng dụng hiện tại không phát hiện được.

Tìm hiểu thêm