Apple प्लेटफ़ॉर्म पर ऑटोएमएल-प्रशिक्षित मॉडल के साथ छवियों में ऑब्जेक्ट का पता लगाएं

ऑटोएमएल विज़न एज का उपयोग करके अपने स्वयं के मॉडल को प्रशिक्षित करने के बाद, आप छवियों में वस्तुओं का पता लगाने के लिए इसे अपने ऐप में उपयोग कर सकते हैं।

ऑटोएमएल विज़न एज से प्रशिक्षित मॉडलों को एकीकृत करने के दो तरीके हैं। आप मॉडल की फ़ाइलों को अपने Xcode प्रोजेक्ट में कॉपी करके मॉडल को बंडल कर सकते हैं, या आप इसे फ़ायरबेस से गतिशील रूप से डाउनलोड कर सकते हैं।

मॉडल बंडलिंग विकल्प
आपके ऐप में बंडल किया गया
  • मॉडल बंडल का हिस्सा है
  • मॉडल तुरंत उपलब्ध है, भले ही Apple डिवाइस ऑफ़लाइन हो
  • फ़ायरबेस प्रोजेक्ट की कोई आवश्यकता नहीं
फायरबेस के साथ होस्ट किया गया
  • मॉडल को फायरबेस मशीन लर्निंग पर अपलोड करके होस्ट करें
  • ऐप बंडल का आकार कम करता है
  • मॉडल मांग पर डाउनलोड किया जाता है
  • अपने ऐप को दोबारा प्रकाशित किए बिना मॉडल अपडेट पुश करें
  • फायरबेस रिमोट कॉन्फ़िगरेशन के साथ आसान ए/बी परीक्षण
  • फ़ायरबेस प्रोजेक्ट की आवश्यकता है

शुरू करने से पहले

  1. यदि आप कोई मॉडल डाउनलोड करना चाहते हैं , तो सुनिश्चित करें कि आपने अपने ऐप्पल प्रोजेक्ट में फायरबेस जोड़ा है , यदि आपने पहले से ऐसा नहीं किया है। जब आप मॉडल को बंडल करते हैं तो इसकी आवश्यकता नहीं होती है।

  2. अपने पॉडफ़ाइल में TensorFlow और Firebase लाइब्रेरी शामिल करें:

    किसी मॉडल को अपने ऐप के साथ बंडल करने के लिए:

    तीव्र

    pod 'TensorFlowLiteSwift'
    

    उद्देश्य सी

    pod 'TensorFlowLiteObjC'
    

    फ़ायरबेस से किसी मॉडल को गतिशील रूप से डाउनलोड करने के लिए, Firebase/MLModelInterpreter निर्भरता जोड़ें:

    तीव्र

    pod 'TensorFlowLiteSwift'
    pod 'Firebase/MLModelInterpreter'
    

    उद्देश्य सी

    pod 'TensorFlowLiteObjC'
    pod 'Firebase/MLModelInterpreter'
    
  3. अपने प्रोजेक्ट के पॉड्स को इंस्टॉल या अपडेट करने के बाद, अपने Xcode प्रोजेक्ट को इसके .xcworkspace का उपयोग करके खोलें।

1. मॉडल लोड करें

स्थानीय मॉडल स्रोत कॉन्फ़िगर करें

मॉडल को अपने ऐप के साथ बंडल करने के लिए, मॉडल और लेबल फ़ाइल को अपने Xcode प्रोजेक्ट में कॉपी करें, ऐसा करते समय फ़ोल्डर संदर्भ बनाएं का चयन करने का ध्यान रखें। मॉडल फ़ाइल और लेबल ऐप बंडल में शामिल किए जाएंगे।

साथ ही, मॉडल के साथ बनाई गई tflite_metadata.json फ़ाइल को भी देखें। आपको दो मान चाहिए:

  • मॉडल के इनपुट आयाम. यह डिफ़ॉल्ट रूप से 320x320 है.
  • मॉडल की अधिकतम पहचान. यह डिफ़ॉल्ट रूप से 40 है.

फ़ायरबेस-होस्टेड मॉडल स्रोत कॉन्फ़िगर करें

दूरस्थ रूप से होस्ट किए गए मॉडल का उपयोग करने के लिए, एक 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"];

फिर, उन शर्तों को निर्दिष्ट करते हुए मॉडल डाउनलोड कार्य शुरू करें जिनके तहत आप डाउनलोड करने की अनुमति देना चाहते हैं। यदि मॉडल डिवाइस पर नहीं है, या यदि मॉडल का एक नया संस्करण उपलब्ध है, तो कार्य फायरबेस से मॉडल को एसिंक्रोनस रूप से डाउनलोड करेगा:

तीव्र

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; }

यदि आपके पास केवल दूरस्थ रूप से होस्ट किया गया मॉडल है, तो आपको मॉडल-संबंधित कार्यक्षमता को अक्षम करना चाहिए - उदाहरण के लिए, अपने यूआई के हिस्से को ग्रे-आउट या छुपाएं - जब तक आप पुष्टि नहीं करते कि मॉडल डाउनलोड हो गया है।

आप पर्यवेक्षकों को डिफ़ॉल्ट अधिसूचना केंद्र में संलग्न करके मॉडल डाउनलोड स्थिति प्राप्त कर सकते हैं। पर्यवेक्षक ब्लॉक में 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];
      }
    }
    

3. ऑब्जेक्ट डिटेक्टर चलाएँ

इसके बाद, दुभाषिया को तैयार इनपुट पास करें:

तीव्र

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; }

4. पता लगाई गई वस्तुओं के बारे में जानकारी प्राप्त करें

यदि ऑब्जेक्ट डिटेक्शन सफल हो जाता है, तो मॉडल आउटपुट के रूप में 40 तत्वों (या जो भी 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);
    }
}

वास्तविक समय के प्रदर्शन को बेहतर बनाने के लिए युक्तियाँ

यदि आप वास्तविक समय एप्लिकेशन में छवियों को लेबल करना चाहते हैं, तो सर्वोत्तम फ्रैमरेट्स प्राप्त करने के लिए इन दिशानिर्देशों का पालन करें:

  • थ्रॉटल डिटेक्टर को कॉल करता है। यदि डिटेक्टर के चलने के दौरान कोई नया वीडियो फ़्रेम उपलब्ध हो जाता है, तो फ़्रेम को छोड़ दें।
  • यदि आप इनपुट छवि पर ग्राफिक्स को ओवरले करने के लिए डिटेक्टर के आउटपुट का उपयोग कर रहे हैं, तो पहले परिणाम प्राप्त करें, फिर छवि को प्रस्तुत करें और एक ही चरण में ओवरले करें। ऐसा करने से, आप प्रत्येक इनपुट फ़्रेम के लिए केवल एक बार डिस्प्ले सतह पर रेंडर करते हैं। उदाहरण के लिए शोकेस नमूना ऐप में पूर्वावलोकनओवरलेव्यू और एफआईआरडिटेक्शनओवरलेव्यू कक्षाएं देखें।