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

1. قبل البدء

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

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

ما ستتعرَّف عليه

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

الأشياء التي تحتاج إليها

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

لتطوير Flutter، تحتاج إلى برنامجَين لإكمال هذا الدرس التطبيقي، وهما Fltter SDK ومحرّر.

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

  • محاكي 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، انقر على File > افتح المجلد ثم اختَر المجلد starter من رمز المصدر الذي نزّلته سابقًا.
  2. إذا ظهر مربع حوار يطلب منك تنزيل الحزم المطلوبة للتطبيق للمبتدئين، انقر على الحصول على الحزم.
  3. إذا لم يظهر لك مربع الحوار هذا، افتح محطّة الدفع، ثم شغِّل الأمر flutter pub get في المجلد starter.

7ada07c300f166a6.png

5. تشغيل تطبيق إجراء التفعيل

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

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

9767649231898791.png

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

95529e3a682268b2.png

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

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

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

b298f605d64dc132.png d3ef3ccd3c338108.png

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

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

يُعدّ تصنيف النص مهمة شائعة جدًا لتعلُّم الآلة وتصنّف النصوص ضمن فئات محدّدة مسبقًا. في هذا الدرس التطبيقي حول الترميز، يمكنك نشر النموذج الذي تم تدريبه مسبقًا من تدريب نموذج رصد التعليقات غير المرغوب فيها باستخدام TensorFlow Lite Maker Maker Code (برنامج الترميز) باستخدام TensorFlow Works والاستدعاء للخلفية من الواجهة الأمامية لتطبيق Flutter لتصنيف نص الإدخال على أنه رسائل غير مرغوب فيها أو ليس محتوى غير مرغوب فيه.

بدء عرض TensorFlow

  • في الوحدة الطرفية، ابدأ تشغيل TensorFlow للعرض باستخدام 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 أولاً، الأمر الذي يستغرق دقيقة واحدة. بعد ذلك، من المفترض أن يبدأ عرض TensorFlow. يجب أن يظهر السجل مثل مقتطف الرمز هذا:

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 Works، ولكن تحتاج أولاً إلى إنشاء رمز مميز لجملة الإدخال. إذا أجريت فحصًا لموتر الإدخال للنموذج، يمكنك ملاحظة أنّه يتوقع قائمة من 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 Driving:

  • استراحة
  • gRPC

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

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

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

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

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

  1. لا ترسل دالة predict() في الوقت الحالي طلب REST إلى TensorFlow العرض. عليك تنفيذ فرع 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 العرض

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

8e21d795af36d07a.png e79a0367a03c2169.png

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

بالإضافة إلى REST، تتوافق خدمة TensorFlow أيضًا مع gRPC.

b6f4449c2c850b0e.png

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

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

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

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

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

اختياري: إنشاء رمز كائن gRPC للعميل

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

a9d0e5cb543467b4.png

يشكّل TensorFlow للعرض وTensorFlow ملفات .proto بالنيابة عنك. اعتبارًا من TensorFlow وTensorFlow العرض 2.8، يجب توفير الملفات التالية .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 العرض

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

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

  • يمكنك إضافة هذا الرمز بعد مقتطف الرمز السابق لتنفيذ وظائف رد الاتصال في التعامل مع الاستجابة:
// 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 > Classify.

e44e6e9a5bde2188.png 92644d723f61968c.png

10- تهانينا

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

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

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