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

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

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

หน้านี้แสดงวิธีที่คุณสามารถย้ายจากการใช้ ModelInterpreter ไปยัง TensorFlow Lite Interpreter

1. อัปเดตการพึ่งพาโครงการ

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

ก่อน

สวิฟท์

pod 'Firebase/MLModelInterpreter', '0.19.0'

วัตถุประสงค์-C

pod 'Firebase/MLModelInterpreter', '0.19.0'

หลังจาก

สวิฟท์

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

วัตถุประสงค์-C

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

2. สร้างล่าม TensorFlow Lite แทน Firebase ModelInterpreter

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

ก่อน

สวิฟท์

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

วัตถุประสงค์-C

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

หลังจาก

สวิฟท์

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

วัตถุประสงค์-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() แทนเพื่อจัดสรรพื้นที่สำหรับอินพุตและเอาต์พุตของโมเดล จากนั้นคัดลอกข้อมูลอินพุตของคุณไปยังเทนเซอร์อินพุต

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

ก่อน

สวิฟท์

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

วัตถุประสงค์-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
  // ...
}];

หลังจาก

สวิฟท์

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

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

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

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

ก่อน

สวิฟท์

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

วัตถุประสงค์-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);
}

หลังจาก

สวิฟท์

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

วัตถุประสงค์-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]);
}