Sử dụng mô hình TensorFlow Lite tuỳ chỉnh trên các nền tảng của Apple

Nếu ứng dụng của bạn sử dụng TensorFlow Các mô hình phiên bản rút gọn, bạn có thể sử dụng công nghệ học máy của Firebase để triển khai mô hình. Theo triển khai các mô hình bằng Firebase, bạn có thể giảm kích thước tải xuống ban đầu của ứng dụng của bạn và cập nhật mô hình học máy của ứng dụng mà không cần phát hành phiên bản mới của ứng dụng của bạn. Đồng thời, với Cấu hình từ xa và Thử nghiệm A/B, bạn có thể linh hoạt sẽ phân phát các mô hình khác nhau đến các nhóm người dùng khác nhau.

Điều kiện tiên quyết

  • Thư viện MLModelDownloader chỉ dành cho Swift.
  • TensorFlow Lite chỉ chạy trên các thiết bị sử dụng iOS 9 trở lên.

Mô hình TensorFlow Lite

Các mô hình TensorFlow Lite là các mô hình học máy được tối ưu hoá để chạy trên thiết bị di động thiết bị. Cách tạo mô hình TensorFlow Lite:

Trước khi bắt đầu

Để sử dụng TensorFlowLite với Firebase, bạn phải sử dụng CocoaPods làm TensorFlowLite hiện không hỗ trợ cài đặt bằng Trình quản lý gói Swift. Xem Hướng dẫn cài đặt CocoaPods cho hướng dẫn về cách cài đặt MLModelDownloader.

Sau khi cài đặt, hãy nhập Firebase và TensorFlowLite để sử dụng.

Swift

import FirebaseMLModelDownloader
import TensorFlowLite

1. Triển khai mô hình

Triển khai các mô hình TensorFlow tuỳ chỉnh bằng bảng điều khiển của Firebase hoặc SDK Node.js và Python Admin của Firebase. Xem Triển khai và quản lý các mô hình tuỳ chỉnh.

Sau khi thêm mô hình tùy chỉnh vào dự án Firebase, bạn có thể tham khảo trong các ứng dụng của mình bằng tên mà bạn đã chỉ định. Bất cứ lúc nào, bạn đều có thể triển khai một mô hình TensorFlow Lite mới và tải mô hình mới xuống thiết bị của người dùng thiết bị của đang gọi getModel() (xem bên dưới).

2. Tải mô hình xuống thiết bị và khởi chạy trình thông dịch TensorFlow Lite

Để dùng mô hình TensorFlow Lite trong ứng dụng, trước tiên, hãy dùng SDK máy học Firebase để tải phiên bản mới nhất của mô hình xuống thiết bị.

Để bắt đầu tải mô hình xuống, hãy gọi phương thức getModel() của trình tải mô hình xuống, chỉ định tên mà bạn đã chỉ định cho mô hình khi tải lên, cho dù bạn muốn luôn tải xuống mô hình mới nhất và các điều kiện mà bạn muốn cho phép tải xuống.

Bạn có thể chọn một trong ba hành vi tải xuống sau:

Loại tệp tải xuống Mô tả
localModel Lấy mẫu cục bộ từ thiết bị. Nếu không có sẵn mô hình cục bộ, điều này hoạt động như latestModel. Sử dụng bản thảo này loại tệp tải xuống nếu bạn không quan tâm đến đang kiểm tra các bản cập nhật mô hình. Ví dụ: bạn đang sử dụng Cấu hình từ xa để truy xuất tên mô hình và bạn luôn tải lên mô hình dưới tên mới (được đề xuất).
localModelUpdateInBackground Lấy mô hình cục bộ từ thiết bị và bắt đầu cập nhật mô hình trong nền. Nếu không có sẵn mô hình cục bộ, điều này hoạt động như latestModel.
latestModel Tải mẫu mới nhất. Nếu mô hình cục bộ là phiên bản mới nhất, trả về mã model. Nếu không, hãy tải phiên bản mới nhất model. Hành vi này sẽ chặn cho đến khi phiên bản mới nhất đã được tải xuống (không phải khuyến nghị). Chỉ sử dụng hành vi này trong trong trường hợp bạn rõ ràng cần .

Bạn nên tắt chức năng liên quan đến mô hình (ví dụ: chuyển màu xám hoặc ẩn một phần giao diện người dùng cho đến khi bạn xác nhận mô hình đã được tải xuống.

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)
        }
}

Nhiều ứng dụng bắt đầu tác vụ tải xuống trong mã khởi chạy của ứng dụng, nhưng bạn có thể làm được vì vậy, tại bất kỳ thời điểm nào trước khi cần sử dụng mô hình này.

3. Tiến hành suy luận về dữ liệu đầu vào

Nhận các hình dạng đầu vào và đầu ra của mô hình

Trình phiên dịch mô hình TensorFlow Lite lấy dữ liệu đầu vào và tạo ra kết quả đầu ra một hoặc nhiều mảng đa chiều. Các mảng này chứa byte, int, long hoặc float giá trị. Trước khi có thể truyền dữ liệu vào mô hình hoặc sử dụng kết quả của mô hình đó, bạn phải biết số lượng và kích thước ("hình dạng") của các mảng mà mô hình của bạn sử dụng.

Nếu bạn tự xây dựng mô hình hoặc nếu định dạng đầu vào và đầu ra của mô hình là được ghi lại, bạn có thể đã có thông tin này. Nếu không biết hình dạng và kiểu dữ liệu của đầu vào và đầu ra của mô hình, bạn có thể sử dụng Trình thông dịch TensorFlow Lite để kiểm tra mô hình của bạn. Ví dụ:

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']))

Kết quả ví dụ:

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

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

Chạy trình phiên dịch

Sau khi xác định định dạng cho đầu vào và đầu ra của mô hình, hãy lấy và thực hiện các biến đổi đối với dữ liệu cần thiết để có được đầu vào có hình dạng phù hợp cho mô hình của bạn.

Ví dụ: nếu mô hình của bạn xử lý hình ảnh và mô hình có phương diện đầu vào [1, 224, 224, 3] giá trị dấu phẩy động, nên bạn có thể phải mở rộng quy mô các giá trị màu của hình ảnh thành một dải dấu phẩy động như trong ví dụ sau:

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)
  }
}

Sau đó, hãy sao chép NSData đã nhập vào trình phiên dịch và chạy lệnh đó:

Swift

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

Bạn có thể nhận kết quả của mô hình bằng cách gọi phương thức output(at:) của trình thông dịch. Cách bạn sử dụng dữ liệu đầu ra phụ thuộc vào mô hình bạn đang sử dụng.

Ví dụ: nếu bạn đang thực hiện phân loại, trong bước tiếp theo, bạn có thể ánh xạ chỉ mục của kết quả với nhãn mà chúng đại diện:

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

Phụ lục: Bảo mật mô hình

Bất kể bạn áp dụng mô hình TensorFlow Lite bằng cách nào Firebase ML, Firebase ML lưu trữ chúng ở định dạng protobuf được chuyển đổi tuần tự tiêu chuẩn trong lưu trữ cục bộ.

Về mặt lý thuyết, điều này có nghĩa là bất kỳ ai cũng có thể sao chép mô hình của bạn. Tuy nhiên, trong thực tế, hầu hết các mô hình đều dành riêng cho ứng dụng và bị làm rối mã nguồn rủi ro tương tự như các biện pháp tối ưu hoá của đối thủ cạnh tranh bị loại bỏ và việc sử dụng lại mã. Tuy nhiên, bạn nên lưu ý rủi ro này trước khi sử dụng một mô hình tuỳ chỉnh trong ứng dụng của bạn.