Di chuyển từ API mô hình tùy chỉnh cũ

Phiên bản 0.20.0 của thư viện Firebase/MLModelInterpreter giới thiệu phương thức getLatestModelFilePath() mới, phương thức này lấy vị trí trên thiết bị của các kiểu máy tùy chỉnh. Bạn có thể sử dụng phương pháp này để khởi tạo trực tiếp một đối tượng TensorFlow Lite Interpreter mà bạn có thể sử dụng thay cho trình bao bọc ModelInterpreter của Firebase.

Trong tương lai, đây là cách tiếp cận ưa thích. Vì phiên bản trình thông dịch TensorFlow Lite không còn được kết hợp với phiên bản thư viện Firebase nên bạn có thể linh hoạt hơn trong việc nâng cấp lên phiên bản mới của TensorFlow Lite khi muốn hoặc dễ dàng sử dụng các bản dựng TensorFlow Lite tùy chỉnh hơn.

Trang này hiển thị cách bạn có thể di chuyển từ việc sử dụng ModelInterpreter sang Interpreter TensorFlow Lite.

1. Cập nhật các phần phụ thuộc của dự án

Cập nhật Podfile của dự án của bạn để bao gồm phiên bản 0.20.0 của thư viện Firebase/MLModelInterpreter (hoặc mới hơn) và thư viện TensorFlow Lite:

Trước

Nhanh

pod 'Firebase/MLModelInterpreter', '0.19.0'

Mục tiêu-C

pod 'Firebase/MLModelInterpreter', '0.19.0'

Sau đó

Nhanh

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

Mục tiêu-C

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

2. Tạo trình thông dịch TensorFlow Lite thay vì Trình thông dịch mô hình Firebase

Thay vì tạo Firebase ModelInterpreter , hãy lấy vị trí của mô hình trên thiết bị bằng getLatestModelFilePath() và sử dụng nó để tạo TensorFlow Lite Interpreter .

Trước

Nhanh

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

Mục tiêu-C

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

Sau đó

Nhanh

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

Mục tiêu-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. Cập nhật mã chuẩn bị đầu vào và đầu ra

Với ModelInterpreter , bạn chỉ định hình dạng đầu vào và đầu ra của mô hình bằng cách chuyển đối tượng ModelInputOutputOptions cho trình thông dịch khi bạn chạy nó.

Đối với trình thông dịch TensorFlow Lite, thay vào đó, bạn hãy gọi allocateTensors() để phân bổ không gian cho đầu vào và đầu ra của mô hình, sau đó sao chép dữ liệu đầu vào của bạn vào các tensor đầu vào.

Ví dụ: nếu mô hình của bạn có hình dạng đầu vào là các giá trị float [1 224 224 3] và hình dạng đầu ra là các giá trị float [1 1000], hãy thực hiện những thay đổi sau:

Trước

Nhanh

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

Mục tiêu-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
  // ...
}];

Sau đó

Nhanh

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

Mục tiêu-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. Cập nhật mã xử lý đầu ra

Cuối cùng, thay vì lấy đầu ra của mô hình bằng phương thức output() của đối tượng ModelOutputs , hãy lấy tensor đầu ra từ trình thông dịch và chuyển đổi dữ liệu của nó sang bất kỳ cấu trúc nào thuận tiện cho trường hợp sử dụng của bạn.

Ví dụ: nếu bạn đang thực hiện phân loại, bạn có thể thực hiện các thay đổi như sau:

Trước

Nhanh

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

Mục tiêu-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);
}

Sau đó

Nhanh

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

Mục tiêu-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]);
}