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 özel bir TensorFlow Lite modeli kullanın

Uygulamanız özel TensorFlow Lite modelleri kullanıyorsa, modellerinizi dağıtmak için Firebase ML'yi kullanabilirsiniz. Modelleri Firebase ile dağıtarak, uygulamanızın ilk indirme boyutunu azaltabilir ve uygulamanızın yeni bir sürümünü yayınlamadan uygulamanızın ML modellerini güncelleyebilirsiniz. Ve Remote Config ve A / B Testing ile, farklı kullanıcı gruplarına dinamik olarak farklı modeller sunabilirsiniz.

TensorFlow Lite, yalnızca iOS 9 ve daha yenisini kullanan cihazlarda çalışır.

TensorFlow Lite modelleri

TensorFlow Lite modelleri, mobil cihazlarda çalışacak şekilde optimize edilmiş makine öğrenimi modelleridir. Bir TensorFlow Lite modeli almak için:

Sen başlamadan önce

  1. Uygulamanıza henüz Firebase eklemediyseniz, başlangıç kılavuzundaki adımları izleyerek bunu yapın.
  2. Firebase ML'yi Pod Dosyanıza ekleyin:

    Swift

    pod 'Firebase/MLModelInterpreter'
    pod 'TensorFlowLiteSwift'
    

    Amaç-C

    pod 'Firebase/MLModelInterpreter'
    pod 'TensorFlowLiteObjC'
    
    Projenizin Kapsüllerini yükledikten veya güncelledikten sonra, .xcworkspace kullanarak Xcode projenizi açtığınızdan emin olun.
  3. Uygulamanızda Firebase'i içe aktarın:

    Swift

    import Firebase
    import TensorFlowLite
    

    Amaç-C

    @import Firebase;
    @import TFLTensorFlowLite;
    

1. Modelinizi dağıtın

Firebase konsolunu veya Firebase Admin Python ve Node.js SDK'larını kullanarak özel TensorFlow modellerinizi dağıtın. Özel modelleri dağıtma ve yönetme konusuna bakın.

Firebase projenize özel bir model ekledikten sonra, belirlediğiniz adı kullanarak uygulamalarınızdaki modele başvurabilirsiniz. İstediğiniz zaman yeni bir TensorFlow Lite modeli yükleyebilirsiniz ve uygulamanız yeni modeli indirir ve uygulama bir sonraki yeniden başladığında onu 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).

2. Modeli cihaza indirin

TensorFlow Lite modelinizi uygulamanızda kullanmak için öncelikle modelin en son sürümünü cihaza indirmek üzere Firebase ML SDK'yı kullanın.

Model indirmeyi başlatmak için, modeli yüklediğinizde atadığınız adı ve indirmeye izin vermek istediğiniz koşulları belirterek model yöneticisinin download() yöntemini çağırın. Model cihazda değilse veya modelin daha yeni bir sürümü mevcutsa görev, modeli Firebase'den eşzamansız olarak indirir.

Modelin indirildiğini onaylayana kadar, modelle ilgili işlevselliği devre dışı bırakmalısınız - örneğin, kullanıcı arayüzünüzün bir kısmını gri hale getirin veya gizleyin -.

Swift

let remoteModel = CustomRemoteModel(
  name: "your_remote_model"  // The name you assigned in the Firebase console.
)
let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)
let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

Amaç-C

// Initialize using the name you assigned in the Firebase console.
FIRCustomRemoteModel *remoteModel =
    [[FIRCustomRemoteModel alloc] initWithName:@"your_remote_model"];
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 modeli kullanmanız gerekmeden önce bunu herhangi bir noktada yapabilirsiniz.

Gözlemcileri varsayılan Bildirim Merkezi'ne ekleyerek model indirme durumunu öğrenebilirsiniz. Gözlemci bloğunda self zayıf bir referans kullandığınızdan emin olun, çünkü indirmeler biraz zaman alabilir ve kaynak nesne indirme işlemi bittiğinde serbest bırakılabilir. Ö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]
    // ...
}

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

3. Bir TensorFlow Lite yorumlayıcısını başlatın

Modeli cihaza indirdikten sonra, model yöneticisinin getLatestModelFilePath() yöntemini çağırarak model dosyası konumunu alabilirsiniz. Bir TensorFlow Lite yorumlayıcısını başlatmak için bu değeri kullanın:

Swift

var interpreter: Interpreter
ModelManager.modelManager().getLatestModelFilePath(remoteModel) { (remoteModelPath, error) in
    guard error == nil else { return }
    guard let remoteModelPath = remoteModelPath else { return }
    do {
        interpreter = try Interpreter(modelPath: remoteModelPath)
    } catch {
        // Error?
    }
}

Amaç-C

TFLInterpreter *interpreter;
[FIRModelManager.modelManager
 getLatestModelFilePath:remoteModel
             completion:^(NSString *_Nullable remoteModelPath, NSError *error) {
  if (remoteModelPath != null && error == null) {
    NSError *tfliteError;
    interpreter = [[TFLInterpreter alloc] initWithModelPath:remoteModelPath
                                                      error:&tfliteError];
  }
}];

4. Giriş verileri üzerinde çıkarım yapın

Modelinizin giriş ve çıkış şekillerini alın

TensorFlow Lite model yorumlayıcısı girdi olarak alır ve çıktı olarak bir veya daha fazla çok boyutlu dizi üretir. Bu diziler byte , int , long veya float değerlerini içerir. Bir modele veri iletmeden veya sonucunu kullanmadan önce, modelinizin kullandığı dizilerin sayısını ve boyutlarını ("şekli") bilmeniz gerekir.

Modeli kendiniz oluşturduysanız veya modelin giriş ve çıkış formatı belgelenmişse, bu bilgiye zaten sahip olabilirsiniz. Modelinizin giriş ve çıkışının şeklini ve veri türünü bilmiyorsanız, modelinizi incelemek için TensorFlow Lite yorumlayıcısını kullanabilirsiniz. Örneğin:

Python

import tensorflow as tf

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

# Print input shape and type
inputs = interpreter.get_input_details()
print('{} input(s):'.format(len(inputs)))
for i in range(0, len(inputs)):
    print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype']))

# Print output shape and type
outputs = interpreter.get_output_details()
print('\n{} output(s):'.format(len(outputs)))
for i in range(0, len(outputs)):
    print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))

Örnek çıktı:

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

Yorumlayıcıyı çalıştırın

Modelinizin girdi ve çıktısının formatını belirledikten sonra, giriş verilerinizi alın ve modeliniz için doğru şeklin girdisini elde etmek için gerekli olan veriler üzerinde herhangi bir dönüşüm gerçekleştirin.

Örneğin, modeliniz görüntüleri işliyorsa ve modelinizin giriş boyutları [1, 224, 224, 3] kayan nokta değerlerine sahipse, aşağıdaki örnekte olduğu gibi görüntünün renk değerlerini bir kayan nokta aralığına ölçeklemeniz gerekebilir. :

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 }

var inputData = Data()
for row in 0 ..&lt; 224 {
  for col in 0 ..&lt; 224 {
    let offset = 4 * (row * context.width + col)
    // (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(&amp;bytes, &amp;normalizedRed, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedGreen, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&ammp;bytes, &amp;normalizedBlue, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
  }
}

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

NSMutableData *inputData = [[NSMutableData alloc] initWithCapacity:0];

for (int row = 0; row &lt; 224; row++) {
  for (int col = 0; col &lt; 224; col++) {
    long offset = 4 * (row * imageWidth + col);
    // 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:&amp;red length:sizeof(red)];
    [inputData appendBytes:&amp;green length:sizeof(green)];
    [inputData appendBytes:&amp;blue length:sizeof(blue)];
  }
}

Ardından, giriş NSData yorumlayıcıya kopyalayın ve çalıştırın:

Swift

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

Amaç-C

NSError *error = nil;

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

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

Yorumlayıcının output(at:) yöntemini çağırarak modelin output(at:) . Çıkışı nasıl kullanacağı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şleyebilirsiniz:

Swift

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

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 labels.indices {
    print("\(labels[i]): \(probabilities[i])")
}

Amaç-C

NSError *error = nil;

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

NSData *outputData = [output dataWithError:&amp;error];
if (error != nil) { return; }

NSString *labelPath = [NSBundle.mainBundle pathForResource:@"retrained_labels"
                                                    ofType:@"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:labelPath
                                                   encoding:NSUTF8StringEncoding
                                                      error:&amp;error];
if (error != nil || fileContents == NULL) { return; }
NSArray&lt;NSString *> *labels = [fileContents componentsSeparatedByString:@"\n"];
for (int i = 0; i &lt; labels.count; i++) {
    NSString *label = labels[i];
    float probability;
    [outputData getBytes:&amp;probability range:NSMakeRange(i * 4, 4)];
    NSLog(@"%@: %f", label, probability);
}

Ek: Yerel olarak paketlenmiş bir modele geri dönün

Modelinizi Firebase ile barındırdığınızda, modelle ilgili herhangi bir işlev, uygulamanız modeli ilk kez indirene kadar kullanılamayacaktır. Bazı uygulamalar için bu iyi olabilir, ancak modeliniz temel işlevleri etkinleştiriyorsa, modelinizin bir sürümünü uygulamanızla birlikte paketleyip mevcut en iyi sürümü kullanmak isteyebilirsiniz. Bunu yaparak uygulamanızın ML özelliklerinin Firebase tarafından barındırılan model mevcut olmadığında çalışmasını sağlayabilirsiniz.

TensorFlow Lite modelinizi uygulamanızla birlikte paketlemek için model dosyasını (genellikle .tflite veya .lite biten) Xcode projenize ekleyin, bunu yaptığınızda dosyayı uygulamanın derleme hedefine eklemeye dikkat edin. Model dosyası, uygulama paketine dahil edilecek ve uygulamanızda kullanılabilecektir.

Ardından, barındırılan model mevcut olmadığında yerel olarak paketlenmiş modeli kullanın:

Swift

var interpreter: Interpreter
ModelManager.modelManager().getLatestModelFilePath(remoteModel) { (remoteModelPath, error) in
  guard let error == nil else { return }
  do {
      if let remoteModelPath = remoteModelPath {
          interpreter = try Interpreter(modelPath: remoteModelPath)
      } else {
          let localModelPath = Bundle.main.path(
              forResource: "your_model",
              ofType: "tflite"
          )
          interpreter = try Interpreter(modelPath: localModelPath ?? "")
      }
  } catch {
      print("Error initializing TensorFlow Lite: \(error.localizedDescription)")
      return
  }
}

Amaç-C

TFLInterpreter *interpreter;
[FIRModelManager.modelManager
 getLatestModelFilePath:remoteModel
             completion:^(NSString *_Nullable remoteModelPath, NSError *error) {
  if (remoteModelPath != null && error == null) {
    NSError *tfliteError;
    interpreter = [[TFLInterpreter alloc] initWithModelPath:remoteModelPath
                                                      error:&tfliteError];
  } else {
    NSError *tfliteError;
    NSString *localModelPath = [NSBundle.mainBundle pathForResource:@"model"
                                                             ofType:@"tflite"];
    interpreter = [[TFLInterpreter alloc] initWithModelPath:localModelPath
                                                      error:&tfliteError];
  }
}];

Ek: Model güvenliği

Firebase ML için TensorFlow Lite modellerinizi nasıl kullanılabilir hale getirdiğinizden bağımsız olarak Firebase ML, bunları yerel depolamada standart serileştirilmiş protobuf biçiminde depolar.

Teorik olarak bu, herkesin modelinizi kopyalayabileceği anlamına gelir. Bununla birlikte, pratikte, çoğu model o kadar uygulamaya özgüdür ve optimizasyonlarla karıştırılır ki, risk, kodunuzu söküp yeniden kullanan rakiplerinkine benzer. Yine de, uygulamanızda özel bir model kullanmadan önce bu riskin farkında olmalısınız.