การใช้หน่วยประมวลผลกราฟิก (GPU) เพื่อเรียกใช้โมเดลแมชชีนเลิร์นนิง (ML) ของคุณสามารถปรับปรุงประสิทธิภาพของโมเดลของคุณและประสบการณ์ผู้ใช้ของแอปพลิเคชันที่เปิดใช้งาน ML ได้อย่างมาก บนอุปกรณ์ iOS คุณสามารถเปิดใช้งานการใช้โมเดลของคุณที่เร่งด้วย GPU ได้โดยใช้ ผู้รับมอบสิทธิ์ . ผู้รับมอบสิทธิ์ทำหน้าที่เป็นไดรเวอร์ฮาร์ดแวร์สำหรับ TensorFlow Lite ซึ่งช่วยให้คุณเรียกใช้โค้ดของรุ่นของคุณบนโปรเซสเซอร์ GPU ได้
หน้านี้อธิบายวิธีเปิดใช้งานการเร่งความเร็ว GPU สำหรับรุ่น TensorFlow Lite ในแอป iOS สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ผู้แทน GPU สำหรับ TensorFlow Lite รวมถึงแนวทางปฏิบัติที่ดีที่สุดและเทคนิคขั้นสูง โปรดดูที่หน้า ผู้แทน GPU
ใช้ GPU กับ Interpreter API
TensorFlow Lite Interpreter API จัดเตรียมชุด API สำหรับใช้งานทั่วไปสำหรับการสร้างแอปพลิเคชันการเรียนรู้ของเครื่อง คำแนะนำต่อไปนี้จะแนะนำคุณเกี่ยวกับการเพิ่มการรองรับ GPU ให้กับแอป iOS คู่มือนี้อนุมานว่าคุณมีแอป iOS ที่สามารถเรียกใช้โมเดล ML ด้วย TensorFlow Lite ได้สำเร็จ
แก้ไข Podfile เพื่อรวมการรองรับ GPU
เริ่มตั้งแต่ TensorFlow Lite 2.3.0 เป็นต้นไป ตัวแทน GPU จะถูกแยกออกจากพ็อดเพื่อลดขนาดไบนารี คุณสามารถรวมได้โดยการระบุข้อกำหนดย่อยสำหรับพ็อด TensorFlowLiteSwift
:
pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',
หรือ
pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']
คุณยังสามารถใช้ TensorFlowLiteObjC
หรือ TensorFlowLiteC
หากต้องการใช้ Objective-C ซึ่งมีให้สำหรับเวอร์ชัน 2.4.0 ขึ้นไป หรือ C API
เริ่มต้นและใช้ผู้รับมอบสิทธิ์ GPU
คุณสามารถใช้ผู้แทน GPU กับ TensorFlow Lite Interpreter API กับภาษาโปรแกรมได้หลายภาษา แนะนำให้ใช้ Swift และ Objective-C แต่คุณยังสามารถใช้ C++ และ C ได้ จำเป็นต้องใช้ C หากคุณใช้ TensorFlow Lite เวอร์ชันก่อนหน้า 2.4 ตัวอย่างโค้ดต่อไปนี้จะสรุปวิธีใช้ผู้รับมอบสิทธิ์กับแต่ละภาษาเหล่านี้
Swift
import TensorFlowLite // Load model ... // Initialize TensorFlow Lite interpreter with the GPU delegate. let delegate = MetalDelegate() if let interpreter = try Interpreter(modelPath: modelPath, delegates: [delegate]) { // Run inference ... }
วัตถุประสงค์-C
// Import module when using CocoaPods with module support @import TFLTensorFlowLite; // Or import following headers manually #import "tensorflow/lite/objc/apis/TFLMetalDelegate.h" #import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h" // Initialize GPU delegate TFLMetalDelegate* metalDelegate = [[TFLMetalDelegate alloc] init]; // Initialize interpreter with model path and GPU delegate TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init]; NSError* error = nil; TFLInterpreter* interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath options:options delegates:@[ metalDelegate ] error:&error]; if (error != nil) { /* Error handling... */ } if (![interpreter allocateTensorsWithError:&error]) { /* Error handling... */ } if (error != nil) { /* Error handling... */ } // Run inference ...
C++
// Set up interpreter. auto model = FlatBufferModel::BuildFromFile(model_path); if (!model) return false; tflite::ops::builtin::BuiltinOpResolver op_resolver; std::unique_ptr<Interpreter> interpreter; InterpreterBuilder(*model, op_resolver)(&interpreter); // Prepare GPU delegate. auto* delegate = TFLGpuDelegateCreate(/*default options=*/nullptr); if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false; // Run inference. WriteToInputTensor(interpreter->typed_input_tensor<float>(0)); if (interpreter->Invoke() != kTfLiteOk) return false; ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0)); // Clean up. TFLGpuDelegateDelete(delegate);
ค (ก่อน 2.4.0)
#include "tensorflow/lite/c/c_api.h" #include "tensorflow/lite/delegates/gpu/metal_delegate.h" // Initialize model TfLiteModel* model = TfLiteModelCreateFromFile(model_path); // Initialize interpreter with GPU delegate TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate(); TfLiteDelegate* delegate = TFLGPUDelegateCreate(nil); // default config TfLiteInterpreterOptionsAddDelegate(options, metal_delegate); TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options); TfLiteInterpreterOptionsDelete(options); TfLiteInterpreterAllocateTensors(interpreter); NSMutableData *input_data = [NSMutableData dataWithLength:input_size * sizeof(float)]; NSMutableData *output_data = [NSMutableData dataWithLength:output_size * sizeof(float)]; TfLiteTensor* input = TfLiteInterpreterGetInputTensor(interpreter, 0); const TfLiteTensor* output = TfLiteInterpreterGetOutputTensor(interpreter, 0); // Run inference TfLiteTensorCopyFromBuffer(input, inputData.bytes, inputData.length); TfLiteInterpreterInvoke(interpreter); TfLiteTensorCopyToBuffer(output, outputData.mutableBytes, outputData.length); // Clean up TfLiteInterpreterDelete(interpreter); TFLGpuDelegateDelete(metal_delegate); TfLiteModelDelete(model);
บันทึกการใช้ภาษา GPU API
- TensorFlow Lite เวอร์ชันก่อน 2.4.0 สามารถใช้ C API สำหรับ Objective-C เท่านั้น
- C++ API ใช้ได้เฉพาะเมื่อคุณใช้ bazel หรือสร้าง TensorFlow Lite ด้วยตัวเอง ไม่สามารถใช้ C++ API กับ CocoaPods
- เมื่อใช้ TensorFlow Lite กับผู้แทน GPU ด้วย C++ ให้รับผู้แทน GPU ผ่าน
TFLGpuDelegateCreate()
แล้วส่งต่อไปยังInterpreter::ModifyGraphWithDelegate()
แทนที่จะเรียกInterpreter::AllocateTensors()
สร้างและทดสอบด้วยโหมดปล่อย
เปลี่ยนเป็นบิลด์รีลีสด้วยการตั้งค่าตัวเร่ง Metal API ที่เหมาะสม เพื่อให้ได้ประสิทธิภาพที่ดีขึ้นและสำหรับการทดสอบขั้นสุดท้าย ส่วนนี้อธิบายวิธีเปิดใช้งานการสร้างรุ่นและกำหนดการตั้งค่าสำหรับการเร่งความเร็วด้วยโลหะ
ในการเปลี่ยนเป็นบิลด์รีลีส:
- แก้ไขการตั้งค่าบิลด์โดยเลือก Product > Scheme > Edit Scheme... จากนั้นเลือก Run
- บนแท็บ ข้อมูล เปลี่ยน Build Configuration เป็น Release และยกเลิกการเลือก Debug executable
- คลิกแท็บ ตัวเลือก และเปลี่ยน GPU Frame Capture เป็น Disabled และ Metal API Validation เป็น Disabled
- ตรวจสอบให้แน่ใจว่าได้เลือกรุ่นเฉพาะรุ่นบนสถาปัตยกรรม 64 บิต ภายใต้ Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings ตั้งค่า Build Active Architecture Only > Release เป็น Yes
รองรับ GPU ขั้นสูง
ส่วนนี้ครอบคลุมการใช้งานขั้นสูงของผู้รับมอบสิทธิ์ GPU สำหรับ iOS รวมถึงตัวเลือกผู้รับมอบสิทธิ์ บัฟเฟอร์อินพุตและเอาต์พุต และการใช้แบบจำลองเชิงปริมาณ
ตัวเลือกผู้รับมอบสิทธิ์สำหรับ iOS
ตัวสร้างสำหรับผู้รับมอบสิทธิ์ struct
ยอมรับโครงสร้างของตัวเลือกใน Swift API , Objective-C API และ C API การส่งผ่าน nullptr
(C API) หรือไม่มีเลย (Objective-C และ Swift API) ไปยังตัวเริ่มต้นจะตั้งค่าตัวเลือกเริ่มต้น (ซึ่งอธิบายไว้ในตัวอย่างการใช้งานพื้นฐานด้านบน)
Swift
// THIS: var options = MetalDelegate.Options() options.isPrecisionLossAllowed = false options.waitType = .passive options.isQuantizationEnabled = true let delegate = MetalDelegate(options: options) // IS THE SAME AS THIS: let delegate = MetalDelegate()
วัตถุประสงค์-C
// THIS: TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init]; options.precisionLossAllowed = false; options.waitType = TFLMetalDelegateThreadWaitTypePassive; options.quantizationEnabled = true; TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] initWithOptions:options]; // IS THE SAME AS THIS: TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] init];
ค
// THIS: const TFLGpuDelegateOptions options = { .allow_precision_loss = false, .wait_type = TFLGpuDelegateWaitType::TFLGpuDelegateWaitTypePassive, .enable_quantization = true, }; TfLiteDelegate* delegate = TFLGpuDelegateCreate(options); // IS THE SAME AS THIS: TfLiteDelegate* delegate = TFLGpuDelegateCreate(nullptr);
บัฟเฟอร์อินพุต/เอาต์พุตโดยใช้ C++ API
การคำนวณบน GPU กำหนดให้มีข้อมูลอยู่ใน GPU ข้อกำหนดนี้มักจะหมายความว่าคุณต้องทำสำเนาหน่วยความจำ คุณควรหลีกเลี่ยงไม่ให้ข้อมูลของคุณข้ามขอบเขตหน่วยความจำ CPU/GPU หากเป็นไปได้ เนื่องจากอาจใช้เวลานานพอสมควร โดยปกติการข้ามดังกล่าวเป็นสิ่งที่หลีกเลี่ยงไม่ได้ แต่ในบางกรณีสามารถละเว้นได้
หากอินพุตของเครือข่ายเป็นภาพที่โหลดไว้แล้วในหน่วยความจำ GPU (เช่น พื้นผิว GPU ที่มีฟีดกล้อง) ข้อมูลดังกล่าวจะอยู่ในหน่วยความจำ GPU โดยไม่ต้องป้อนหน่วยความจำของ CPU ในทำนองเดียวกัน หากเอาต์พุตของเครือข่ายอยู่ในรูปของภาพที่แสดงผลได้ เช่น การดำเนินการ ถ่ายโอนรูปแบบรูปภาพ คุณสามารถแสดงผลบนหน้าจอได้โดยตรง
เพื่อให้ได้ประสิทธิภาพที่ดีที่สุด TensorFlow Lite ทำให้ผู้ใช้สามารถอ่านและเขียนโดยตรงไปยังบัฟเฟอร์ฮาร์ดแวร์ TensorFlow และเลี่ยงผ่านสำเนาหน่วยความจำที่หลีกเลี่ยงได้
สมมติว่าอินพุตรูปภาพอยู่ในหน่วยความจำ GPU คุณต้องแปลงเป็นวัตถุ MTLBuffer
สำหรับ Metal ก่อน คุณสามารถเชื่อมโยง TfLiteTensor
กับ MTLBuffer ที่ผู้ใช้เตรียมไว้ด้วยฟังก์ชัน MTLBuffer
TFLGpuDelegateBindMetalBufferToTensor()
โปรดทราบว่า จะต้อง เรียกใช้ฟังก์ชันนี้หลังจาก Interpreter::ModifyGraphWithDelegate()
นอกจากนี้ ตามค่าเริ่มต้น เอาต์พุตการอนุมานจะถูกคัดลอกจากหน่วยความจำ GPU ไปยังหน่วยความจำ CPU คุณสามารถปิดการทำงานนี้ได้โดยการเรียก Interpreter::SetAllowBufferHandleOutput(true)
ระหว่างการเริ่มต้น
C++
#include "tensorflow/lite/delegates/gpu/metal_delegate.h" #include "tensorflow/lite/delegates/gpu/metal_delegate_internal.h" // ... // Prepare GPU delegate. auto* delegate = TFLGpuDelegateCreate(nullptr); if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false; interpreter->SetAllowBufferHandleOutput(true); // disable default gpu->cpu copy if (!TFLGpuDelegateBindMetalBufferToTensor( delegate, interpreter->inputs()[0], user_provided_input_buffer)) { return false; } if (!TFLGpuDelegateBindMetalBufferToTensor( delegate, interpreter->outputs()[0], user_provided_output_buffer)) { return false; } // Run inference. if (interpreter->Invoke() != kTfLiteOk) return false;
เมื่อปิดการทำงานเริ่มต้น การคัดลอกเอาต์พุตการอนุมานจากหน่วยความจำ GPU ไปยังหน่วยความจำ CPU จำเป็นต้องมีการเรียก Interpreter::EnsureTensorDataIsReadable()
อย่างชัดเจนสำหรับเอาต์พุตเทนเซอร์แต่ละตัว วิธีการนี้ยังใช้ได้กับโมเดลเชิงปริมาณ แต่คุณยังคงต้องใช้ บัฟเฟอร์ขนาด float32 ที่มีข้อมูล float32 เนื่องจากบัฟเฟอร์ถูกผูกไว้กับบัฟเฟอร์ de-quantized ภายใน
โมเดลเชิงปริมาณ
ไลบรารีผู้รับมอบสิทธิ์ GPU iOS รองรับโมเดลเชิงปริมาณโดยค่าเริ่มต้น คุณไม่จำเป็นต้องทำการเปลี่ยนแปลงโค้ดใดๆ เพื่อใช้โมเดลเชิงปริมาณกับผู้รับมอบสิทธิ์ GPU ส่วนต่อไปนี้จะอธิบายวิธีปิดใช้งานการสนับสนุนเชิงปริมาณสำหรับวัตถุประสงค์ในการทดสอบหรือการทดลอง
ปิดใช้งานการสนับสนุนโมเดลเชิงปริมาณ
รหัสต่อไปนี้แสดงวิธี ปิดใช้งาน การสนับสนุนสำหรับโมเดลเชิงปริมาณ
Swift
var options = MetalDelegate.Options() options.isQuantizationEnabled = false let delegate = MetalDelegate(options: options)
วัตถุประสงค์-C
TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init]; options.quantizationEnabled = false;
ค
TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault(); options.enable_quantization = false; TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเรียกใช้โมเดลเชิงปริมาณด้วยการเร่งความเร็ว GPU โปรดดูที่ภาพรวมการ มอบสิทธิ์ GPU