يقدّم الإصدار 0.20.0 من مكتبة Firebase/MLModelInterpreter طريقة getLatestModelFilePath() جديدة تحصل على موقع النماذج المخصّصة على الجهاز. يمكنك استخدام هذه الطريقة لإنشاء كائن TensorFlow Lite
Interpreter مباشرةً، ويمكنك استخدامه بدلاً من برنامج التغليف ModelInterpreter
من Firebase.
من الآن فصاعدًا، هذا هو النهج المفضّل. بما أنّ إصدار برنامج تفسير TensorFlow Lite لم يعُد مرتبطًا بإصدار مكتبة Firebase، يمكنك الترقية إلى إصدارات جديدة من TensorFlow Lite متى أردت، أو استخدام إصدارات مخصّصة من TensorFlow Lite بسهولة أكبر.
تعرض هذه الصفحة كيفية الانتقال من استخدام ModelInterpreter إلى
TensorFlow Lite Interpreter.
1. تعديل تبعيات المشروع
عدِّل ملف 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 بدلاً من ModelInterpreter من Firebase
بدلاً من إنشاء ModelInterpreter من Firebase، احصل على موقع النموذج على
الجهاز باستخدام getLatestModelFilePath() واستخدِمه لإنشاء Interpreter من TensorFlow Lite.
قبل
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() لتخصيص مساحة لإدخال النموذج وإخراجه، ثم نسخ بيانات الإدخال إلى موترات الإدخال.
على سبيل المثال، إذا كان للنموذج شكل إدخال من قيم float يبلغ [1 224 224 3] وشكل إخراج من قيم float يبلغ [1 1000]، يمكنك إجراء هذه التغييرات:
قبل
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. تعديل رمز معالجة الإخراج
أخيرًا، بدلاً من الحصول على إخراج النموذج باستخدام طريقة output() الخاصة بكائن ModelOutputs، احصل على موتر الإخراج من برنامج التفسير وحوِّل بياناته إلى أي بنية مناسبة لحالة الاستخدام.
على سبيل المثال، إذا كنت تصنّف الصور، يمكنك إجراء تغييرات مثل ما يلي:
قبل
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]);
}