استخدام نموذج TensorFlow Lite المخصّص على منصات Apple

إذا كان تطبيقك يستخدم نماذج TensorFlow Lite مخصّصة، يمكنك استخدام Firebase ML لنشر نماذجك. من خلال نشر النماذج باستخدام Firebase، يمكنك تقليل حجم التنزيل الأولي لـ تطبيقك وتحديث نماذج تعلُّم الآلة في تطبيقك بدون إصدار إصدار جديد من تطبيقك. وباستخدام Remote Config وA/B Testing، يمكنك عرض نماذج مختلفة بشكل ديناميكي لمجموعات مختلفة من المستخدمين.

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

  • لا تتوفّر مكتبة MLModelDownloader إلا للغة Swift.
  • لا يعمل TensorFlow Lite إلا على الأجهزة التي تستخدم iOS 9 والإصدارات الأحدث.

نماذج TensorFlow Lite

نماذج TensorFlow Lite هي نماذج تعلُّم آلة تم تحسينها للعمل على الأجهزة الجوّالة للحصول على نموذج TensorFlow Lite:

قبل البدء

لاستخدام TensorFlowLite مع Firebase، عليك استخدام CocoaPods لأنّ TensorFlowLite لا يتيح حاليًا التثبيت باستخدام Swift Package Manager. يُرجى الاطّلاع على دليل تثبيت CocoaPods للحصول على تعليمات حول كيفية تثبيت MLModelDownloader.

بعد التثبيت، استورِد Firebase وTensorFlowLite لاستخدامهما.

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

1. نشر النموذج

انشر نماذج TensorFlow المخصّصة باستخدام إما وحدة تحكّم Firebase أو حِزمتَي Firebase Admin Python وNode.js SDK. يُرجى الاطّلاع على مقالة نشر النماذج المخصّصة وإدارتها.

بعد إضافة نموذج مخصّص إلى مشروع Firebase، يمكنك الإشارة إلى الـ نموذج في تطبيقاتك باستخدام الاسم الذي حدّدته. في أي وقت، يمكنك نشر نموذج TensorFlow Lite جديد وتنزيل النموذج الجديد على أجهزة المستخدمين من خلال استدعاء getModel() (راجِع أدناه).

2. تنزيل النموذج على الجهاز وتهيئة مفسّر TensorFlow Lite

لاستخدام نموذج TensorFlow Lite في تطبيقك، استخدِم أولاً Firebase ML SDK لتنزيل أحدث إصدار من النموذج على الجهاز.

لبدء تنزيل النموذج، استدعِ طريقة getModel() في أداة تنزيل النماذج، مع تحديد الاسم الذي خصّصته للنموذج عند تحميله، وما إذا كنت تريد تنزيل أحدث نموذج دائمًا، والشروط التي تريد السماح بموجبها بالتنزيل.

يمكنك الاختيار من بين ثلاثة سلوكيات للتنزيل:

نوع التنزيل الوصف
localModel الحصول على النموذج المحلي من الجهاز إذا لم يتوفّر نموذج محلي، سيتصرّف هذا الخيار مثل latestModel. استخدِم هذا النوع من التنزيل إذا لم تكن مهتمًا بالتحقّق من توفّر تحديثات للنموذج. على سبيل المثال، أنت تستخدم "الإعداد عن بُعد" لاسترداد أسماء النماذج وتحمّل النماذج دائمًا بأسماء جديدة (ننصحك بذلك).
localModelUpdateInBackground الحصول على النموذج المحلي من الجهاز وبدء تحديث النموذج في الخلفية إذا لم يتوفّر نموذج محلي، سيتصرّف هذا الخيار مثل latestModel.
latestModel الحصول على أحدث نموذج إذا كان النموذج المحلي هو أحدث إصدار، يتم عرض النموذج المحلي. وإلا، يتم تنزيل أحدث نموذج. سيتم حظر هذا السلوك إلى أن يتم تنزيل أحدث إصدار (لا ننصحك بذلك). استخدِم هذا السلوك فقط في الحالات التي تحتاج فيها صراحةً إلى أحدث إصدار.

عليك إيقاف الوظائف المرتبطة بالنموذج، مثلاً، إخفاء جزء من واجهة المستخدم أو عرضه باللون الرمادي، إلى أن تتأكّد من تنزيل النموذج.

Swift

let conditions = ModelDownloadConditions(allowsCellularAccess: false)
ModelDownloader.modelDownloader()
    .getModel(name: "your_model",
              downloadType: .localModelUpdateInBackground,
              conditions: conditions) { result in
        switch (result) {
        case .success(let customModel):
            do {
                // Download complete. Depending on your app, you could enable the ML
                // feature, or switch from the local model to the remote model, etc.

                // The CustomModel object contains the local path of the model file,
                // which you can use to instantiate a TensorFlow Lite interpreter.
                let interpreter = try Interpreter(modelPath: customModel.path)
            } catch {
                // Error. Bad model file?
            }
        case .failure(let error):
            // Download was unsuccessful. Don't enable ML features.
            print(error)
        }
}

تبدأ العديد من التطبيقات مهمة التنزيل في رمز التهيئة، ولكن يمكنك إجراء ذلك في أي وقت قبل أن تحتاج إلى استخدام النموذج.

3. إجراء الاستنتاج على بيانات الإدخال

الحصول على أشكال الإدخال والإخراج في نموذجك

يأخذ مفسّر نموذج TensorFlow Lite صفيفًا واحدًا أو أكثر من الصفائف المتعدّدة الأبعاد كإدخال ويُنتجها كإخراج. تحتوي هذه الصفائف على قيم byte أو int أو long أو float. قبل أن تتمكّن من تمرير البيانات إلى نموذج أو استخدام نتيجته، عليك معرفة عدد الصفائف التي يستخدمها نموذجك وأبعادها ("شكلها").

إذا أنشأت النموذج بنفسك، أو إذا تم توثيق تنسيق الإدخال والإخراج للنموذج، قد تكون لديك هذه المعلومات. إذا لم تكن تعرف الـ شكل ونوع بيانات الإدخال والإخراج في نموذجك، يمكنك استخدام الـ مفسّر TensorFlow Lite لفحص نموذجك. على سبيل المثال:

Python

import tensorflow as tf

interpreter = tf.lite.Interpreter(model_path="your_model.tflite")
interpreter.allocate_tensors()

# Print input shape and type
inputs = interpreter.get_input_details()
print('{} input(s):'.format(len(inputs)))
for i in range(0, len(inputs)):
    print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype']))

# Print output shape and type
outputs = interpreter.get_output_details()
print('\n{} output(s):'.format(len(outputs)))
for i in range(0, len(outputs)):
    print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))

مثال على الإخراج:

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

تشغيل المفسّر

بعد تحديد تنسيق الإدخال والإخراج في نموذجك، احصل على بيانات الإدخال وأجرِ أي عمليات تحويل على البيانات اللازمة للحصول على إدخال بالشكل المناسب لنموذجك.

على سبيل المثال، إذا كان نموذجك يعالج الصور، وكانت أبعاد الإدخال في نموذجك هي [1, 224, 224, 3] لقيم النقطة العائمة، قد تحتاج إلى تغيير حجم قيم ألوان الصورة إلى نطاق النقطة العائمة كما في المثال التالي:

Swift

let image: CGImage = // Your input image
guard let context = CGContext(
  data: nil,
  width: image.width, height: image.height,
  bitsPerComponent: 8, bytesPerRow: image.width * 4,
  space: CGColorSpaceCreateDeviceRGB(),
  bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
) else {
  return false
}

context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
guard let imageData = context.data else { return false }

var inputData = Data()
for row in 0 ..&lt; 224 {
  for col in 0 ..&lt; 224 {
    let offset = 4 * (row * context.width + col)
    // (Ignore offset 0, the unused alpha channel)
    let red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
    let green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
    let blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)

    // Normalize channel values to [0.0, 1.0]. This requirement varies
    // by model. For example, some models might require values to be
    // normalized to the range [-1.0, 1.0] instead, and others might
    // require fixed-point values or the original bytes.
    var normalizedRed = Float32(red) / 255.0
    var normalizedGreen = Float32(green) / 255.0
    var normalizedBlue = Float32(blue) / 255.0

    // Append normalized values to Data object in RGB order.
    let elementSize = MemoryLayout.size(ofValue: normalizedRed)
    var bytes = [UInt8](repeating: 0, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedRed, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedGreen, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&ammp;bytes, &amp;normalizedBlue, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
  }
}

بعد ذلك، انسخ NSData للإدخال إلى المفسّر وشغِّله:

Swift

try interpreter.allocateTensors()
try interpreter.copy(inputData, toInputAt: 0)
try interpreter.invoke()

يمكنك الحصول على ناتج النموذج من خلال استدعاء طريقة output(at:) في المفسّر. تعتمد طريقة استخدام الناتج على النموذج الذي تستخدمه.

على سبيل المثال، إذا كنت تجري عملية تصنيف، قد تربط في الخطوة التالية فهارس النتيجة بالتصنيفات التي تمثّلها:

Swift

let output = try interpreter.output(at: 0)
let probabilities =
        UnsafeMutableBufferPointer<Float32>.allocate(capacity: 1000)
output.data.copyBytes(to: probabilities)

guard let labelPath = Bundle.main.path(forResource: "retrained_labels", ofType: "txt") else { return }
let fileContents = try? String(contentsOfFile: labelPath)
guard let labels = fileContents?.components(separatedBy: "\n") else { return }

for i in labels.indices {
    print("\(labels[i]): \(probabilities[i])")
}

الملحق: أمان النموذج

بغض النظر عن كيفية إتاحة نماذج TensorFlow Lite لـ Firebase ML، تخزّنها Firebase ML بتنسيق protobuf التسلسلي العادي في وحدة التخزين المحلية.

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