ใช้โมเดล 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 เพื่อใช้งาน

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

1. ทำให้โมเดลใช้งานได้

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

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

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

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

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

คุณเลือกพฤติกรรมการดาวน์โหลดได้ 3 แบบดังนี้

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

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

Swift

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 เพื่อตรวจสอบโมเดล เช่น

Python

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] ค่า คุณอาจต้องปรับขนาด ค่าสีของรูปภาพเป็นช่วงจุดลอยตัวในตัวอย่างต่อไปนี้

Swift

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 ไปยังล่ามแล้วเรียกใช้ดังนี้

Swift

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

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

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

Swift

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 จะจัดเก็บเนื้อหาในรูปแบบ Protocolbuf แบบอนุกรมมาตรฐานใน ที่จัดเก็บข้อมูลในตัวเครื่อง

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