Catch up on highlights from Firebase at Google I/O 2023. Learn more

Eski özel model API'sinden geçiş yapın

Firebase/MLModelInterpreter kitaplığının 0.20.0 sürümü, özel modellerin aygıtındaki konumu alan yeni bir getLatestModelFilePath() yöntemini sunar. Firebase'in ModelInterpreter sarmalayıcısı yerine kullanabileceğiniz bir TensorFlow Lite Interpreter nesnesini doğrudan başlatmak için bu yöntemi kullanabilirsiniz.

İleriye dönük olarak, bu tercih edilen yaklaşımdır. TensorFlow Lite yorumlayıcı sürümü artık Firebase kitaplığı sürümüyle birleştirilmediğinden, istediğiniz zaman TensorFlow Lite'ın yeni sürümlerine yükseltmek veya özel TensorFlow Lite yapılarını daha kolay kullanmak için daha fazla esnekliğe sahipsiniz.

Bu sayfa, ModelInterpreter kullanmaktan TensorFlow Lite Interpreter nasıl geçiş yapabileceğinizi gösterir.

1. Proje bağımlılıklarını güncelleyin

Firebase/MLModelInterpreter kitaplığının (veya daha yenisinin) ve TensorFlow Lite kitaplığının 0.20.0 sürümünü içerecek şekilde projenizin Pod dosyasını güncelleyin:

Önce

Süratli

pod 'Firebase/MLModelInterpreter', '0.19.0'

Amaç-C

pod 'Firebase/MLModelInterpreter', '0.19.0'

Sonrasında

Süratli

pod 'Firebase/MLModelInterpreter', '~> 0.20.0'
pod 'TensorFlowLiteSwift'

Amaç-C

pod 'Firebase/MLModelInterpreter', '~> 0.20.0'
pod 'TensorFlowLiteObjC'

2. Firebase ModelInterpreter yerine bir TensorFlow Lite yorumlayıcısı oluşturun

Firebase ModelInterpreter oluşturmak yerine getLatestModelFilePath() ile modelin cihazdaki konumunu alın ve bunu bir TensorFlow Lite Interpreter oluşturmak için kullanın.

Önce

Süratli

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

Amaç-C

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

Sonrasında

Süratli

let remoteModel = CustomRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Firebase console.
)
ModelManager.modelManager().getLatestModelFilePath(remoteModel) { (remoteModelPath, error) in
    guard error == nil, let remoteModelPath = remoteModelPath else { return }
    do {
        interpreter = try Interpreter(modelPath: remoteModelPath)
    } catch {
        // Error?
    }
}

Amaç-C

FIRCustomRemoteModel *remoteModel =
        [[FIRCustomRemoteModel alloc] initWithName:@"your_remote_model"];
[[FIRModelManager modelManager] getLatestModelFilePath:remoteModel
                                            completion:^(NSString * _Nullable filePath,
                                                         NSError * _Nullable error) {
    if (error != nil || filePath == nil) { return; }

    NSError *tfError = nil;
    interpreter = [[TFLInterpreter alloc] initWithModelPath:filePath error:&tfError];
}];

3. Girdi ve çıktı hazırlama kodunu güncelleyin

ModelInterpreter ile, çalıştırdığınızda yorumlayıcıya bir ModelInputOutputOptions nesnesi ileterek modelin girdi ve çıktı şekillerini belirtirsiniz.

TensorFlow Lite yorumlayıcısı için bunun yerine allocateTensors() u çağırarak modelin giriş ve çıkışına yer ayırın, ardından giriş verilerinizi giriş tensörlerine kopyalayın.

Örneğin, modelinizin giriş şekli [1 224 224 3] float değerlere ve çıkış şekli [1 1000] float değerlere sahipse şu değişiklikleri yapın:

Önce

Süratli

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)")
}

let inputs = ModelInputs()
do {
    let inputData = Data()
    // Then populate with input data.

    try inputs.addInput(inputData)
} catch let error {
    print("Failed to add input: \(error)")
}

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

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

FIRModelInputs *inputs = [[FIRModelInputs alloc] init];
NSMutableData *inputData = [[NSMutableData alloc] initWithCapacity:0];
// Then populate with input data.

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

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

Sonrasında

Süratli

do {
    try interpreter.allocateTensors()

    let inputData = Data()
    // Then populate with input data.

    try interpreter.copy(inputData, toInputAt: 0)

    try interpreter.invoke()
} catch let err {
    print(err.localizedDescription)
}

Amaç-C

NSError *error = nil;

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

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

NSMutableData *inputData = [[NSMutableData alloc] initWithCapacity:0];
// Then populate with input data.

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

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

4. Çıkış işleme kodunu güncelleyin

Son olarak, ModelOutputs nesnesinin output() yöntemiyle modelin çıktısını almak yerine, yorumlayıcıdan çıktı tensörünü alın ve verilerini kullanım durumunuz için uygun olan yapıya dönüştürün.

Örneğin, sınıflandırma yapıyorsanız aşağıdaki gibi değişiklikler yapabilirsiniz:

Önce

Süratli

let output = try? outputs.output(index: 0) as? [[NSNumber]]
let probabilities = output?[0]

guard let labelPath = Bundle.main.path(
    forResource: "custom_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)")
    }
}

Amaç-C

// Get first and only output of inference with a batch size of 1
NSError *error;
NSArray *probabilites = [outputs outputAtIndex:0 error:&error][0];
if (error != nil) { return; }

NSString *labelPath = [NSBundle.mainBundle pathForResource:@"retrained_labels"
                                                    ofType:@"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:labelPath
                                                   encoding:NSUTF8StringEncoding
                                                      error:&error];
if (error != 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);
}

Sonrasında

Süratli

do {
    // After calling interpreter.invoke():
    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: "custom_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])")
    }
} catch let err {
    print(err.localizedDescription)
}

Amaç-C

NSError *error = nil;

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

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

Float32 probabilities[outputData.length / 4];
[outputData getBytes:&probabilities length:outputData.length];

NSString *labelPath = [NSBundle.mainBundle pathForResource:@"custom_labels"
                                                    ofType:@"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:labelPath
                                                   encoding:NSUTF8StringEncoding
                                                      error:&error];
if (error != nil || fileContents == nil) { return; }

NSArray<NSString *> *labels = [fileContents componentsSeparatedByString:@"\n"];
for (int i = 0; i < labels.count; i++) {
    NSLog(@"%@: %f", labels[i], probabilities[i]);
}