ใช้โมเดล TensorFlow Lite แบบกำหนดเองบนแพลตฟอร์ม Apple

หากแอปของคุณใช้โมเดล TensorFlow Lite ที่กำหนดเอง คุณสามารถใช้ Firebase ML เพื่อปรับใช้โมเดลของคุณได้ เมื่อปรับใช้โมเดลกับ Firebase คุณจะลดขนาดการดาวน์โหลดเริ่มต้นของแอปและอัปเดตโมเดล ML ของแอปได้โดยไม่ต้องเปิดตัวแอปเวอร์ชันใหม่ และด้วยการกำหนดค่าระยะไกลและการทดสอบ A/B คุณสามารถให้บริการโมเดลต่างๆ แก่ผู้ใช้กลุ่มต่างๆ แบบไดนามิกได้

ข้อกำหนดเบื้องต้น

  • ไลบรารี MLModelDownloader ใช้งานได้กับ Swift เท่านั้น
  • TensorFlow Lite ทำงานบนอุปกรณ์ที่ใช้ iOS 9 และใหม่กว่าเท่านั้น

รุ่น TensorFlow Lite

รุ่น TensorFlow Lite คือรุ่น ML ที่ได้รับการปรับแต่งให้ทำงานบนอุปกรณ์เคลื่อนที่ วิธีรับโมเดล TensorFlow Lite:

ก่อนที่คุณจะเริ่ม

หากต้องการใช้ TensorFlowLite กับ Firebase คุณต้องใช้ CocoaPods เนื่องจากปัจจุบัน TensorFlowLite ไม่รองรับการติดตั้งด้วย Swift Package Manager ดู คู่มือการติดตั้ง CocoaPods สำหรับคำแนะนำเกี่ยวกับวิธีการติดตั้ง MLModelDownloader

เมื่อติดตั้งแล้ว ให้นำเข้า Firebase และ TensorFlowLite เพื่อใช้งาน

สวิฟท์

import FirebaseMLModelDownloader
import TensorFlowLite

1. ปรับใช้โมเดลของคุณ

ปรับใช้โมเดล TensorFlow ที่กำหนดเองของคุณโดยใช้คอนโซล Firebase หรือ Firebase Admin Python และ Node.js SDK ดู ปรับใช้และจัดการโมเดลแบบกำหนดเอง

หลังจากที่คุณเพิ่มโมเดลที่กำหนดเองลงในโปรเจ็กต์ Firebase แล้ว คุณจะอ้างอิงโมเดลในแอปได้โดยใช้ชื่อที่คุณระบุ คุณสามารถปรับใช้โมเดล TensorFlow Lite ใหม่และดาวน์โหลดโมเดลใหม่ลงในอุปกรณ์ของผู้ใช้ได้ทุกเมื่อโดยเรียก getModel() (ดูด้านล่าง)

2. ดาวน์โหลดโมเดลลงในอุปกรณ์และเริ่มต้นล่าม TensorFlow Lite

หากต้องการใช้โมเดล TensorFlow Lite ในแอป ขั้นแรกให้ใช้ Firebase ML SDK เพื่อดาวน์โหลดเวอร์ชันล่าสุดของโมเดลลงในอุปกรณ์

หากต้องการเริ่มการดาวน์โหลดโมเดล ให้เรียกเมธอด getModel() ของผู้ดาวน์โหลดโมเดล โดยระบุชื่อที่คุณกำหนดให้กับโมเดลเมื่อคุณอัปโหลด ไม่ว่าคุณต้องการดาวน์โหลดโมเดลล่าสุดเสมอหรือไม่ และเงื่อนไขที่คุณต้องการอนุญาตให้ดาวน์โหลด

คุณสามารถเลือกลักษณะการดาวน์โหลดได้สามแบบ:

ประเภทการดาวน์โหลด คำอธิบาย
localModel รับโมเดลท้องถิ่นจากอุปกรณ์ หากไม่มีรุ่นท้องถิ่น สิ่งนี้จะทำงานเหมือน latestModel ใช้ประเภทการดาวน์โหลดนี้หากคุณไม่สนใจที่จะตรวจสอบการอัพเดตโมเดล ตัวอย่างเช่น คุณกำลังใช้การกำหนดค่าระยะไกลเพื่อเรียกชื่อโมเดล และคุณจะอัปโหลดโมเดลภายใต้ชื่อใหม่เสมอ (แนะนำ)
localModelUpdateInBackground รับโมเดลในเครื่องจากอุปกรณ์ และเริ่มอัปเดตโมเดลในเบื้องหลัง หากไม่มีรุ่นท้องถิ่น สิ่งนี้จะทำงานเหมือน latestModel
latestModel รับรุ่นใหม่ล่าสุด หากโมเดลโลคัลเป็นเวอร์ชันล่าสุด ให้ส่งคืนโมเดลโลคัล มิฉะนั้น ให้ดาวน์โหลดเวอร์ชันล่าสุด ลักษณะการทำงานนี้จะบล็อกจนกว่าจะดาวน์โหลดเวอร์ชันล่าสุด (ไม่แนะนำ) ใช้ลักษณะการทำงานนี้เฉพาะในกรณีที่คุณต้องการเวอร์ชันล่าสุดอย่างชัดเจน

คุณควรปิดการใช้งานฟังก์ชันที่เกี่ยวข้องกับโมเดล เช่น ทำให้เป็นสีเทาหรือซ่อนบางส่วนของ UI จนกว่าคุณจะยืนยันว่าดาวน์โหลดโมเดลแล้ว

สวิฟท์

let conditions = ModelDownloadConditions(allowsCellularAccess: false)
ModelDownloader.modelDownloader()
    .getModel(name: "your_model",
              downloadType: .localModelUpdateInBackground,
              conditions: conditions) { result in
        switch (result) {
        case .success(let customModel):
            do {
                // Download complete. Depending on your app, you could enable the ML
                // feature, or switch from the local model to the remote model, etc.

                // The CustomModel object contains the local path of the model file,
                // which you can use to instantiate a TensorFlow Lite interpreter.
                let interpreter = try Interpreter(modelPath: customModel.path)
            } catch {
                // Error. Bad model file?
            }
        case .failure(let error):
            // Download was unsuccessful. Don't enable ML features.
            print(error)
        }
}

แอพจำนวนมากเริ่มงานดาวน์โหลดด้วยโค้ดเริ่มต้น แต่คุณสามารถทำได้ทุกเมื่อก่อนจำเป็นต้องใช้โมเดล

3. ทำการอนุมานข้อมูลอินพุต

รับรูปร่างอินพุตและเอาท์พุตของโมเดลของคุณ

ล่ามโมเดล TensorFlow Lite ใช้เป็นอินพุตและสร้างเป็นเอาต์พุตอาร์เรย์หลายมิติอย่างน้อยหนึ่งรายการ อาร์เรย์เหล่านี้มีค่า byte , int , long หรือ float ก่อนที่คุณจะสามารถส่งข้อมูลไปยังโมเดลหรือใช้ผลลัพธ์ได้ คุณต้องทราบจำนวนและขนาด ("รูปร่าง") ของอาร์เรย์ที่โมเดลของคุณใช้

หากคุณสร้างโมเดลด้วยตัวเอง หรือหากรูปแบบอินพุตและเอาท์พุตของโมเดลได้รับการบันทึกไว้ คุณอาจมีข้อมูลนี้อยู่แล้ว หากคุณไม่ทราบรูปร่างและประเภทข้อมูลของอินพุตและเอาต์พุตของโมเดล คุณสามารถใช้ล่าม TensorFlow Lite เพื่อตรวจสอบโมเดลของคุณได้ ตัวอย่างเช่น:

หลาม

import tensorflow as tf

interpreter = tf.lite.Interpreter(model_path="your_model.tflite")
interpreter.allocate_tensors()

# Print input shape and type
inputs = interpreter.get_input_details()
print('{} input(s):'.format(len(inputs)))
for i in range(0, len(inputs)):
    print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype']))

# Print output shape and type
outputs = interpreter.get_output_details()
print('\n{} output(s):'.format(len(outputs)))
for i in range(0, len(outputs)):
    print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))

ตัวอย่างผลลัพธ์:

1 input(s):
[  1 224 224   3] <class 'numpy.float32'>

1 output(s):
[1 1000] <class 'numpy.float32'>

เรียกใช้ล่าม

หลังจากที่คุณกำหนดรูปแบบของอินพุตและเอาต์พุตของโมเดลของคุณแล้ว ให้รับข้อมูลอินพุตของคุณและดำเนินการแปลงข้อมูลที่จำเป็นเพื่อให้ได้อินพุตที่มีรูปทรงที่เหมาะสมสำหรับโมเดลของคุณ

ตัวอย่างเช่น หากโมเดลของคุณประมวลผลรูปภาพ และโมเดลของคุณมีขนาดอินพุตเป็นค่าจุดลอยตัว [1, 224, 224, 3] คุณอาจต้องปรับขนาดค่าสีของรูปภาพเป็นช่วงจุดลอยตัวตามตัวอย่างต่อไปนี้ : :

สวิฟท์

let image: CGImage = // Your input image
guard let context = CGContext(
  data: nil,
  width: image.width, height: image.height,
  bitsPerComponent: 8, bytesPerRow: image.width * 4,
  space: CGColorSpaceCreateDeviceRGB(),
  bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
) else {
  return false
}

context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
guard let imageData = context.data else { return false }

var inputData = Data()
for row in 0 ..&lt; 224 {
  for col in 0 ..&lt; 224 {
    let offset = 4 * (row * context.width + col)
    // (Ignore offset 0, the unused alpha channel)
    let red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
    let green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
    let blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)

    // Normalize channel values to [0.0, 1.0]. This requirement varies
    // by model. For example, some models might require values to be
    // normalized to the range [-1.0, 1.0] instead, and others might
    // require fixed-point values or the original bytes.
    var normalizedRed = Float32(red) / 255.0
    var normalizedGreen = Float32(green) / 255.0
    var normalizedBlue = Float32(blue) / 255.0

    // Append normalized values to Data object in RGB order.
    let elementSize = MemoryLayout.size(ofValue: normalizedRed)
    var bytes = [UInt8](repeating: 0, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedRed, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&amp;bytes, &amp;normalizedGreen, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
    memcpy(&ammp;bytes, &amp;normalizedBlue, elementSize)
    inputData.append(&amp;bytes, count: elementSize)
  }
}

จากนั้นคัดลอกอินพุต NSData ของคุณไปยังล่ามแล้วรัน:

สวิฟท์

try interpreter.allocateTensors()
try interpreter.copy(inputData, toInputAt: 0)
try interpreter.invoke()

คุณสามารถรับเอาต์พุตของโมเดลได้โดยการเรียกเมธอด output(at:) วิธีที่คุณใช้เอาต์พุตจะขึ้นอยู่กับรุ่นที่คุณใช้

ตัวอย่างเช่น หากคุณกำลังดำเนินการจัดหมวดหมู่ ในขั้นตอนถัดไป คุณอาจจับคู่ดัชนีของผลลัพธ์กับป้ายกำกับที่เป็นตัวแทน:

สวิฟท์

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: "retrained_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])")
}

ภาคผนวก: ความปลอดภัยของโมเดล

ไม่ว่าคุณจะทำให้โมเดล TensorFlow Lite พร้อมใช้งานกับ Firebase ML ได้อย่างไร Firebase ML จะจัดเก็บโมเดลเหล่านั้นในรูปแบบ protobuf ที่เป็นอนุกรมมาตรฐานในพื้นที่จัดเก็บในเครื่อง

ตามทฤษฎีแล้ว นี่หมายความว่าใครๆ ก็สามารถคัดลอกโมเดลของคุณได้ อย่างไรก็ตาม ในทางปฏิบัติ โมเดลส่วนใหญ่จะมีความเฉพาะเจาะจงกับแอปพลิเคชันมากและถูกทำให้สับสนด้วยการปรับให้เหมาะสมให้เหมาะสม ซึ่งมีความเสี่ยงใกล้เคียงกับความเสี่ยงที่คู่แข่งจะแยกส่วนและนำโค้ดของคุณกลับมาใช้ใหม่ อย่างไรก็ตาม คุณควรตระหนักถึงความเสี่ยงนี้ก่อนที่จะใช้โมเดลที่กำหนดเองในแอปของคุณ