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

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

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

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

โมเดล TensorFlow Lite

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

ก่อนเริ่มต้น

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

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

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

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

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

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

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

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

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

คุณเลือกลักษณะการดาวน์โหลดได้ 3 แบบ ดังนี้

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

คุณควรปิดใช้ฟังก์ชันที่เกี่ยวข้องกับโมเดล เช่น ทำให้เป็นสีเทาหรือซ่อนส่วนหนึ่งของ 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 รับอาร์เรย์หลายมิติอย่างน้อย 1 รายการเป็นอินพุตและสร้างเป็นเอาต์พุต อาร์เรย์เหล่านี้มีค่า 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 จะจัดเก็บโมเดลในรูปแบบ protobuf ที่ซีเรียลไลซ์มาตรฐานในที่เก็บข้อมูลในเครื่อง

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