Version 0.20.0 der Firebase/MLModelInterpreter
Bibliothek führt eine neue getLatestModelFilePath()
Methode ein, die den Speicherort benutzerdefinierter Modelle auf dem Gerät abruft. Mit dieser Methode können Sie ein TensorFlow Lite Interpreter
Objekt direkt instanziieren, das Sie anstelle des ModelInterpreter
Wrappers von Firebase verwenden können.
Für die Zukunft ist dies der bevorzugte Ansatz. Da die TensorFlow Lite-Interpreterversion nicht mehr mit der Firebase-Bibliotheksversion gekoppelt ist, haben Sie mehr Flexibilität, bei Bedarf auf neue Versionen von TensorFlow Lite zu aktualisieren oder benutzerdefinierte TensorFlow Lite-Builds einfacher zu verwenden.
Auf dieser Seite wird gezeigt, wie Sie von der Verwendung ModelInterpreter
auf den TensorFlow Lite Interpreter
migrieren können.
1. Projektabhängigkeiten aktualisieren
Aktualisieren Sie die Poddatei Ihres Projekts so, dass sie Version 0.20.0 der Firebase/MLModelInterpreter
Bibliothek (oder neuer) und der TensorFlow Lite-Bibliothek enthält:
Vor
Schnell
pod 'Firebase/MLModelInterpreter', '0.19.0'
Ziel c
pod 'Firebase/MLModelInterpreter', '0.19.0'
Nach
Schnell
pod 'Firebase/MLModelInterpreter', '~> 0.20.0'
pod 'TensorFlowLiteSwift'
Ziel c
pod 'Firebase/MLModelInterpreter', '~> 0.20.0'
pod 'TensorFlowLiteObjC'
2. Erstellen Sie einen TensorFlow Lite-Interpreter anstelle eines Firebase ModelInterpreter
Anstatt einen Firebase ModelInterpreter
zu erstellen, rufen Sie mit getLatestModelFilePath()
den Speicherort des Modells auf dem Gerät ab und verwenden Sie ihn, um einen TensorFlow Lite Interpreter
zu erstellen.
Vor
Schnell
let remoteModel = CustomRemoteModel(
name: "your_remote_model" // The name you assigned in the Firebase console.
)
interpreter = ModelInterpreter.modelInterpreter(remoteModel: remoteModel)
Ziel c
// Initialize using the name you assigned in the Firebase console.
FIRCustomRemoteModel *remoteModel =
[[FIRCustomRemoteModel alloc] initWithName:@"your_remote_model"];
interpreter = [FIRModelInterpreter modelInterpreterForRemoteModel:remoteModel];
Nach
Schnell
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?
}
}
Ziel 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. Aktualisieren Sie den Eingabe- und Ausgabevorbereitungscode
Mit ModelInterpreter
geben Sie die Eingabe- und Ausgabeformen des Modells an, indem Sie beim Ausführen ein ModelInputOutputOptions
Objekt an den Interpreter übergeben.
Für den TensorFlow Lite-Interpreter rufen Sie stattdessen allocateTensors()
auf, um Platz für die Eingabe und Ausgabe des Modells zu reservieren, und kopieren dann Ihre Eingabedaten in die Eingabetensoren.
Wenn Ihr Modell beispielsweise eine Eingabeform mit [1 224 224 3] float
und eine Ausgabeform mit [1 1000] float
hat, nehmen Sie die folgenden Änderungen vor:
Vor
Schnell
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
// ...
}
Ziel 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
// ...
}];
Nach
Schnell
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)
}
Ziel 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. Aktualisieren Sie den Ausgabeverarbeitungscode
Anstatt schließlich die Ausgabe des Modells mit der Methode output()
des ModelOutputs
Objekts abzurufen, rufen Sie den Ausgabetensor vom Interpreter ab und konvertieren Sie seine Daten in eine beliebige Struktur, die für Ihren Anwendungsfall geeignet ist.
Wenn Sie beispielsweise eine Klassifizierung durchführen, können Sie Änderungen wie die folgenden vornehmen:
Vor
Schnell
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)")
}
}
Ziel 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);
}
Nach
Schnell
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)
}
Ziel 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]);
}