تصنيف الصور باستخدام نموذج تم تدريبه على AutoML على نظام التشغيل iOS

بعد تدريب باستخدام AutoML Vision Edge، يمكنك استخدامه في تطبيقك لتصنيف الصور.

قبل البدء

  1. إذا لم يسبق لك إضافة Firebase إلى تطبيقك، يمكنك إجراء ذلك من خلال اتّباع الخطوات الأولى في دليل البدء.
  2. تضمين مكتبات ML Kit في Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionAutoML', '6.25.0'
    
    بعد تثبيت مجموعات مشروعك الصغيرة أو تحديثها، احرص على فتح ملف Xcode باستخدام .xcworkspace.
  3. في تطبيقك، استورد Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

1- تحميل النموذج

تشغّل مجموعة أدوات تعلُّم الآلة النماذج التي يتم إنشاؤها تلقائيًا باستخدام تعلُّم الآلة على الجهاز. ومع ذلك، يمكنك يمكنك ضبط أداة تعلُّم الآلة لتحميل نموذجك عن بُعد من Firebase أو أو كليهما معًا.

ويمكنك تعديل النموذج بدون طرحه من خلال استضافة النموذج على Firebase. إصدار جديد من التطبيق، ويمكنك استخدام Remote Config وA/B Testing لإجراء ما يلي: تعرض نماذج مختلفة ديناميكيًا لمجموعات مختلفة من المستخدمين.

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

يمكنك ضمان ميزات تعلُّم الآلة في تطبيقك من خلال دمج نموذجك مع تطبيقك. لا يزال يعمل في حال عدم توفُّر النموذج المستضاف على Firebase.

ضبط مصدر نموذج مستضاف على Firebase

لاستخدام النموذج المستضاف عن بُعد، عليك إنشاء عنصر AutoMLRemoteModel، لتحديد الاسم الذي عينته للنموذج عند نشره:

Swift

let remoteModel = AutoMLRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Firebase console.
)

Objective-C

FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel alloc]
    initWithName:@"your_remote_model"];  // The name you assigned in the Firebase console.

بعد ذلك، ابدأ مهمة تنزيل النموذج، مع تحديد الشروط التي الذي تريد السماح بتنزيله إذا لم يكن الطراز موجودًا على الجهاز، أو إذا كان طرازًا أحدث إتاحة إصدار معين من النموذج، فإن المهمة ستنزّل بشكل غير متزامن النموذج من Firebase:

Swift

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

Objective-C

FIRModelDownloadConditions *downloadConditions =
    [[FIRModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[FIRModelManager modelManager] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

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

إعداد مصدر نموذج محلي

لدمج النموذج مع تطبيقك:

  1. يمكنك استخراج النموذج وبياناته الوصفية من أرشيف ZIP الذي نزّلته. من وحدة تحكّم Firebase إلى مجلد:
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
    يجب أن تكون جميع الملفات الثلاثة في مجلد واحد. نوصيك باستخدام الملفات وقمت بتنزيلها، بدون تعديل (بما في ذلك أسماء الملفات).
  2. انسخ المجلد إلى مشروع Xcode، مع الحرص على تحديد أنشئ مراجع للمجلدات عند إجراء ذلك. ملف النموذج وبيانات التعريف سيتم تضمينه في حِزمة التطبيق وإتاحتها في حزمة تعلّم الآلة.
  3. إنشاء عنصر AutoMLLocalModel، لتحديد المسار إلى بيان النموذج الملف:

    Swift

    guard let manifestPath = Bundle.main.path(
        forResource: "manifest",
        ofType: "json",
        inDirectory: "your_model_directory"
    ) else { return true }
    let localModel = AutoMLLocalModel(manifestPath: manifestPath)
    

    Objective-C

    NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest"
                                                           ofType:@"json"
                                                      inDirectory:@"your_model_directory"];
    FIRAutoMLLocalModel *localModel = [[FIRAutoMLLocalModel alloc] initWithManifestPath:manifestPath];
    

إنشاء مصنِّف للصور من نموذجك

بعد ضبط مصادر النموذج، أنشئ عنصر VisionImageLabeler. من إحداها.

وإذا كان لديك نموذج مجمّع محليًا فقط، ما عليك سوى إنشاء مصنِّف من عنصر AutoMLLocalModel وضبط الحد الأدنى لنتيجة الثقة الذي تريده مطلوب (راجع تقييم النموذج):

Swift

let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

Objective-C

FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
    [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0;  // Evaluate your model in the Firebase console
                                  // to determine an appropriate value.
FIRVisionImageLabeler *labeler =
    [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

فإذا كان لديك نموذج مستضاف عن بُعد، فعليك التحقق من أنه تم تنزيله قبل تشغيله. يمكنك التحقّق من حالة تنزيل النموذج باستخدام طريقة isModelDownloaded(remoteModel:) لمدير النموذج.

وما عليك سوى تأكيد هذا قبل تشغيل المُصنِّف، إذا لكل من نموذج مُستضاف عن بُعد ونموذج مُجمع محليًا، فقد تجعل إجراء عملية الفحص هذه عند إنشاء مثيل VisionImageLabeler: إنشاء مصنِّف من النموذج البعيد إذا تم تنزيله، ومن الإعدادات نموذج بخلاف ذلك.

Swift

var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

Objective-C

VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f;  // Evaluate your model in the Firebase console
                                     // to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];

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

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

Swift

NotificationCenter.default.addObserver(
    forName: .firebaseMLModelDownloadDidSucceed,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel,
        model.name == "your_remote_model"
        else { return }
    // The model was downloaded and is available on the device
}

NotificationCenter.default.addObserver(
    forName: .firebaseMLModelDownloadDidFail,
    object: nil,
    queue: nil
) { [weak self] notification in
    guard let strongSelf = self,
        let userInfo = notification.userInfo,
        let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue]
            as? RemoteModel
        else { return }
    let error = userInfo[ModelDownloadUserInfoKey.error.rawValue]
    // ...
}

Objective-C

__weak typeof(self) weakSelf = self;

[NSNotificationCenter.defaultCenter
    addObserverForName:FIRModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              FIRRemoteModel *model = note.userInfo[FIRModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:FIRModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[FIRModelDownloadUserInfoKeyError];
            }];

2- تحضير صورة الإدخال

بعد ذلك، لكل صورة تريد تصنيفها، أنشِئ عنصر VisionImage باستخدام الخيارات الموضحة في هذا القسم وتمريرها إلى مثيل VisionImageLabeler (الموضّحة في القسم التالي).

إنشاء عنصر VisionImage باستخدام UIImage أو CMSampleBufferRef

لاستخدام UIImage:

  1. إذا لزم الأمر، يمكنك تدوير الصورة لتكون imageOrientation الموقع هو .up.
  2. إنشاء عنصر VisionImage باستخدام عنصر التدوير الذي تم تدويره بشكل صحيح UIImage عدم تحديد أي بيانات وصفية حول عرض الإعلانات بالتناوب - البيانات التلقائية القيمة، .topLeft،.

    Swift

    let image = VisionImage(image: uiImage)

    Objective-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

لاستخدام CMSampleBufferRef:

  1. أنشئ كائن VisionImageMetadata يحدّد اتجاه بيانات الصورة الواردة في المخزن المؤقت CMSampleBufferRef

    للحصول على اتجاه الصورة:

    Swift

    func imageOrientation(
        deviceOrientation: UIDeviceOrientation,
        cameraPosition: AVCaptureDevice.Position
        ) -> VisionDetectorImageOrientation {
        switch deviceOrientation {
        case .portrait:
            return cameraPosition == .front ? .leftTop : .rightTop
        case .landscapeLeft:
            return cameraPosition == .front ? .bottomLeft : .topLeft
        case .portraitUpsideDown:
            return cameraPosition == .front ? .rightBottom : .leftBottom
        case .landscapeRight:
            return cameraPosition == .front ? .topRight : .bottomRight
        case .faceDown, .faceUp, .unknown:
            return .leftTop
        }
    }

    Objective-C

    - (FIRVisionDetectorImageOrientation)
        imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                               cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationLeftTop;
          } else {
            return FIRVisionDetectorImageOrientationRightTop;
          }
        case UIDeviceOrientationLandscapeLeft:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationBottomLeft;
          } else {
            return FIRVisionDetectorImageOrientationTopLeft;
          }
        case UIDeviceOrientationPortraitUpsideDown:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationRightBottom;
          } else {
            return FIRVisionDetectorImageOrientationLeftBottom;
          }
        case UIDeviceOrientationLandscapeRight:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationTopRight;
          } else {
            return FIRVisionDetectorImageOrientationBottomRight;
          }
        default:
          return FIRVisionDetectorImageOrientationTopLeft;
      }
    }

    بعد ذلك، أنشئ كائن البيانات الوصفية:

    Swift

    let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
    let metadata = VisionImageMetadata()
    metadata.orientation = imageOrientation(
        deviceOrientation: UIDevice.current.orientation,
        cameraPosition: cameraPosition
    )

    Objective-C

    FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
    AVCaptureDevicePosition cameraPosition =
        AVCaptureDevicePositionBack;  // Set to the capture device you used.
    metadata.orientation =
        [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                     cameraPosition:cameraPosition];
  2. إنشاء عنصر VisionImage باستخدام عنصر CMSampleBufferRef والبيانات الوصفية بالتناوب:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.metadata = metadata

    Objective-C

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
    image.metadata = metadata;

3- تشغيل أداة تصنيف الصور

لتصنيف العناصر في صورة، مرِّر كائن VisionImage إلى طريقة process() لـ VisionImageLabeler:

Swift

labeler.process(image) { labels, error in
    guard error == nil, let labels = labels else { return }

    // Task succeeded.
    // ...
}

Objective-C

[labeler
    processImage:image
      completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
        if (error != nil || labels == nil) {
          return;
        }

        // Task succeeded.
        // ...
      }];

في حال نجاح تصنيف الصور، سيتم إنشاء مصفوفة من VisionImageLabel عنصر. تمريره إلى معالج الإكمال. من كل عنصر، يمكنك الحصول على معلومات حول ميزة تم التعرف عليها في الصورة.

على سبيل المثال:

Swift

for label in labels {
    let labelText = label.text
    let confidence = label.confidence
}

Objective-C

for (FIRVisionImageLabel *label in labels) {
  NSString *labelText = label.text;
  NSNumber *confidence = label.confidence;
}

نصائح لتحسين الأداء في الوقت الفعلي

  • التحكُّم في المكالمات الواردة إلى أداة الرصد. إذا أصبح إطار فيديو جديد المتاح أثناء تشغيل أداة الكشف، أفلِت الإطار.
  • إذا كنت تستخدم ناتج أداة الكشف لتراكب الرسومات على الصورة المدخلة، والحصول أولاً على النتيجة من ML Kit، ثم عرض الصورة وتراكبها في خطوة واحدة. ومن خلال القيام بذلك، يمكنك العرض على سطح الشاشة مرة واحدة فقط لكل إطار إدخال اطّلع على previewOverlayView وFIRDetectionOverlayView الفئات في نموذج تطبيق العرض كمثال.