Google is committed to advancing racial equity for Black communities. See how.
Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

İOS'ta ML Kit ile çıkarım yapmak için bir TensorFlow Lite modeli kullanın

ML Kit'i bir TensorFlow Lite modeliyle cihaz üzerinde çıkarım yapmak için kullanabilirsiniz .

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

Sen başlamadan önce

  1. Uygulamanıza daha önce Firebase eklemediyseniz, başlangıç kılavuzundaki adımları uygulayarak bunu yapın.
  2. Pod Kitinize ML Kit kitaplıklarını ekleyin:
    pod 'Firebase/MLModelInterpreter', '6.25.0'
    
    Projenizin .xcworkspace yükledikten veya güncelledikten sonra, Xcode projenizi .xcworkspace kullanarak açtığınızdan emin olun.
  3. Uygulamanızda Firebase'i içe aktarın:

    hızlı

    import Firebase

    Objective-C

    @import Firebase;
  4. Kullanmak istediğiniz TensorFlow modelini TensorFlow Lite biçimine dönüştürün. Bkz. TOCO: TensorFlow Lite Optimizing Converter .

Modelinizi barındırın veya paketleyin

Bir TensorFlow Lite modelini uygulamanızda çıkarım yapmak için kullanmadan önce, modeli ML Kit için kullanılabilir hale getirmelisiniz. ML Kit, Firebase'i kullanarak, uygulama ikili dosyasıyla veya her ikisiyle birlikte uzaktan barındırılan TensorFlow Lite modellerini kullanabilir.

Firebase'de bir model barındırarak, yeni bir uygulama sürümü yayınlamadan modeli güncelleyebilir ve farklı modelleri farklı kullanıcı gruplarına dinamik olarak sunmak için Uzaktan Yapılandırma ve A / B Testi'ni kullanabilirsiniz.

Modeli yalnızca Firebase ile barındırarak sağlamayı seçerseniz ve uygulamanızla birlikte paketlemezseniz, uygulamanızın ilk indirme boyutunu azaltabilirsiniz. Bununla birlikte, model uygulamanızla birlikte verilmezse, uygulamanız modeli ilk kez indirinceye kadar modelle ilgili işlevlerin kullanılamayacağını unutmayın.

Modelinizi uygulamanızla birleştirerek, Firebase tarafından barındırılan model mevcut olmadığında uygulamanızın ML özelliklerinin çalışmaya devam etmesini sağlayabilirsiniz.

Firebase'de ana makine modelleri

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

  1. Firebase konsolunun ML Kiti bölümünde Özel sekmesini tıklayın.
  2. Özel model ekle'yi (veya Başka bir model ekle ) tıklayın.
  3. Firebase projenizde modelinizi tanımlamak için kullanılacak bir ad belirtin, ardından TensorFlow Lite model dosyasını yükleyin (genellikle .tflite veya .lite ).

Firebase projenize özel bir model ekledikten sonra, belirttiğiniz adı kullanarak uygulamalarınızdaki modele başvurabilirsiniz. İstediğiniz zaman yeni bir TensorFlow Lite modeli yükleyebilirsiniz; uygulamanız yeni modeli indirir ve uygulama bir sonraki yeniden başlatıldığında kullanmaya başlar. Uygulamanızın modeli güncellemeye çalışması için gereken cihaz koşullarını tanımlayabilirsiniz (aşağıya bakın).

Modelleri bir uygulama ile birleştirme

Uygulamanızla birlikte giderek TensorFlow Lite modeli paket için, model dosyası (genellikle biten eklemek .tflite veya .lite bunu yaptığınızda kaynakların yumağı Kopyala seçmek için özen, Xcode projesine kadar). Model dosyası uygulama paketine dahil edilecek ve ML Kit tarafından kullanılabilecektir.

Modeli yükle

TensorFlow Lite modelinizi uygulamanızda kullanmak için, önce ML Kit'i modelinizin mevcut olduğu konumlarla yapılandırın: Firebase'i uzaktan kullanarak, yerel depolamada veya her ikisinde. Hem yerel hem de uzak bir model belirtirseniz, varsa uzak modeli kullanabilir ve uzak model mevcut değilse yerel olarak depolanan modele geri dönebilirsiniz.

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

Modelinizi Firebase ile barındırdıysanız, modeli yayınladığınızda atadığınız adı belirterek bir CustomRemoteModel nesnesi oluşturun:

hızlı

 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, indirmeye izin vermek istediğiniz koşulları belirterek model indirme görevini başlatın. Model cihazda yoksa veya modelin daha yeni bir sürümü mevcutsa görev, senkronize olmayan bir şekilde Firebase'den modeli indirir:

hızlı

 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 kodlarında başlatır, ancak bunu modeli kullanmanız gerekmeden önce istediğiniz zaman yapabilirsiniz.

Yerel modeli yapılandırma

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

hızlı

 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 bir tercüman oluşturun

Model kaynaklarınızı yapılandırdıktan sonra, bunlardan birinden bir ModelInterpreter nesnesi oluşturun.

Yalnızca yerel olarak paketlenmiş bir modeliniz varsa, CustomLocalModel nesnesini modelInterpreter(localModel:) :

hızlı

 let interpreter = ModelInterpreter.modelInterpreter(localModel: localModel)
 

Objective-C

 FIRModelInterpreter *interpreter =
    [FIRModelInterpreter modelInterpreterForLocalModel:localModel];
 

Uzaktan barındırılan bir modeliniz varsa, çalıştırmadan önce modelin indirildiğini kontrol etmeniz gerekir. Model indirme görevinin durumunu model yöneticisinin isModelDownloaded(remoteModel:) yöntemini kullanarak kontrol edebilirsiniz.

Bunu yalnızca yorumlayıcıyı çalıştırmadan önce onaylamanız gerekse de, hem uzaktan barındırılan bir modeliniz hem de yerel olarak paketlenmiş bir modeliniz varsa, ModelInterpreter başlatırken bu kontrolü gerçekleştirmek mantıklı olabilir: aksi takdirde yerel modelden indirilmiştir.

hızlı

 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, modelin indirildiğini onaylayana kadar modelle ilgili işlevselliği (örneğin, kullanıcı arayüzünüzün grileşmesini veya gizlenmesini) devre dışı bırakmalısınız.

Gözlemcileri varsayılan Bildirim Merkezi'ne ekleyerek model indirme durumunu alabilirsiniz. İndirmeler biraz zaman alabileceğinden ve kaynak nesnesi indirme işlemi bittiğinde serbest bırakılabileceğinden, gözlemci bloğunda self zayıf bir referans kullandığınızdan emin olun. Örneğin:

hızlı

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.

Bir TensorFlow Lite modeli girdi olarak alır ve çıktı olarak bir veya daha fazla çok boyutlu dizi üretir. Bu diziler byte , int , long veya float değer içerir. ML Kitini modelinizin kullandığı dizilerin sayısı ve boyutları ("şekli") ile yapılandırmalısınız.

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ış biçimini belirledikten sonra, bir ModelInputOutputOptions nesnesi oluşturarak uygulamanızın model yorumlayıcısını yapılandırın.

Örneğin, bir kayan noktalı görüntü sınıflandırma modeli girdi olarak bir alabilir N arasında x224x224x3 dizisi Float bir toplu temsil değerleri N 1000 listesini çıkışı olarak 224x224 üç kanal (RGB) görüntü ve üretim Float her birini temsil eden değerler olasılık, modelin öngördüğü 1000 kategoriden birinin üyesidir.

Böyle bir model için, model yorumlayıcının giriş ve çıkışını aşağıda gösterildiği gibi yapılandırabilirsiniz:

hızlı

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 çıkarsama gerçekleştirin

Son olarak, modeli kullanarak çıkarım yapmak için giriş verilerinizi alın, modeliniz için gerekli olabilecek veriler üzerinde herhangi bir dönüşüm gerçekleştirin ve verileri içeren bir Data nesnesi oluşturun.

Örneğin, modeliniz görüntüleri [BATCH_SIZE, 224, 224, 3] ve modelinizin [BATCH_SIZE, 224, 224, 3] kayan nokta değerlerinin giriş boyutları varsa, görüntünün renk değerlerini aşağıdaki örnekteki gibi bir kayan nokta aralığına ölçeklendirmeniz gerekebilir :

hızlı

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 kullanılabilir olduğunu onayladıktan sonra), giriş ve giriş / çıkış seçeneklerini model yorumcunuzun run(inputs:options:completion:) yöntemine iletin.

hızlı

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

Döndürülen nesnenin output(index:) yöntemini çağırarak çıktı alabilirsiniz. Örneğin:

hızlı

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

Çıktıyı nasıl kullandığınız, kullandığınız modele bağlıdır.

Örneğin, bir sonraki adım olarak sınıflandırma yapıyorsanız, sonucun dizinlerini temsil ettikleri etiketlerle eşleştirebilirsiniz. Modelinizin kategorilerinin her biri için etiket dizeleri içeren bir metin dosyanız olduğunu varsayalım; aşağıdakine benzer bir şey yaparak etiket dizelerini çıktı olasılıklarıyla eşleyebilirsiniz:

hızlı

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 ML Kit için nasıl kullanılabilir hale getirdiğinizden bağımsız olarak, ML Kit bunları yerel depolamada standart seri protobuf formatında saklar.

Teorik olarak, bu, herhangi birinin modelinizi kopyalayabileceği anlamına gelir. Bununla birlikte, uygulamada, çoğu model o kadar uygulamaya özeldir ve optimizasyonlar tarafından gizlenir ve risk, kodunuzu söküp tekrar kullanan rakiplerinkine benzer. Bununla birlikte, uygulamanızda özel bir model kullanmadan önce bu riskin farkında olmalısınız.