إنشاء تطبيق Flutter لتصنيف النصوص

1. قبل البدء

في هذا الدرس التطبيقي، ستتعرّف على كيفية تنفيذ استنتاج لتصنيف النصوص من تطبيق Flutter باستخدام TensorFlow Serving من خلال REST وgRPC.

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

أهداف الدورة التعليمية

  • كيفية إنشاء تطبيق بسيط باستخدام Flutter وتصنيف النصوص من خلال TensorFlow Serving (REST وgRPC)
  • كيفية عرض النتائج في واجهة المستخدم

المتطلبات

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

لتطوير تطبيقات Flutter، تحتاج إلى برنامجَين لإكمال هذا التمرين العملي، وهما حزمة تطوير البرامج (SDK) الخاصة بـ Flutter ومحرِّر.

يمكنك تشغيل الدرس العملي باستخدام أيّ من الأجهزة التالية:

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

3- طريقة الإعداد

لتنزيل الرمز البرمجي لهذا الدرس التطبيقي حول الترميز، اتّبِع الخطوات التالية:

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

2cd45599f51fb8a2.png

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

في هذا الدرس العملي، تحتاج فقط إلى الملفات في الدليل الفرعي tfserving-flutter/codelab2 في المستودع، والذي يحتوي على مجلدَين:

  • يحتوي المجلد starter على الرمز الأولي الذي ستستند إليه في هذا الدرس العملي.
  • يحتوي المجلد finished على الرمز البرمجي المكتمل لتطبيق العيّنة النهائي.

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

  1. في VS Code، انقر على ملف > فتح مجلد، ثم اختَر المجلد starter من رمز المصدر الذي نزّلته سابقًا.
  2. إذا ظهر لك مربّع حوار يطلب منك تنزيل الحِزم المطلوبة لتطبيق المبتدئين، انقر على الحصول على الحِزم.
  3. إذا لم يظهر لك مربع الحوار هذا، افتح الوحدة الطرفية ثم نفِّذ الأمر flutter pub get في المجلد starter.

7ada07c300f166a6.png

5- تشغيل التطبيق النموذجي

  1. في VS Code، تأكَّد من إعداد "محاكي Android" أو "محاكي iOS" بشكل صحيح وظهورهما في شريط الحالة.

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

9767649231898791.png

في ما يلي ما يظهر عند استخدام iPhone 13 مع iOS Simulator:

95529e3a682268b2.png

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

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

يجب تشغيل التطبيق على "محاكي Android" أو "محاكي iOS". واجهة المستخدم بسيطة جدًا. يتوفّر حقل نص يتيح للمستخدم كتابة النص. يمكن للمستخدم اختيار ما إذا كان يريد إرسال البيانات إلى الخلفية باستخدام REST أو gRPC. يستخدم الخلفية نموذج TensorFlow لتنفيذ تصنيف النصوص على الإدخال الذي تمت معالجته مسبقًا، ويعرض نتيجة التصنيف لتطبيق العميل الذي يعدّل واجهة المستخدم بدوره.

b298f605d64dc132.png d3ef3ccd3c338108.png

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

6. نشر نموذج لتصنيف النصوص باستخدام TensorFlow Serving

تصنيف النصوص هو مهمة شائعة جدًا في مجال تعلُّم الآلة، وتصنّف النصوص إلى فئات محدَّدة مسبقًا. في هذا الدرس التطبيقي حول الترميز، ستنشر النموذج المدرَّب مسبقًا من الدرس التطبيقي حول الترميز الخاص بتدريب نموذج رصد التعليقات غير المرغوب فيها باستخدام أداة Model Maker في TensorFlow Lite باستخدام TensorFlow Serving، وستطلب من الخلفية من واجهة Flutter الأمامية تصنيف النص المُدخَل على أنّه غير مرغوب فيه أو مرغوب فيه.

بدء TensorFlow Serving

  • في نافذة الأوامر، ابدأ TensorFlow Serving باستخدام Docker، ولكن استبدِل العنصر النائب PATH/TO/SAVEDMODEL بالمسار المطلق للمجلد mm_spam_savedmodel على جهاز الكمبيوتر.
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

ينزّل Docker تلقائيًا صورة TensorFlow Serving أولاً، ويستغرق ذلك دقيقة واحدة. بعد ذلك، من المفترض أن يبدأ TensorFlow Serving. يجب أن يبدو السجلّ على النحو التالي:

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. إنشاء رمز مميز للجملة المدخلة

أصبحت الخلفية جاهزة الآن، لذا أنت على وشك أن تصبح جاهزًا لإرسال طلبات العميل إلى TensorFlow Serving، ولكن عليك أولاً تحويل الجملة المدخلة إلى رموز مميزة. إذا فحصت موتر الإدخال الخاص بالنموذج، يمكنك ملاحظة أنّه يتوقّع قائمة تضم 20 عددًا صحيحًا بدلاً من السلاسل الأولية. التقسيم إلى رموز مميزة هو عملية ربط الكلمات الفردية التي تكتبها في التطبيق بقائمة من الأعداد الصحيحة استنادًا إلى قاموس المفردات قبل إرسالها إلى الخلفية لتصنيفها. على سبيل المثال، إذا كتبت buy book online to learn more، سيتم ربطها بـ [32, 79, 183, 10, 224, 631, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] في عملية تحويل النص إلى رموز مميزة. يمكن أن تختلف الأرقام المحددة استنادًا إلى قاموس المفردات.

  1. في الملف lib/main.dart، أضِف الرمز التالي إلى الطريقة predict() لإنشاء قاموس المفردات _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. بعد مقتطف الرمز السابق مباشرةً، أضِف الرمز التالي لتنفيذ عملية الترميز:
// 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;
  }
}

يؤدي هذا الرمز إلى تحويل سلسلة الجملة إلى أحرف صغيرة وإزالة الأحرف غير الأبجدية وربط الكلمات بفهارس 20 عددًا صحيحًا استنادًا إلى جدول المفردات.

8. ربط تطبيق Flutter بمنصة TensorFlow للعرض من خلال REST

هناك طريقتان لإرسال الطلبات إلى TensorFlow Serving:

  • REST
  • gRPC

إرسال الطلبات وتلقّي الردود من خلال REST

هناك ثلاث خطوات بسيطة لإرسال الطلبات وتلقّي الردود من خلال REST:

  1. أنشئ طلب REST.
  2. أرسِل طلب REST إلى TensorFlow Serving.
  3. استخرِج النتيجة المتوقّعة من ردّ REST واعرض واجهة المستخدم.

يمكنك إكمال هذه الخطوات في الملف main.dart.

إنشاء طلب REST وإرساله إلى TensorFlow Serving

  1. في الوقت الحالي، لا ترسل الدالة predict() طلب REST إلى TensorFlow Serving. عليك تنفيذ فرع REST لإنشاء طلب REST:
if (_connectionMode == ConnectionModeType.rest) {
  // TODO: Create and send the REST request.

}
  1. أضِف الرمز التالي إلى فرع 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],
  }),
);

معالجة استجابة REST من TensorFlow Serving

  • أضِف هذا الرمز بعد مقتطف الرمز السابق مباشرةً للتعامل مع استجابة 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');
}

يستخرج رمز المعالجة اللاحقة احتمال أن تكون الجملة المُدخَلة رسالة غير مرغوب فيها من الرد ويعرض نتيجة التصنيف في واجهة المستخدم.

تشغيلها

  1. انقر على a19a0c68bc4046e6.png بدء تصحيح الأخطاء ثم انتظِر إلى أن يتم تحميل التطبيق.
  2. أدخِل بعض النص ثم انقر على REST > تصنيف.

8e21d795af36d07a.png e79a0367a03c2169.png

9- ربط تطبيق Flutter بخدمة TensorFlow Serving من خلال gRPC

بالإضافة إلى REST، يتيح TensorFlow Serving أيضًا استخدام gRPC.

b6f4449c2c850b0e.png

‫gRPC هو إطار عمل حديث ومفتوح المصدر وعالي الأداء لاستدعاء الإجراءات عن بُعد (RPC) يمكن تشغيله في أي بيئة. يمكنه ربط الخدمات بكفاءة داخل مراكز البيانات وفي ما بينها مع إمكانية إضافة ميزات موازنة التحميل والتتبُّع والتحقّق من الصحة والمصادقة. وقد تبيّن أنّ gRPC يتفوّق على REST من حيث الأداء في الواقع العملي.

إرسال الطلبات وتلقّي الردود باستخدام gRPC

في ما يلي أربع خطوات بسيطة لإرسال الطلبات وتلقّي الردود باستخدام gRPC:

  1. اختياري: إنشاء رمز بديل لعميل gRPC
  2. أنشِئ طلب gRPC.
  3. أرسِل طلب gRPC إلى TensorFlow Serving.
  4. استخرِج النتيجة المتوقّعة من استجابة gRPC واعرض واجهة المستخدم.

يمكنك إكمال هذه الخطوات في الملف main.dart.

اختياري: إنشاء رمز بديل لعميل gRPC

لاستخدام gRPC مع TensorFlow Serving، عليك اتّباع سير عمل gRPC. لمزيد من المعلومات عن التفاصيل، يُرجى الاطّلاع على مستندات gRPC.

a9d0e5cb543467b4.png

تحدّد منصة TensorFlow للعرض وTensorFlow ملفات .proto نيابةً عنك. اعتبارًا من الإصدار 2.8 من TensorFlow وTensorFlow Serving، هذه هي ملفات .proto المطلوبة:

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
  • في الوحدة الطرفية، انتقِل إلى المجلد starter/lib/proto/ وأنشئ رمزًا زائفًا:
bash generate_grpc_stub_dart.sh

إنشاء طلب gRPC

على غرار طلب REST، يمكنك إنشاء طلب gRPC في فرع gRPC.

if (_connectionMode == ConnectionModeType.rest) {

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

}
  • أضِف الرمز التالي لإنشاء طلب 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});

ملاحظة: قد تختلف أسماء موترات الإدخال والإخراج من نموذج إلى آخر، حتى إذا كانت بنية النماذج هي نفسها. احرص على تعديلها إذا درّبت نموذجك الخاص.

إرسال طلب gRPC إلى TensorFlow Serving

  • أضِف هذا الرمز بعد مقتطف الرمز السابق لإرسال طلب gRPC إلى TensorFlow Serving:
// Send the gRPC request.
PredictResponse response = await _stub.predict(request);

معالجة استجابة gRPC من TensorFlow Serving

  • أضِف هذا الرمز بعد مقتطف الرمز السابق لتنفيذ دوال ردّ الاتصال للتعامل مع الردّ:
// 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');
}

الآن، يستخرج رمز ما بعد المعالجة نتيجة التصنيف من الرد ويعرضها في واجهة المستخدم.

تشغيلها

  1. انقر على a19a0c68bc4046e6.png بدء تصحيح الأخطاء ثم انتظِر إلى أن يتم تحميل التطبيق.
  2. أدخِل بعض النص ثم انقر على gRPC > تصنيف.

e44e6e9a5bde2188.png 92644d723f61968c.png

10. تهانينا

لقد استخدمت TensorFlow Serving لإضافة إمكانات تصنيف النصوص إلى تطبيقك.

في تجربة البرمجة التالية، ستعمل على تحسين النموذج حتى تتمكّن من رصد رسائل غير مرغوب فيها معيّنة لا يمكن للتطبيق الحالي رصدها.

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