برچسب‌گذاری تصاویر با یک مدل آموزش‌دیده AutoML در iOS

بعد از اینکه مدل خودتان را با استفاده از AutoML Vision Edge آموزش دادید ، می‌توانید از آن در برنامه خود برای برچسب‌گذاری تصاویر استفاده کنید.

دو راه برای ادغام مدل‌های آموزش‌دیده از AutoML Vision Edge وجود دارد. می‌توانید مدل را با کپی کردن فایل‌های مدل در پروژه Xcode خود، بسته‌بندی کنید، یا می‌توانید آن را به صورت پویا از Firebase دانلود کنید.

گزینه‌های بسته‌بندی مدل
در برنامه شما گنجانده شده است
  • مدل بخشی از بسته است
  • این مدل بلافاصله در دسترس است، حتی زمانی که دستگاه iOS آفلاین باشد
  • نیازی به پروژه Firebase نیست
میزبانی شده با فایربیس
  • با آپلود مدل در Firebase Machine Learning، آن را میزبانی کنید.
  • حجم بسته برنامه را کاهش می‌دهد
  • مدل بر اساس تقاضا دانلود می‌شود
  • به‌روزرسانی‌های مدل را بدون انتشار مجدد برنامه خود، ارسال کنید
  • تست A/B آسان با پیکربندی از راه دور Firebase
  • نیاز به یک پروژه Firebase دارد

امتحانش کن.

قبل از اینکه شروع کنی

۱. کتابخانه‌های ML Kit را در Podfile خود قرار دهید:

برای باندل کردن یک مدل با برنامه‌تان:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    
برای دانلود پویای یک مدل از Firebase، وابستگی LinkFirebase را اضافه کنید:
    pod 'GoogleMLKit/ImageLabelingAutoML'
    pod 'GoogleMLKit/LinkFirebase'
    
۲. پس از نصب یا به‌روزرسانی Podهای پروژه خود، پروژه Xcode خود را با استفاده از کد .xcworkspace > آن باز کنید. ML Kit در Xcode نسخه ۱۳.۲.۱ یا بالاتر پشتیبانی می‌شود. ۳. اگر می‌خواهید مدلی را دانلود کنید ، اگر قبلاً Firebase را به پروژه iOS خود اضافه نکرده‌اید، حتماً آن را اضافه کنید. این کار هنگام بسته‌بندی مدل لازم نیست.

۱. مدل را بارگذاری کنید

پیکربندی یک منبع مدل محلی

برای اتصال مدل به برنامه خود:

۱. مدل و متادیتای آن را از فایل زیپی که از کنسول فایربیس دانلود کرده‌اید، در یک پوشه استخراج کنید:
    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    
هر سه فایل باید در یک پوشه باشند. توصیه می‌کنیم فایل‌ها را همانطور که دانلود کرده‌اید، بدون تغییر (از جمله نام فایل‌ها) استفاده کنید.

۲. پوشه را در پروژه Xcode خود کپی کنید، و هنگام انجام این کار، حتماً گزینه Create folder references را انتخاب کنید. فایل مدل و متادیتا در بسته برنامه قرار می‌گیرند و در ML Kit در دسترس خواهند بود.

۳. شیء AutoMLImageLabelerLocalModel را ایجاد کنید و مسیر فایل مانیفست مدل را مشخص کنید:

سویفت

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

هدف-سی

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

پیکربندی یک منبع مدل میزبانی‌شده توسط Firebase

برای استفاده از مدل میزبانی‌شده از راه دور، یک شیء AutoMLImageLabelerRemoteModel ایجاد کنید و نامی را که هنگام انتشار مدل به آن اختصاص داده‌اید، مشخص کنید:

سویفت

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

هدف-سی

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

سپس، وظیفه دانلود مدل را آغاز کنید و شرایطی را که می‌خواهید تحت آن اجازه دانلود داده شود، مشخص کنید. اگر مدل روی دستگاه نباشد، یا اگر نسخه جدیدتری از مدل در دسترس باشد، وظیفه به صورت غیرهمزمان مدل را از Firebase دانلود می‌کند:

سویفت

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

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

هدف-سی

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

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadModel:remoteModel
                                       conditions:downloadConditions];

بسیاری از برنامه‌ها وظیفه دانلود را در کد مقداردهی اولیه خود شروع می‌کنند، اما شما می‌توانید این کار را در هر زمانی قبل از نیاز به استفاده از مدل انجام دهید.

یک برچسب تصویر از مدل خود ایجاد کنید

پس از پیکربندی منابع مدل خود، یک شیء ImageLabeler از یکی از آنها ایجاد کنید.

اگر فقط یک مدل محلی دارید، کافیست یک برچسب‌گذار از شیء AutoMLImageLabelerLocalModel خود ایجاد کنید و آستانه امتیاز اطمینان مورد نیاز خود را پیکربندی کنید (به بخش ارزیابی حالت خود مراجعه کنید:

سویفت

let options = AutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

هدف-سی

MLKAutoMLImageLabelerOptions *options =
    [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

اگر یک مدل از راه دور دارید، باید قبل از اجرا، بررسی کنید که آیا دانلود شده است یا خیر. می‌توانید وضعیت وظیفه دانلود مدل را با استفاده از متد isModelDownloaded (remoteModel:) در مدیریت مدل بررسی کنید.

اگرچه شما فقط باید قبل از اجرای برچسب‌گذار این موضوع را تأیید کنید، اما اگر هم یک مدل میزبانی‌شده از راه دور و هم یک مدل بسته‌بندی‌شده محلی دارید، انجام این بررسی هنگام نمونه‌سازی ImageLabeler منطقی است: اگر مدل از راه دور دانلود شده است، یک برچسب‌گذار از آن و در غیر این صورت از مدل محلی ایجاد کنید.

سویفت

var options: AutoMLImageLabelerOptions!
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = AutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = AutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Firebase console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options: options)

هدف-سی

MLKAutoMLImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0);  // Evaluate your model in the Firebase console
                                       // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

اگر فقط یک مدل میزبانی‌شده از راه دور دارید، باید عملکردهای مربوط به مدل را غیرفعال کنید - مثلاً بخشی از رابط کاربری خود را خاکستری کنید یا پنهان کنید - تا زمانی که تأیید کنید مدل دانلود شده است.

شما می‌توانید با اتصال ناظرها به مرکز اعلان پیش‌فرض، وضعیت دانلود مدل را دریافت کنید. حتماً از یک ارجاع ضعیف به self در بلوک ناظر استفاده کنید، زیرا دانلودها می‌توانند مدتی طول بکشند و شیء مبدا می‌تواند تا زمان اتمام دانلود آزاد شود. برای مثال:

سویفت

NotificationCenter.default.addObserver(
    forName: .mlkitModelDownloadDidSucceed,
    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: .mlkitModelDownloadDidFail,
    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]
    // ...
}

هدف-سی

__weak typeof(self) weakSelf = self;

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

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

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

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

۲. تصویر ورودی را آماده کنید

با استفاده از UIImage یا CMSampleBuffer یک شیء VisionImage ایجاد کنید.

اگر از UIImage استفاده می‌کنید، مراحل زیر را دنبال کنید:

  • یک شیء VisionImage با UIImage ایجاد کنید. مطمئن شوید که .orientation صحیح را مشخص می‌کنید.

    سویفت

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    هدف-سی

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

اگر از CMSampleBuffer استفاده می‌کنید، مراحل زیر را دنبال کنید:

  • جهت داده‌های تصویر موجود در CMSampleBuffer را مشخص کنید.

    برای بدست آوردن جهت تصویر:

    سویفت

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    هدف-سی

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • با استفاده از شیء و جهت‌گیری CMSampleBuffer ، یک شیء VisionImage ایجاد کنید:

    سویفت

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    هدف-سی

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

۳. برچسب‌گذار تصویر را اجرا کنید

ناهمزمان:

سویفت

imageLabeler.process(image) { labels, error in
    guard error == nil, let labels = labels, !labels.isEmpty else {
        // Handle the error.
        return
    }
    // Show results.
}

هدف-سی

[imageLabeler
    processImage:image
      completion:^(NSArray *_Nullable labels,
                   NSError *_Nullable error) {
        if (labels.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

همزمان:

سویفت

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

هدف-سی

NSError *error;
NSArray *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

۴. اطلاعات مربوط به اشیاء برچسب‌گذاری شده را دریافت کنید

اگر عملیات برچسب‌گذاری تصویر با موفقیت انجام شود، آرایه‌ای از ImageLabel را برمی‌گرداند. هر ImageLabel نشان دهنده چیزی است که در تصویر برچسب‌گذاری شده است. می‌توانید توضیحات متنی هر برچسب (در صورت وجود در فراداده فایل مدل TensorFlow Lite)، امتیاز اطمینان و شاخص آن را دریافت کنید. برای مثال:

سویفت

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

هدف-سی

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

نکاتی برای بهبود عملکرد در زمان واقعی

اگر می‌خواهید تصاویر را در یک برنامه‌ی بلادرنگ برچسب‌گذاری کنید، برای دستیابی به بهترین نرخ فریم، این دستورالعمل‌ها را دنبال کنید:

  • برای پردازش فریم‌های ویدیویی، از API همزمان results(in:) آشکارساز استفاده کنید. این متد را از تابع captureOutput(_, didOutput:from:) مربوط به AVCaptureVideoDataOutputSampleBufferDelegate فراخوانی کنید تا نتایج از فریم ویدیویی داده شده به صورت همزمان دریافت شوند. alwaysDiscardsLateVideoFrames مربوط به AVCaptureVideoDataOutput را برای فراخوانی‌های throttle به آشکارساز، true نگه دارید. اگر فریم ویدیویی جدیدی در حین اجرای آشکارساز در دسترس قرار گیرد، حذف خواهد شد.
  • اگر از خروجی آشکارساز برای همپوشانی گرافیک روی تصویر ورودی استفاده می‌کنید، ابتدا نتیجه را از کیت ML دریافت کنید، سپس تصویر و همپوشانی را در یک مرحله رندر کنید. با انجام این کار، برای هر فریم ورودی پردازش شده، فقط یک بار روی سطح نمایشگر رندر می‌کنید. برای مثال، به updatePreviewOverlayViewWithLastFrame در نمونه شروع سریع کیت ML مراجعه کنید.