از API مدل سفارشی قدیمی مهاجرت کنید

نسخه 0.20.0 کتابخانه Firebase/MLModelInterpreter یک متد getLatestModelFilePath() جدید را معرفی می کند که مکان را در دستگاه مدل های سفارشی دریافت می کند. می‌توانید از این روش برای نمونه‌سازی مستقیم یک شی Interpreter TensorFlow Lite استفاده کنید، که می‌توانید به‌جای بسته‌بندی ModelInterpreter Firebase از آن استفاده کنید.

در آینده، این رویکرد ارجح است. از آنجایی که نسخه مفسر TensorFlow Lite دیگر با نسخه کتابخانه Firebase همراه نیست، انعطاف پذیری بیشتری برای ارتقاء به نسخه های جدید TensorFlow Lite در صورت تمایل دارید، یا آسان تر از ساخت های سفارشی TensorFlow Lite استفاده کنید.

این صفحه نشان می دهد که چگونه می توانید از ModelInterpreter به Interpreter TensorFlow Lite مهاجرت کنید.

1. وابستگی های پروژه را به روز کنید

فایل پادفایل پروژه خود را به‌روزرسانی کنید تا شامل نسخه 0.20.0 کتابخانه Firebase/MLModelInterpreter (یا جدیدتر) و کتابخانه 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() دریافت کنید و از آن برای ایجاد یک Interpreter TensorFlow Lite استفاده کنید.

قبل از

سویفت

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() فراخوانی کنید تا فضا را برای ورودی و خروجی مدل تخصیص دهد، سپس داده های ورودی خود را در تانسورهای ورودی کپی کنید.

برای مثال، اگر مدل شما دارای شکل ورودی [1 224 224 3] مقادیر float و شکل خروجی [1 1000] مقادیر float است، این تغییرات را انجام دهید:

قبل از

سویفت

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

نسخه 0.20.0 کتابخانه Firebase/MLModelInterpreter یک متد getLatestModelFilePath() جدید را معرفی می کند که مکان را در دستگاه مدل های سفارشی دریافت می کند. می‌توانید از این روش برای نمونه‌سازی مستقیم یک شی Interpreter TensorFlow Lite استفاده کنید، که می‌توانید به‌جای بسته‌بندی ModelInterpreter Firebase از آن استفاده کنید.

در آینده، این رویکرد ارجح است. از آنجایی که نسخه مفسر TensorFlow Lite دیگر با نسخه کتابخانه Firebase همراه نیست، انعطاف پذیری بیشتری برای ارتقاء به نسخه های جدید TensorFlow Lite در صورت تمایل دارید، یا آسان تر از ساخت های سفارشی TensorFlow Lite استفاده کنید.

این صفحه نشان می دهد که چگونه می توانید از ModelInterpreter به Interpreter TensorFlow Lite مهاجرت کنید.

1. وابستگی های پروژه را به روز کنید

فایل پادفایل پروژه خود را به‌روزرسانی کنید تا شامل نسخه 0.20.0 کتابخانه Firebase/MLModelInterpreter (یا جدیدتر) و کتابخانه 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() دریافت کنید و از آن برای ایجاد یک Interpreter TensorFlow Lite استفاده کنید.

قبل از

سویفت

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() فراخوانی کنید تا فضا را برای ورودی و خروجی مدل تخصیص دهد، سپس داده های ورودی خود را در تانسورهای ورودی کپی کنید.

برای مثال، اگر مدل شما دارای شکل ورودی [1 224 224 3] مقادیر float و شکل خروجی [1 1000] مقادیر float است، این تغییرات را انجام دهید:

قبل از

سویفت

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