1. قبل البدء
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية تنفيذ استنتاج تصنيف الصور من موقع إلكتروني باستخدام TensorFlow Signing مع REST وgRPC.
المتطلّبات الأساسية
- معرفة أساسية بتطوير برامج الويب، مثل HTML وJavaScript
- معرفة أساسية بتعلُّم الآلة مع TensorFlow، مثل التدريب والنشر
- معرفة أساسية حول محطات الدفع وقاعدة الإرساء
ما ستتعرَّف عليه
- كيفية العثور على نماذج مصنّفة مسبقًا لتصنيف الصور على TensorFlow Hub
- كيفية إنشاء موقع إلكتروني بسيط وتوقّع التوقعات باستخدام نموذج تصنيف الصور الذي تم تنزيله من خلال TensorFlow Driving (REST وgRPC).
- كيفية عرض نتيجة الاكتشاف في واجهة المستخدم.
الأشياء التي تحتاج إليها
- الدوكر
- Google Chrome
- خادم الويب لمتصفّح Chrome
- Node.js وNPM
- البش
- المُجمِّع المؤقت للمخزون المؤقت للبروتوكول (مطلوب فقط إذا كنت تريد إعادة إنشاء مثيل gRPC بنفسك)
- المكوِّن الإضافي لمنشئ رمز موقع gRPC (مطلوب فقط إذا كنت تريد إعادة إنشاء بديل gRPC بنفسك)
2. الإعداد
لتنزيل الرمز في هذا الدرس التطبيقي حول الترميز:
- انتقِل إلى مستودع GitHub.
- انقر على رمز > تنزيل ملف zip لتنزيل كل رموز هذا الدرس التطبيقي حول الترميز.
- يمكنك فك ضغط ملف ZIP الذي تم تنزيله لفك ضغط مجلد الجذر الذي يتضمّن
codelabs
مع جميع الموارد التي تحتاجها.
بالنسبة إلى هذا الدرس التطبيقي حول الترميز، تحتاج فقط إلى الملفات في دليل TFServing/ImageClassificationWeb
الفرعي في المستودع، الذي يحتوي على مجلدَين:
- يتضمّن المجلد
starter
رمز التفعيل الذي تستند إليه في هذا الدرس التطبيقي حول الترميز. - يحتوي مجلد
finished
على الرمز المكتمل لنموذج التطبيق المكتمل.
3- تثبيت التبعيات
لتثبيت التبعيات:
- في الوحدة الطرفية، انتقِل إلى المجلد
starter
ثم ثبِّت حِزم NPM المطلوبة:
npm install
4. تشغيل الموقع الإلكتروني للمبتدئين
استخدِم Web Server for Chrome لتحميل ملف TFServing/ImageClassificationWeb/starter/dist/index.html
:
- أدخِل
Chrome://apps/
في شريط العناوين في Chrome، ثم ابحث عن Web Server for Chrome في قائمة التطبيقات. - افتح خادم الويب لمتصفِّح Chrome، ثم اختَر مجلد
TFServing/ImageClassificationWeb/starter/dist/
. - انقر على مفتاح تبديل خادم الويب لتفعيله ثم انتقِل إلى http://localhost:8887/ في المتصفّح.
إدارة الموقع الإلكتروني واستكشافه
من المفترض أن يظهر لك الموقع الإلكتروني الآن. واجهة المستخدم سهلة الاستخدام، فهي توفّر صورة للقطط تريد تصنيفها، ويمكن للمستخدم إرسال البيانات إلى الخلفية باستخدام REST أو gRPC. تؤدي الخلفية إلى تصنيف الصورة على أنها تعرض نتيجة التصنيف لموقع الويب الذي يعرض النتيجة.
إذا نقرت على التصنيف، لن يحدث شيء لأنه لا يمكن التواصل مع الخلفية بعد.
5. نشر نموذج تصنيف الصور باستخدام TensorFlow
يُعدّ تصنيف الصور مهمة شائعة جدًا تتعلّق بتعلّم الآلة وتصنيف الصورة إلى فئات محدّدة مسبقًا استنادًا إلى المحتوى الأساسي للصورة. في ما يلي مثال على تصنيف الزهور:
هناك عدد من نماذج تصنيف الصور المدرَّبة مسبقًا في TensorFlow Hub. أنت تستخدم نموذجًا شهيرًا من Incetion v3 لهذا الدرس التطبيقي حول الترميز.
لنشر نموذج تصنيف الصور مع TensorFlow:
- نزِّل ملف النموذج Incetion v3.
- يمكنك فك ضغط ملف
.tar.gz
الذي تم تنزيله باستخدام أداة فك ضغط، مثل 7-Zip. - يمكنك إنشاء مجلد
inception_v3
ثم إنشاء مجلد فرعي فيه123
. - ضع المجلد
variables
المستخرج والملفsaved_model.pb
في المجلد الفرعي123
.
يمكنك الإشارة إلى المجلد inception_v3
باعتباره المجلد SavedModel
. 123
هو مثال على رقم الإصدار. يمكنك اختيار رقم آخر، إذا أردت ذلك.
يجب أن تظهر بنية المجلد على النحو التالي:
بدء عرض TensorFlow
- في الوحدة الطرفية، ابدأ تشغيل TensorFlow للعرض باستخدام docker، ولكن استبدِل
PATH/TO/SAVEDMODEL
بالمسار المطلق للمجلدinception_v3
على جهاز الكمبيوتر.
docker pull tensorflow/serving docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/inception" -e MODEL_NAME=inception 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/inception/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/inception/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: inception 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 ...
6- إعداد خادم وكيل Envoy
في الوقت الحالي، لا تضبط خدمة TensorFlow للعرض عنوان Access-Control-Allow-Origin
، وبالتالي يحظر المتصفّح الطلب من JavaScript من الواجهة الأمامية إلى TensorFlow العرض لأسباب أمنية. ولحل هذا الأمر، يجب استخدام خادم وكيل، مثل Envoy، لربط الطلب من JavaScript بواجهة TensorFlow العرضية.
بدء Envoy
- في الوحدة الطرفية، نزِّل صورة Envoy وابدأ تشغيل Envoy باستخدام docker، ولكن استبدل العنصر النائب
PATH/TO/ENVOY-CUSTOM.YAML
بالمسار المطلق للملفenvoy-custom.yaml
في مجلدstarter
.
docker pull envoyproxy/envoy-dev:fd3e8370ddb7a96634c192d1461516e6de1d1797 docker run --add-host host.docker.internal:host-gateway --rm -it -p 9901:9901 -p 8000:8000 -p 8080:8080 -v PATH/TO/ENVOY-CUSTOM.YAML:/envoy-custom.yaml envoyproxy/envoy-dev:fd3e8370ddb7a96634c192d1461516e6de1d1797 -c /envoy-custom.yaml
ينزّل docker صورة Envoy تلقائيًا أولاً. بَعْدَ ذَلِكَ، يَجِبُ أَنْ يَبْدَأَ أَنْفُوِي. يجب أن يظهر السجل مثل مقتطف الرمز هذا:
[2022-03-02 07:51:48.563][1][info][main] [source/server/server.cc:436] response trailer map: 152 bytes: grpc-message,grpc-status [2022-03-02 07:51:48.681][1][info][main] [source/server/server.cc:772] runtime: {} [2022-03-02 07:51:48.682][1][info][admin] [source/server/admin/admin.cc:134] admin address: 0.0.0.0:9901 [2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:127] loading tracing configuration [2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:87] loading 0 static secret(s) [2022-03-02 07:51:48.683][1][info][config] [source/server/configuration_impl.cc:93] loading 2 cluster(s) [2022-03-02 07:51:48.687][1][info][config] [source/server/configuration_impl.cc:97] loading 2 listener(s) [2022-03-02 07:51:48.694][1][info][config] [source/server/configuration_impl.cc:109] loading stats configuration [2022-03-02 07:51:48.696][1][info][main] [source/server/server.cc:868] starting main dispatch loop [2022-03-02 07:51:48.881][1][info][runtime] [source/common/runtime/runtime_impl.cc:446] RTDS has finished initialization [2022-03-02 07:51:48.881][1][info][upstream] [source/common/upstream/cluster_manager_impl.cc:207] cm init: all clusters initialized [2022-03-02 07:51:48.881][1][info][main] [source/server/server.cc:849] all clusters initialized. initializing init manager [2022-03-02 07:51:48.881][1][info][config] [source/server/listener_manager_impl.cc:784] all dependencies initialized. starting workers [2022-03-02 07:51:48.902][1][warning][main] [source/server/server.cc:747] there is no configured limit to the number of allowed active connections. Set a limit via the runtime key overload.global_downstream_max_connections
7- ربط الموقع الإلكتروني بتطبيق TensorFlow من خلال REST
أصبحت الخلفية الآن جاهزة الآن حتى تتمكن من إرسال طلبات العميل إلى TensorFlow العرض لتصنيف الصور. تتوفّر طريقتان لإرسال الطلبات إلى TensorFlow Driving:
- استراحة
- gRPC
إرسال طلبات وتلقّي ردود من خلال REST
هناك ثلاث خطوات بسيطة لإرسال الطلبات واستلامها من خلال خدمة REST:
- إنشاء طلب REST.
- يُرجى إرسال طلب REST إلى TensorFlow serving.
- استخرج النتيجة المتوقعة من استجابة REST واعرض النتيجة.
يمكنك تنفيذ هذه الخطوات في ملف src/index.js
.
إنشاء طلب REST
لا ترسل دالة classify_img()
في الوقت الحالي طلب REST إلى TensorFlow العرض. عليك تنفيذ فرع REST هذا لإنشاء طلب REST أولاً:
if (radioButtons[0].checked) {
console.log('Using REST');
// TODO: Add code to send a REST request to TensorFlow Serving.
}
تتوقع خدمة TensorFlow عرض طلب POST يحتوي على موتّر الصورة لنموذج Incetion v3 الذي تستخدمه، لذا تحتاج إلى استخراج قيم RGB من كل بكسل للصورة إلى مصفوفة ثم لفّ المصفوفة بتنسيق JSON، وهو حمولة الطلب.
- إضافة هذا الرمز إلى فرع REST:
//Create the REST request.
let imgTensor = new Array();
let pixelArray = new Array();
context.drawImage(img, 0, 0);
for(let i=0; i<inputImgHeight; i++) {
pixelArray[i] = new Array();
for (let j=0; j<inputImgWidth; j++) {
pixelArray[i][j] = new Array();
pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[0]/255);
pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[1]/255);
pixelArray[i][j].push(context.getImageData(i, j, 1, 1).data[2]/255);
}
}
imgTensor.push(pixelArray);
const RESTURL = 'http://localhost:8000/v1/models/inception:predict';
let xhr = new XMLHttpRequest();
xhr.open('POST', RESTURL);
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8;');
let data = JSON.stringify({
instances: imgTensor
});
xhr.onload = () => {
}
xhr.onerror = () => {
console.log('REST request error');
}
إرسال طلب REST إلى TensorFlow للعرض
يمكنك الآن إرسال الطلب.
- أضف هذا الرمز مباشرةً بعد الرمز أعلاه في فرع REST:
// Send the REST request.
xhr.send(data);
معالجة استجابة REST من TensorFlow العرض
يعرض نموذج Inception v3 مجموعة من الاحتمالات التي تنتمي إليها الصورة في فئات محدّدة مسبقًا. عند نجاح التوقّع، يجب إخراج أكثر فئة احتمالية في واجهة المستخدم.
ويمكنك تنفيذ أداة معالجة onload()
لمعالجة الرد.
xhr.onload = () => {
}
- إضافة هذا الرمز إلى المستمع
onload()
:
// Process the REST response.
const response = JSON.parse(xhr.responseText);
const maxIndex = argmax(response['predictions'][0])
document.getElementById('category').textContent = 'Predicted category: ' + maxIndex;
والآن، يستخلص المستمع الاحتمالات المتوقعة من الاستجابة، ويحدّد الفئة الأكثر احتمالاً للعنصر، ويعرض النتيجة في واجهة المستخدم.
التشغيل
- في المحطّة الطرفية، انتقِل إلى المجلد
starter
واستخدِم Webpack لتجميع كل ملفات JavaScript في ملف واحد، يمكنك تضمينه في ملفdist/index.html
:
npm install -g npx npm install --save-dev webpack npx webpack
- حدّث http://localhost:8887/ في المتصفح وانقر على REST > Classify.
يعرض الموقع الإلكتروني 286
على أنه الفئة المتوقعة التي يتم ربطها بتصنيف Egyptian Cat
في مجموعة بيانات الصور على NetNet.
8- ربط الموقع الإلكتروني بخدمة TensorFlow من خلال gRPC
بالإضافة إلى REST، تتوافق خدمة TensorFlow أيضًا مع gRPC.
gRPC هو إطار عمل حديث ومفتوح المصدر وعالي الأداء للإجراءات عن بُعد يمكن تشغيله في أي بيئة. وتستطيع هذه الخدمة توصيل الخدمات بكفاءة في مراكز البيانات وفي مناطق أخرى مع دعم قابل للتوصيل لموازنة الحِمل وتتبُّع الحالة الصحية والمصادقة. لقد لاحظنا أن gRPC هو أكثر أداءً من REST من الناحية العملية.
إرسال الطلبات وتلقّي الردود باستخدام gRPC
هناك أربع خطوات بسيطة:
- اختياري: أنشئ رمز كائن gRPC للعميل.
- إنشاء طلب gRPC.
- أرسِل طلب gRPC إلى TensorFlow العرض.
- استخرِج النتيجة المتوقعة من استجابة gRPC وعرضها في واجهة المستخدم.
يمكنك إكمال هذه الخطوات في ملف src/index.js
.
اختياري: إنشاء رمز كائن gRPC للعميل
لاستخدام gRPC مع عرض TensorFlow، عليك اتّباع طريقة عمل gRPC. لمعرفة المزيد من التفاصيل، يُرجى الاطّلاع على وثائق gRPC.
يشكّل 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
- في الوحدة الطرفية، انتقِل إلى المجلد
starter/src/proto/
وأنشِئ التنويه الموجز:
bash generate_grpc_stub_js.sh
إنشاء طلب gRPC
على غرار طلب REST، يمكنك إنشاء طلب gRPC في فرع gRPC..
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
}
else {
print("Using gRPC")
// TODO: Add code to send a gRPC request to TensorFlow Serving.
}
- إضافة هذا الرمز إلى فرع gRPC:
// Create the gRPC request.
const PredictModule = require('./proto/generated/tensorflow_serving/apis/predict_pb.js');
const PredictionServiceClientModule = require('./proto/generated/tensorflow_serving/apis/prediction_service_grpc_web_pb.js');
const ModelModule = require('./proto/generated/tensorflow_serving/apis/model_pb.js');
const TensorModule = require('./proto/generated/tensorflow/core/framework/tensor_pb.js');
const GPRCURL = 'http://localhost:8080';
const stub = new PredictionServiceClientModule.PredictionServiceClient(GPRCURL);
const modelSpec = new ModelModule.ModelSpec();
modelSpec.setName('inception');
const tensorProto = new TensorModule.TensorProto();
const tensorShapeProto = new TensorModule.TensorShapeProto();
const batchDim = (new TensorModule.TensorShapeProto.Dim()).setSize(1);
const heightDim = (new TensorModule.TensorShapeProto.Dim()).setSize(inputImgHeight);
const widthDim = (new TensorModule.TensorShapeProto.Dim()).setSize(inputImgWidth);
const channelDim = (new TensorModule.TensorShapeProto.Dim()).setSize(3);
tensorShapeProto.setDimList([batchDim, heightDim, widthDim, channelDim]);
tensorProto.setDtype(proto.tensorflow.DataType.DT_FLOAT);
tensorProto.setTensorShape(tensorShapeProto);
context.drawImage(img, 0, 0);
for(let i=0; i<inputImgHeight; i++) {
for (let j=0; j<inputImgWidth; j++) {
tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[0]/255);
tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[1]/255);
tensorProto.addFloatVal(context.getImageData(i, j, 1, 1).data[2]/255);
}
}
const predictionServiceRequest = new PredictModule.PredictRequest();
predictionServiceRequest.setModelSpec(modelSpec);
predictionServiceRequest.getInputsMap().set('inputs', tensorProto);
إرسال طلب gRPC إلى TensorFlow العرض
يمكنك الآن إرسال الطلب.
- أضف هذا الرمز مباشرةً بعد الرمز في فرع gRPC في مقتطف الرمز السابق:
// Send the gRPC request.
stub.predict(predictionServiceRequest, {}, function(err, response) {
// TODO: Add code to process the response.
});
معالجة استجابة gRPC من TensorFlow
وأخيرًا، نفّذ دالة رد الاتصال أعلاه للتعامل مع الاستجابة.
- أضف هذا الرمز إلى نص الدالة في مقتطف الرمز السابق:
// Process the gRPC response.
if (err) {
console.log(err.code);
console.log(err.message);
}
else {
const maxIndex = argmax(response.getOutputsMap().get('logits').getFloatValList());
document.getElementById('category').textContent = 'Predicted category: ' + maxIndex;
}
والآن، يستخلص المستمع الاحتمالات المتوقعة من الاستجابة، ويحدّد الفئة الأكثر احتمالاً للعنصر، ويعرض النتيجة في واجهة المستخدم.
التشغيل
- في المحطّة الطرفية، استخدِم حزمة الويب لتجميع جميع ملفات JavaScript في ملف واحد يمكنك تضمينه في ملف
index.html
:
npx webpack
- حدّث http://localhost:8887/ في متصفحك.
- انقر على gRPC > Classification.
ويعرض الموقع الإلكتروني الفئة المتوقّعة التي تبلغ 286
، والتي يتم ربطها بتصنيف Egyptian Cat
في مجموعة بيانات ImageNet.
9- تهانينا
استخدمت منصة TensorFlow لعرض إمكانيات تصنيف الصور على موقعك الإلكتروني.