เวอร์ชัน 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]);
}