Check out what’s new from Firebase at Google I/O 2022. Learn more

ใช้รุ่น 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 หรือ 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 ของคุณ จนกว่าคุณจะยืนยันว่าดาวน์โหลดโมเดลแล้ว

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

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