iOS'te ML Kit ile çıkarım için TensorFlow Lite modeli kullanma

Android Kit'i kullanarak cihaz üzerinde çıkarım yapmak için TensorFlow Lite modeli.

ML Kit, TensorFlow Lite modellerini yalnızca iOS 9 ve sonraki sürümleri çalıştıran cihazlarda kullanabilir daha yeni.

Başlamadan önce

  1. Firebase'i uygulamanıza henüz eklemediyseniz başlangıç kılavuzundaki adımlara bakın.
  2. ML Kit kitaplıklarını Podfile'ınıza ekleyin:
    pod 'Firebase/MLModelInterpreter', '6.25.0'
    
    . Projenizin kapsüllerini yükledikten veya güncelledikten sonra Xcode projenin yaşam döngüsünü yürütmeniz gerekir..xcworkspace
  3. Uygulamanızda Firebase'i içe aktarın:

    Swift

    import Firebase

    Objective-C

    @import Firebase;
  4. Kullanmak istediğiniz TensorFlow modelini TensorFlow Lite biçimine dönüştürün. Görüntüleyin TOCO: TensorFlow Lite Dönüşüm Optimize Edici.

Modelinizi barındırın veya paketleyin

Uygulamanızda çıkarım için TensorFlow Lite modelini kullanmadan önce modeli ML Kit'te kullanılabilir hale getirmelidir. ML Kit, TensorFlow Lite'ı kullanabilir Firebase kullanılarak uzaktan barındırılan, uygulama ikili programıyla paket halinde sunulan veya her iki model de kullanılabilir.

Firebase'de bir model barındırarak bir model yayınlamadan güncelleyebilirsiniz. ve Remote Config ve A/B Testi'ni kullanarak Farklı kullanıcı gruplarına dinamik olarak farklı modeller sunar.

Modeli Firebase'de barındırarak değil, yalnızca Firebase'de barındırarak sağlamayı seçerseniz uygulamanızla birlikte paket haline getirirseniz uygulamanızın başlangıçtaki indirme boyutunu küçültebilirsiniz. Bununla birlikte, modelin uygulamanızla birlikte pakette olmadığı durumlarda, uygulamanız, uygulamanızı indirene kadar modelle ilgili işlevleri ilk kez devreye giriyor.

Modelinizi uygulamanızla paket haline getirerek uygulamanızın makine öğrenimi özelliklerinin etkin olmasını sağlayabilirsiniz. Firebase tarafından barındırılan model kullanılamadığında çalışmaya devam eder.

Firebase'de modelleri barındırma

TensorFlow Lite modelinizi Firebase'de barındırmak için:

  1. Firebase konsolunun Makine Öğrenimi Kiti bölümünde Özel sekmesi.
  2. Özel model ekle (veya Başka bir model ekle) seçeneğini tıklayın.
  3. Firebase'inizde modelinizi tanımlamak için kullanılacak bir ad belirtin açın, ardından TensorFlow Lite model dosyasını yükleyin (genellikle .tflite veya .lite).

Firebase projenize özel model ekledikten sonra, modeliniz olmalıdır. İstediğiniz zaman yeni bir TensorFlow Lite modelini çıkarırsanız uygulamanız yeni modeli indirir ve Uygulama yeniden başlatıldığında bunu kullanmaya başlayabilirsiniz. Cihazı tanımlayabilirsiniz. uygulamanızın modeli güncellemeyi denemesi için gereken koşullar (aşağıya bakın).

Modelleri uygulama ile paketleme

TensorFlow Lite modelinizi uygulamanızla paketlemek için model dosyasını (genellikle .tflite veya .lite ile biten) Xcode projenize ekleyebilirsiniz. Bunu yaparken paket kaynaklarını kopyalayın. Model dosyası uygulama paketinden ve ML Kit'te kullanılabilir.

Modeli yükleme

TensorFlow Lite modelinizi uygulamanızda kullanmak için öncelikle ML Kit'i modelinizin mevcut olduğu konumlar: Firebase'i uzaktan kullanma, ya da her ikisi birden olabilir. Hem yerel hem de uzak model belirtirseniz aşağıdakileri yapabilirsiniz: varsa uzak modeli kullanın ve yerel olarak depolanan modelle ilişkilidir.

Firebase tarafından barındırılan bir modeli yapılandırma

Modelinizi Firebase ile barındırdıysanız bir CustomRemoteModel nesnesi oluşturun. modeli yayınlarken atadığınız adı belirtin:

Swift

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

Objective-C

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

Ardından, model indirme görevinizi başlatın ve çalıştırmayı istediğiniz koşulları indirmeye izin vermek istiyorsunuz. Model cihazda yoksa veya sürümü kullanılabiliyorsa görev, yeni bir sürümün yüklü olduğu modeliniz:

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

Birçok uygulama, indirme görevini başlatma kodunda başlatır ancak Bu nedenle, herhangi bir noktada modeli kullanmanız gerekir.

Yerel model yapılandırma

Modeli uygulamanızla paketlediyseniz bir CustomLocalModel nesnesi oluşturun, TensorFlow Lite modelinin dosya adını belirtin:

Swift

guard let modelPath = Bundle.main.path(
  forResource: "your_model",
  ofType: "tflite",
  inDirectory: "your_model_directory"
) else { /* Handle error. */ }
let localModel = CustomLocalModel(modelPath: modelPath)

Objective-C

NSString *modelPath = [NSBundle.mainBundle pathForResource:@"your_model"
                                                    ofType:@"tflite"
                                               inDirectory:@"your_model_directory"];
FIRCustomLocalModel *localModel =
    [[FIRCustomLocalModel alloc] initWithModelPath:modelPath];

Modelinizden çevirmen oluşturma

Model kaynaklarınızı yapılandırdıktan sonra ModelInterpreter bir nesne çıkarmayı deneyin.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa CustomLocalModel öğesini iletmeniz yeterlidir nesnesini (modelInterpreter(localModel:)) çağırın:

Swift

let interpreter = ModelInterpreter.modelInterpreter(localModel: localModel)

Objective-C

FIRModelInterpreter *interpreter =
    [FIRModelInterpreter modelInterpreterForLocalModel:localModel];

Uzaktan barındırılan bir modeliniz varsa bu modelin indiremezsiniz. Model indirme işleminin durumunu kontrol edebilirsiniz. model yöneticisinin isModelDownloaded(remoteModel:) yöntemini kullanarak görevi tamamlayın.

Çevirmeni çalıştırmadan önce bunu onaylamanız gerekse de hem uzaktan barındırılan hem de yerel olarak paketlenen ModelInterpreter örneğini örneklendirirken şu kontrolü gerçekleştirmek mantıklıdır: yerel modelden ve yerel makine öğreniminden modelini kullanmanız gerekir.

Swift

var interpreter: ModelInterpreter
if ModelManager.modelManager().isModelDownloaded(remoteModel) {
  interpreter = ModelInterpreter.modelInterpreter(remoteModel: remoteModel)
} else {
  interpreter = ModelInterpreter.modelInterpreter(localModel: localModel)
}

Objective-C

FIRModelInterpreter *interpreter;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
  interpreter = [FIRModelInterpreter modelInterpreterForRemoteModel:remoteModel];
} else {
  interpreter = [FIRModelInterpreter modelInterpreterForLocalModel:localModel];
}

Yalnızca uzaktan barındırılan bir modeliniz varsa modelle ilgili ayarını devre dışı bırakmanız gerekir. devre dışı bırakana veya gizleyene kadar (örneğin, modelin indirildiğini onaylayın.

Varsayılan değere gözlemleyiciler ekleyerek model indirme durumunu öğrenebilirsiniz. Bildirim Merkezi. Gözlemcide self için zayıf bir referans kullandığınızdan emin olun biraz zaman alabilir ve kaynak nesne indirme tamamlandığında serbest bırakılır. Örneğin:

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

Modelin giriş ve çıkışını belirtin

Ardından, model yorumlayıcının giriş ve çıkış biçimlerini yapılandırın.

TensorFlow Lite modeli girdi olarak alır ve bir veya daha fazla çıkış olarak üretir çok boyutlu diziler. Bu diziler byte, int, long veya float değerleri. Şunu yapmalısınız: ML Kit'ini, kullandığınız dizilerin sayısı ve boyutlarıyla ("şekli") en iyi uygulamaları göz önünde bulundurun.

Modelinizin giriş ve çıkışının şeklini ve veri türünü bilmiyorsanız modelinizi incelemek için TensorFlow Lite Python yorumlayıcısını kullanabilirsiniz. Örneğin:

import tensorflow as tf

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

# Print input shape and type
print(interpreter.get_input_details()[0]['shape'])  # Example: [1 224 224 3]
print(interpreter.get_input_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

# Print output shape and type
print(interpreter.get_output_details()[0]['shape'])  # Example: [1 1000]
print(interpreter.get_output_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

Modelinizin giriş ve çıkışının biçimini belirledikten sonra uygulamanızın model çevirmeni için ModelInputOutputOptions nesnesini tanımlayın.

Örneğin, kayan noktalı görüntü sınıflandırma modeli için NBir grubu temsil eden Float değerlerinden oluşan x224x224x3 dizisi N 224x224 üç kanallı (RGB) resimler ve Her biri resmin üyesi olma olasılığını temsil eden 1.000 Float değeri kategoriden birini seçmeniz gerekir.

Böyle bir model için model çevirmeninin giriş ve çıkışını yapılandırırsınız. aşağıdaki gibidir:

Swift

let ioOptions = ModelInputOutputOptions()
do {
    try ioOptions.setInputFormat(index: 0, type: .float32, dimensions: [1, 224, 224, 3])
    try ioOptions.setOutputFormat(index: 0, type: .float32, dimensions: [1, 1000])
} catch let error as NSError {
    print("Failed to set input or output format with error: \(error.localizedDescription)")
}

Objective-C

FIRModelInputOutputOptions *ioOptions = [[FIRModelInputOutputOptions alloc] init];
NSError *error;
[ioOptions setInputFormatForIndex:0
                             type:FIRModelElementTypeFloat32
                       dimensions:@[@1, @224, @224, @3]
                            error:&error];
if (error != nil) { return; }
[ioOptions setOutputFormatForIndex:0
                              type:FIRModelElementTypeFloat32
                        dimensions:@[@1, @1000]
                             error:&error];
if (error != nil) { return; }

Giriş verilerinde çıkarım yap

Son olarak, modeli kullanarak çıkarım yapmak, giriş verilerinizi almak, dönüşüm işlemlerini daha verimli şekilde gerçekleştirebilir ve Verileri içeren Data nesnesi.

Örneğin, modeliniz görüntüleri işliyorsa ve modelinizin giriş boyutları varsa [BATCH_SIZE, 224, 224, 3] kayan nokta değerinden dolayı resmin renk değerlerini, aşağıdaki örnekte olduğu gibi bir kayan nokta aralığına ayarlayın:

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 }

let inputs = ModelInputs()
var inputData = Data()
do {
  for row in 0 ..< 224 {
    for col in 0 ..< 224 {
      let offset = 4 * (col * context.width + row)
      // (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(&bytes, &normalizedRed, elementSize)
      inputData.append(&bytes, count: elementSize)
      memcpy(&bytes, &normalizedGreen, elementSize)
      inputData.append(&bytes, count: elementSize)
      memcpy(&ammp;bytes, &normalizedBlue, elementSize)
      inputData.append(&bytes, count: elementSize)
    }
  }
  try inputs.addInput(inputData)
} catch let error {
  print("Failed to add input: \(error)")
}

Objective-C

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

FIRModelInputs *inputs = [[FIRModelInputs alloc] init];
NSMutableData *inputData = [[NSMutableData alloc] initWithCapacity:0];

for (int row = 0; row < 224; row++) {
  for (int col = 0; col < 224; col++) {
    long offset = 4 * (col * imageWidth + row);
    // 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.
    // (Ignore offset 0, the unused alpha channel)
    Float32 red = imageData[offset+1] / 255.0f;
    Float32 green = imageData[offset+2] / 255.0f;
    Float32 blue = imageData[offset+3] / 255.0f;

    [inputData appendBytes:&red length:sizeof(red)];
    [inputData appendBytes:&green length:sizeof(green)];
    [inputData appendBytes:&blue length:sizeof(blue)];
  }
}

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

Model girişinizi hazırladıktan sonra (ve modelin, varsa, giriş ve giriş/çıkış seçeneklerini model çevirmeninizin run(inputs:options:completion:) yöntemidir.

Swift

interpreter.run(inputs: inputs, options: ioOptions) { outputs, error in
    guard error == nil, let outputs = outputs else { return }
    // Process outputs
    // ...
}

Objective-C

[interpreter runWithInputs:inputs
                   options:ioOptions
                completion:^(FIRModelOutputs * _Nullable outputs,
                             NSError * _Nullable error) {
  if (error != nil || outputs == nil) {
    return;
  }
  // Process outputs
  // ...
}];

Oluşturulan nesnenin output(index:) yöntemini çağırarak çıktıyı alabilirsiniz hatası döndürülür. Örneğin:

Swift

// Get first and only output of inference with a batch size of 1
let output = try? outputs.output(index: 0) as? [[NSNumber]]
let probabilities = output??[0]

Objective-C

// Get first and only output of inference with a batch size of 1
NSError *outputError;
NSArray *probabilites = [outputs outputAtIndex:0 error:&outputError][0];

Sonucu nasıl kullanacağınız, kullandığınız modele bağlıdır.

Örneğin, sınıflandırma yapıyorsanız, bir sonraki adım olarak sonucun dizinlerini, temsil ettikleri etiketlerle eşleştirir. Bir modelinizin her bir kategorisi için etiket dizeleri içeren metin dosyası; dünyanın dört bir yanındaki etiket dizelerini çıktı olasılıklarına bağlayacak şekilde takip etmek için:

Swift

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 0 ..< labels.count {
  if let probability = probabilities?[i] {
    print("\(labels[i]): \(probability)")
  }
}

Objective-C

NSError *labelReadError = nil;
NSString *labelPath = [NSBundle.mainBundle pathForResource:@"retrained_labels"
                                                    ofType:@"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:labelPath
                                                   encoding:NSUTF8StringEncoding
                                                      error:&labelReadError];
if (labelReadError != nil || fileContents == NULL) { return; }
NSArray<NSString *> *labels = [fileContents componentsSeparatedByString:@"\n"];
for (int i = 0; i < labels.count; i++) {
    NSString *label = labels[i];
    NSNumber *probability = probabilites[i];
    NSLog(@"%@: %f", label, probability.floatValue);
}

Ek: Model güvenliği

TensorFlow Lite modellerinizi kullanıcılara nasıl sunduğunuz fark etmeksizin ML Kit, ML Kit, bu dosyaları standart serileştirilmiş protobuf biçiminde depolar. yerel depolama.

Teoride bu, herkesin modelinizi kopyalayabileceği anlamına gelir. Ancak, pratikte çoğu model, uygulamaya özgüdür ve her bir model rakiplerin parçalarının parçalarının sökülüp parçalarının parçalarının kodunuzu tekrarlamanız gerekir. Yine de, anahtar kelimeleri kullanmadan önce bu riskin farkında olmalısınız. bir model oluşturabilirsiniz.