Apple প্ল্যাটফর্মগুলিতে একটি AutoML- প্রশিক্ষিত মডেলের সাথে চিত্রগুলিতে বস্তুগুলি সনাক্ত করুন৷

AutoML Vision Edge ব্যবহার করে আপনার নিজস্ব মডেল প্রশিক্ষণের পর, আপনি ছবিতে বস্তু সনাক্ত করতে আপনার অ্যাপে এটি ব্যবহার করতে পারেন।

AutoML Vision Edge থেকে প্রশিক্ষিত মডেলগুলিকে একীভূত করার দুটি উপায় রয়েছে। আপনি আপনার Xcode প্রকল্পে মডেলের ফাইলগুলি অনুলিপি করে মডেলটি বান্ডেল করতে পারেন, অথবা আপনি Firebase থেকে গতিশীলভাবে এটি ডাউনলোড করতে পারেন।

মডেল বান্ডলিং বিকল্পগুলি
আপনার অ্যাপে বান্ডেল করা
  • মডেলটি বান্ডেলের অংশ।
  • অ্যাপল ডিভাইস অফলাইনে থাকলেও মডেলটি তাৎক্ষণিকভাবে উপলব্ধ।
  • ফায়ারবেস প্রকল্পের কোন প্রয়োজন নেই
Firebase এর সাথে হোস্ট করা হয়েছে
  • Firebase Machine Learning- এ আপলোড করে মডেলটি হোস্ট করুন।
  • অ্যাপ বান্ডেলের আকার কমায়
  • মডেলটি চাহিদা অনুযায়ী ডাউনলোড করা হয়।
  • আপনার অ্যাপ পুনঃপ্রকাশ না করেই মডেল আপডেটগুলি পুশ করুন
  • ফায়ারবেস রিমোট কনফিগারেশনের সাহায্যে সহজ এ/বি টেস্টিং
  • একটি Firebase প্রকল্প প্রয়োজন

শুরু করার আগে

  1. যদি আপনি একটি মডেল ডাউনলোড করতে চান , তাহলে আপনার অ্যাপল প্রোজেক্টে Firebase যোগ করতে ভুলবেন না, যদি আপনি ইতিমধ্যেই তা না করে থাকেন। মডেলটি বান্ডেল করার সময় এটি প্রয়োজন হয় না।

  2. আপনার পডফাইলে টেনসরফ্লো এবং ফায়ারবেস লাইব্রেরি অন্তর্ভুক্ত করুন:

    আপনার অ্যাপের সাথে একটি মডেল বান্ডেল করার জন্য:

    সুইফট

    pod 'TensorFlowLiteSwift'
    

    অবজেক্টিভ-সি

    pod 'TensorFlowLiteObjC'
    

    Firebase থেকে একটি মডেল গতিশীলভাবে ডাউনলোড করার জন্য, Firebase/MLModelInterpreter নির্ভরতা যোগ করুন:

    সুইফট

    pod 'TensorFlowLiteSwift'
    pod 'Firebase/MLModelInterpreter'
    

    অবজেক্টিভ-সি

    pod 'TensorFlowLiteObjC'
    pod 'Firebase/MLModelInterpreter'
    
  3. আপনার প্রোজেক্টের পড ইনস্টল বা আপডেট করার পরে, .xcworkspace ব্যবহার করে আপনার Xcode প্রোজেক্টটি খুলুন।

1. মডেলটি লোড করুন

একটি স্থানীয় মডেল উৎস কনফিগার করুন

আপনার অ্যাপের সাথে মডেলটি বান্ডেল করতে, আপনার Xcode প্রজেক্টে মডেল এবং লেবেল ফাইলটি অনুলিপি করুন, এটি করার সময় Create folder references নির্বাচন করতে ভুলবেন না। মডেল ফাইল এবং লেবেলগুলি অ্যাপ বান্ডেলে অন্তর্ভুক্ত করা হবে।

এছাড়াও, মডেলের পাশাপাশি তৈরি করা tflite_metadata.json ফাইলটি দেখুন। আপনার দুটি মান প্রয়োজন:

  • মডেলের ইনপুট মাত্রা। এটি ডিফল্টরূপে 320x320।
  • মডেলটির সর্বোচ্চ সনাক্তকরণ। ডিফল্টরূপে এটি ৪০।

একটি Firebase-হোস্টেড মডেল সোর্স কনফিগার করুন

রিমোটলি-হোস্টেড মডেল ব্যবহার করতে, একটি CustomRemoteModel অবজেক্ট তৈরি করুন, যেখানে আপনি মডেলটি প্রকাশ করার সময় যে নামটি দিয়েছিলেন তা উল্লেখ করুন:

সুইফট

let remoteModel = CustomRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Google Cloud console.
)

অবজেক্টিভ-সি

FIRCustomRemoteModel *remoteModel = [[FIRCustomRemoteModel alloc]
                                     initWithName:@"your_remote_model"];

তারপর, মডেল ডাউনলোড টাস্ক শুরু করুন, আপনি কোন শর্তাবলীর অধীনে ডাউনলোডের অনুমতি দিতে চান তা উল্লেখ করুন। যদি মডেলটি ডিভাইসে না থাকে, অথবা মডেলের একটি নতুন সংস্করণ উপলব্ধ থাকে, তাহলে টাস্কটি Firebase থেকে অ্যাসিঙ্ক্রোনাসভাবে মডেলটি ডাউনলোড করবে:

সুইফট

let downloadProgress = ModelManager.modelManager().download(
    remoteModel,
    conditions: ModelDownloadConditions(
        allowsCellularAccess: true,
        allowsBackgroundDownloading: true
    )
)

অবজেক্টিভ-সি

FIRModelDownloadConditions *conditions =
        [[FIRModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                             allowsBackgroundDownloading:YES];
NSProgress *progress = [[FIRModelManager modelManager] downloadModel:remoteModel
                                                          conditions:conditions];

অনেক অ্যাপ তাদের ইনিশিয়ালাইজেশন কোডে ডাউনলোডের কাজ শুরু করে, কিন্তু মডেলটি ব্যবহার করার আগে আপনি যেকোনো সময় তা করতে পারেন।

আপনার মডেল থেকে একটি অবজেক্ট ডিটেক্টর তৈরি করুন

আপনার মডেল সোর্সগুলি কনফিগার করার পরে, তাদের যেকোনো একটি থেকে একটি TensorFlow Lite Interpreter অবজেক্ট তৈরি করুন।

যদি আপনার কেবল স্থানীয়ভাবে তৈরি একটি মডেল থাকে, তাহলে মডেল ফাইল থেকে একটি ইন্টারপ্রেটার তৈরি করুন:

সুইফট

guard let modelPath = Bundle.main.path(
    forResource: "model",
    ofType: "tflite"
) else {
  print("Failed to load the model file.")
  return true
}
let interpreter = try Interpreter(modelPath: modelPath)
try interpreter.allocateTensors()

অবজেক্টিভ-সি

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

NSError *error;
TFLInterpreter *interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath
                                                                  error:&error];
if (error != NULL) { return; }

[interpreter allocateTensorsWithError:&error];
if (error != NULL) { return; }

যদি আপনার একটি রিমোটলি-হোস্টেড মডেল থাকে, তাহলে এটি চালানোর আগে আপনাকে এটি ডাউনলোড করা হয়েছে কিনা তা পরীক্ষা করতে হবে। আপনি মডেল ম্যানেজারের isModelDownloaded(remoteModel:) পদ্ধতি ব্যবহার করে মডেল ডাউনলোড টাস্কের অবস্থা পরীক্ষা করতে পারেন।

যদিও ইন্টারপ্রেটার চালানোর আগে আপনাকে কেবল এটি নিশ্চিত করতে হবে, যদি আপনার কাছে রিমোটলি-হোস্টেড মডেল এবং স্থানীয়ভাবে-বান্ডেলড মডেল উভয়ই থাকে, তাহলে Interpreter চালু করার সময় এই পরীক্ষাটি করা যুক্তিসঙ্গত হতে পারে: যদি এটি ডাউনলোড করা থাকে তবে রিমোট মডেল থেকে একটি ইন্টারপ্রেটার তৈরি করুন, এবং অন্যথায় স্থানীয় মডেল থেকে।

সুইফট

var modelPath: String?
if ModelManager.modelManager().isModelDownloaded(remoteModel) {
    ModelManager.modelManager().getLatestModelFilePath(remoteModel) { path, error in
        guard error == nil else { return }
        guard let path = path else { return }
        modelPath = path
    }
} else {
    modelPath = Bundle.main.path(
        forResource: "model",
        ofType: "tflite"
    )
}

guard modelPath != nil else { return }
let interpreter = try Interpreter(modelPath: modelPath)
try interpreter.allocateTensors()

অবজেক্টিভ-সি

__block NSString *modelPath;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
    [[FIRModelManager modelManager] getLatestModelFilePath:remoteModel
                                                completion:^(NSString * _Nullable filePath,
                                                             NSError * _Nullable error) {
        if (error != NULL) { return; }
        if (filePath == NULL) { return; }
        modelPath = filePath;
    }];
} else {
    modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                ofType:@"tflite"];
}

NSError *error;
TFLInterpreter *interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath
                                                                  error:&error];
if (error != NULL) { return; }

[interpreter allocateTensorsWithError:&error];
if (error != NULL) { return; }

যদি আপনার কেবল একটি রিমোটলি-হোস্টেড মডেল থাকে, তাহলে আপনার মডেল-সম্পর্কিত কার্যকারিতা অক্ষম করা উচিত—যেমন, ধূসর-আউট অথবা আপনার UI-এর কিছু অংশ লুকান—যতক্ষণ না আপনি নিশ্চিত হন যে মডেলটি ডাউনলোড হয়েছে।

ডিফল্ট নোটিফিকেশন সেন্টারে অবজারভার সংযুক্ত করে আপনি মডেল ডাউনলোড স্ট্যাটাস পেতে পারেন। অবজারভার ব্লকে self এর জন্য একটি দুর্বল রেফারেন্স ব্যবহার করতে ভুলবেন না, কারণ ডাউনলোডে কিছুটা সময় লাগতে পারে এবং ডাউনলোড শেষ হওয়ার সাথে সাথে অরিজিনিং অবজেক্টটি মুক্ত হয়ে যেতে পারে। উদাহরণস্বরূপ:

সুইফট

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]
    // ...
}

অবজেক্টিভ-সি

__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. ইনপুট ইমেজ প্রস্তুত করুন

এরপর, আপনাকে TensorFlow Lite ইন্টারপ্রেটারের জন্য আপনার ছবিগুলি প্রস্তুত করতে হবে।

  1. tflite_metadata.json ফাইলে (ডিফল্টরূপে 320x320 পিক্সেল) উল্লেখিত মডেলের ইনপুট মাত্রা অনুসারে ছবিটি ক্রপ এবং স্কেল করুন। আপনি এটি কোর ইমেজ বা তৃতীয় পক্ষের লাইব্রেরি দিয়ে করতে পারেন।

  2. ছবির ডেটা একটি Data ( NSData অবজেক্টে কপি করুন):

    সুইফট

    guard 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 nil
    }
    
    context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
    guard let imageData = context.data else { return nil }
    
    var inputData = Data()
    for row in 0 ..< 320 {    // Model takes 320x320 pixel images as input
      for col in 0 ..< 320 {
        let offset = 4 * (col * context.width + row)
        // (Ignore offset 0, the unused alpha channel)
        var red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
        var green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
        var blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)
    
        inputData.append(&red, count: 1)
        inputData.append(&green, count: 1)
        inputData.append(&blue, count: 1)
      }
    }
    

    অবজেক্টিভ-সি

    CGImageRef image = // Your input image
    long imageWidth = CGImageGetWidth(image);
    long imageHeight = CGImageGetHeight(image);
    CGContextRef context = CGBitmapContextCreate(nil,
                                                 imageWidth, imageHeight,
                                                 8,
                                                 imageWidth * 4,
                                                 CGColorSpaceCreateDeviceRGB(),
                                                 kCGImageAlphaNoneSkipFirst);
    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image);
    UInt8 *imageData = CGBitmapContextGetData(context);
    
    NSMutableData *inputData = [[NSMutableData alloc] initWithCapacity:0];
    
    for (int row = 0; row < 300; row++) {
      for (int col = 0; col < 300; col++) {
        long offset = 4 * (row * imageWidth + col);
        // (Ignore offset 0, the unused alpha channel)
        UInt8 red = imageData[offset+1];
        UInt8 green = imageData[offset+2];
        UInt8 blue = imageData[offset+3];
    
        [inputData appendBytes:&red length:1];
        [inputData appendBytes:&green length:1];
        [inputData appendBytes:&blue length:1];
      }
    }
    

৩. অবজেক্ট ডিটেক্টর চালান

এরপর, প্রস্তুত ইনপুটটি দোভাষীর কাছে পাঠান:

সুইফট

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

অবজেক্টিভ-সি

TFLTensor *input = [interpreter inputTensorAtIndex:0 error:&error];
if (error != nil) { return; }

[input copyData:inputData error:&error];
if (error != nil) { return; }

[interpreter invokeWithError:&error];
if (error != nil) { return; }

৪. সনাক্ত করা বস্তু সম্পর্কে তথ্য পান

যদি বস্তু সনাক্তকরণ সফল হয়, তাহলে মডেলটি আউটপুট হিসেবে ৪০টি উপাদানের (অথবা tflite_metadata.json ফাইলে যা উল্লেখ করা হয়েছে) তিনটি অ্যারে তৈরি করে। প্রতিটি উপাদান একটি সম্ভাব্য বস্তুর সাথে সম্পর্কিত। প্রথম অ্যারেটি বাউন্ডিং বাক্সের একটি অ্যারে; দ্বিতীয়টি, লেবেলের একটি অ্যারে; এবং তৃতীয়টি, আত্মবিশ্বাসের মানগুলির একটি অ্যারে। মডেল আউটপুট পেতে:

সুইফট

var output = try interpreter.output(at: 0)
let boundingBoxes =
    UnsafeMutableBufferPointer<Float32>.allocate(capacity: 4 * 40)
output.data.copyBytes(to: boundingBoxes)

output = try interpreter.output(at: 1)
let labels =
    UnsafeMutableBufferPointer<Float32>.allocate(capacity: 40)
output.data.copyBytes(to: labels)

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

অবজেক্টিভ-সি

TFLTensor *output = [interpreter outputTensorAtIndex:0 error:&error];
if (error != nil) { return; }
NSData *boundingBoxes = [output dataWithError:&error];
if (error != nil) { return; }

output = [interpreter outputTensorAtIndex:1 error:&error];
if (error != nil) { return; }
NSData *labels = [output dataWithError:&error];
if (error != nil) { return; }

output = [interpreter outputTensorAtIndex:2 error:&error];
if (error != nil) { return; }
NSData *probabilities = [output dataWithError:&error];
if (error != nil) { return; }

তারপর, আপনি আপনার লেবেল অভিধানের সাথে লেবেল আউটপুটগুলিকে একত্রিত করতে পারেন:

সুইফট

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

for i in 0 ..< 40 {
    let top = boundingBoxes[0 * i]
    let left = boundingBoxes[1 * i]
    let bottom = boundingBoxes[2 * i]
    let right = boundingBoxes[3 * i]

    let labelIdx = Int(labels[i])
    let label = labelText[labelIdx]
    let confidence = probabilities[i]

    if confidence > 0.66 {
        print("Object found: \(label) (confidence: \(confidence))")
        print("  Top-left: (\(left),\(top))")
        print("  Bottom-right: (\(right),\(bottom))")
    }
}

অবজেক্টিভ-সি

NSString *labelPath = [NSBundle.mainBundle pathForResource:@"dict"
                                                    ofType:@"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:labelPath
                                                   encoding:NSUTF8StringEncoding
                                                      error:&error];
if (error != nil || fileContents == NULL) { return; }
NSArray<NSString*> *labelText = [fileContents componentsSeparatedByString:@"\n"];

for (int i = 0; i < 40; i++) {
    Float32 top, right, bottom, left;
    Float32 labelIdx;
    Float32 confidence;

    [boundingBoxes getBytes:&top range:NSMakeRange(16 * i + 0, 4)];
    [boundingBoxes getBytes:&left range:NSMakeRange(16 * i + 4, 4)];
    [boundingBoxes getBytes:&bottom range:NSMakeRange(16 * i + 8, 4)];
    [boundingBoxes getBytes:&right range:NSMakeRange(16 * i + 12, 4)];

    [labels getBytes:&labelIdx range:NSMakeRange(4 * i, 4)];
    [probabilities getBytes:&confidence range:NSMakeRange(4 * i, 4)];

    if (confidence > 0.5f) {
        NSString *label = labelText[(int)labelIdx];
        NSLog(@"Object detected: %@", label);
        NSLog(@"  Confidence: %f", confidence);
        NSLog(@"  Top-left: (%f,%f)", left, top);
        NSLog(@"  Bottom-right: (%f,%f)", right, bottom);
    }
}

রিয়েল-টাইম পারফর্ম্যান্স উন্নত করার টিপস

আপনি যদি রিয়েল-টাইম অ্যাপ্লিকেশনে ছবি লেবেল করতে চান, তাহলে সেরা ফ্রেমরেট অর্জনের জন্য এই নির্দেশিকাগুলি অনুসরণ করুন:

  • থ্রটল ডিটেক্টরে কল করে। ডিটেক্টর চলাকালীন যদি একটি নতুন ভিডিও ফ্রেম পাওয়া যায়, তাহলে ফ্রেমটি ফেলে দিন।
  • যদি আপনি ইনপুট ছবিতে গ্রাফিক্স ওভারলে করার জন্য ডিটেক্টরের আউটপুট ব্যবহার করেন, তাহলে প্রথমে ফলাফলটি পান, তারপর ছবিটি রেন্ডার করুন এবং এক ধাপে ওভারলে করুন। এটি করার মাধ্যমে, আপনি প্রতিটি ইনপুট ফ্রেমের জন্য শুধুমাত্র একবার ডিসপ্লে সারফেসে রেন্ডার করবেন। উদাহরণের জন্য শোকেস নমুনা অ্যাপে previewOverlayView এবং FIRDetectionOverlayView ক্লাসগুলি দেখুন।