ย้ายข้อมูลจาก API รูปแบบที่กำหนดเองเดิม

ไลบรารี Firebase/MLModelInterpreter เวอร์ชัน 0.20.0 ได้เปิดตัวฟีเจอร์ใหม่ getLatestModelFilePath() ซึ่งได้รับตำแหน่งในอุปกรณ์ของ โมเดลที่กำหนดเอง คุณใช้เมธอดนี้เพื่อสร้างอินสแตนซ์ TensorFlow Lite ได้โดยตรง Interpreter รายการซึ่งใช้แทน ModelInterpreter ของ Firebase ได้ Wrapper

นับแต่นี้ไป เราแนะนำให้ใช้วิธีนี้ เนื่องจาก TensorFlow Lite เวอร์ชันล่ามไม่ได้จับคู่กับเวอร์ชันไลบรารี Firebase แล้ว มีความยืดหยุ่นมากขึ้นในการอัปเกรดเป็น TensorFlow Lite เวอร์ชันใหม่เมื่อคุณ หรือใช้บิลด์ TensorFlow Lite ที่กำหนดเองได้ง่ายยิ่งขึ้น

หน้านี้แสดงวิธีย้ายข้อมูลจากการใช้ ModelInterpreter ไปยัง TensorFlow Lite Interpreter

1. อัปเดตทรัพยากร Dependency ของโปรเจ็กต์

อัปเดต Podfile ของโปรเจ็กต์ให้รวมเวอร์ชัน 0.20.0 ไลบรารี Firebase/MLModelInterpreter (หรือใหม่กว่า) และ TensorFlow Lite คลัง:

ก่อน

Swift

pod 'Firebase/MLModelInterpreter', '0.19.0'

Objective-C

pod 'Firebase/MLModelInterpreter', '0.19.0'

หลัง

Swift

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

Objective-C

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

2. สร้างอินเทอร์พรีเตอร์ของ TensorFlow Lite แทนโมเดลโมเดลล่ามของ Firebase

รับตำแหน่งที่ตั้งของโมเดลใน แทนการสร้าง ModelInterpreter ใน Firebase ที่มี getLatestModelFilePath() และใช้เพื่อสร้าง TensorFlow Lite Interpreter

ก่อน

Swift

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

Objective-C

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

หลัง

Swift

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

Objective-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. อัปเดตโค้ดการเตรียมอินพุตและเอาต์พุต

เมื่อใช้ ModelInterpreter คุณจะระบุรูปร่างอินพุตและเอาต์พุตของโมเดลได้ โดยการส่งออบเจ็กต์ ModelInputOutputOptions ไปยังอินเทอร์พรีเตอร์เมื่อคุณเรียกใช้ ได้

สำหรับอินเทอร์พรีเตอร์ของ TensorFlow Lite คุณจะต้องเรียกใช้ allocateTensors() เพื่อ จัดสรรพื้นที่สำหรับอินพุตและเอาต์พุตของโมเดล จากนั้นคัดลอกข้อมูลอินพุตไปยัง Tensor อินพุต

เช่น หากโมเดลมีรูปร่างอินพุตเป็น [1 224 224 3] ค่า float และรูปร่างเอาต์พุตที่มีค่าเป็น [1 1000] float ให้ทำการเปลี่ยนแปลงต่อไปนี้

ก่อน

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

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

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

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

หลัง

Swift

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

Objective-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. อัปเดตโค้ดการจัดการเอาต์พุต

สุดท้ายนี้ แทนที่จะได้รับเอาต์พุตของโมเดลด้วยออบเจ็กต์ ModelOutputs output() รับ Tensor เอาต์พุตจากล่ามและแปลง ข้อมูลเป็นโครงสร้างที่สะดวกสำหรับกรณีการใช้งานของคุณ

ตัวอย่างเช่น ถ้าคุณกำลังแยกประเภท คุณอาจทำการเปลี่ยนแปลง ดังต่อไปนี้:

ก่อน

Swift

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

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

หลัง

Swift

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

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