Sử dụng mô hình TensorFlow Lite tùy chỉnh trên nền tảng Apple

Nếu ứng dụng của bạn sử dụng mô hình TensorFlow Lite tùy chỉnh, bạn có thể sử dụng Firebase ML để triển khai mô hình của mình. Bằng cách triển khai các mô hình với Firebase, bạn có thể giảm kích thước tải xuống ban đầu của ứng dụng và cập nhật các mô hình ML 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. Và, với Cấu hình từ xa và Thử nghiệm A/B, bạn có thể linh hoạt phân phát các mô hình khác nhau cho các nhóm người dùng khác nhau.

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

  • Thư viện MLModelDownloader chỉ có sẵn 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

Mô hình TensorFlow Lite là mô hình ML được tối ưu hóa để chạy trên thiết bị di động. Để có được 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 vì 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 để biết hướng dẫn cách cài đặt MLModelDownloader .

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

Nhanh

import FirebaseMLModelDownloader
import TensorFlowLite

1. Triển khai mô hình của bạn

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

Sau khi thêm mô hình tùy chỉnh vào dự án Firebase, bạn có thể tham chiếu mô hình đó trong ứng dụng của mình bằng tên bạn đã chỉ định. Bất cứ lúc nào, bạn có thể triển khai 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 bằng cách 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

Để sử dụng mô hình TensorFlow Lite trong ứng dụng của bạn, trước tiên hãy sử dụng SDK Firebase ML để 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 xuống mô hình, hãy gọi phương thức getModel() của trình tải xuống mô hình, chỉ định tên bạn đã gán cho mô hình khi tải mô hình lên, liệu bạn có muốn luôn tải xuống mô hình mới nhất hay không 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 từ ba hành vi tải xuống:

Loại tải xuống Sự miêu tả
localModel Lấy mô hình cục bộ từ thiết bị. Nếu không có mô hình cục bộ nào, mô hình này sẽ hoạt động như latestModel . Sử dụng loại tải xuống này nếu bạn không muốn kiểm tra các bản cập nhật kiểu máy. Ví dụ: bạn đang sử dụng Cấu hình từ xa để truy xuất tên mẫu máy và bạn luôn tải lên các mẫu máy dưới tên mới (được khuyến nghị).
localModelUpdateInBackground Lấy mô hình cục bộ từ thiết bị và bắt đầu cập nhật mô hình ở chế độ nền. Nếu không có mô hình cục bộ nào, mô hình này sẽ hoạt động như latestModel .
latestModel Lấy 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ô hình cục bộ. Nếu không, hãy tải xuống mẫu mới nhất. 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 được khuyến nghị). Chỉ sử dụng hành vi này trong trường hợp bạn rõ ràng cần phiên bản mới nhất.

Bạn nên tắt chức năng liên quan đến mô hình—ví dụ: chuyển sang 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.

Nhanh

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 tạo của chúng nhưng bạn có thể làm như vậy bất kỳ lúc nào trước khi cần sử dụng mô hình.

3. Thực hiện suy luận dữ liệu đầu vào

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

Trình thông dịch mô hình TensorFlow Lite lấy đầu vào và tạo ra một hoặc nhiều mảng đa chiều làm đầu ra. Các mảng này chứa các giá trị byte , int , long hoặc float . Trước khi có thể truyền dữ liệu đến một mô hình hoặc sử dụng kết quả của nó, 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 được ghi lại thì 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 mình. 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']))

Đầu ra ví dụ:

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

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

Chạy trình thông dịch

Sau khi bạn đã xác định định dạng đầu vào và đầu ra của mô hình, hãy lấy dữ liệu đầu vào và thực hiện bất kỳ phép biến đổi nào trên 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ủa bạn có kích thước đầu vào là các giá trị dấu phẩy động [1, 224, 224, 3] thì bạn có thể phải chia tỷ lệ các giá trị màu của hình ảnh thành phạm vi dấu phẩy động như trong ví dụ sau :

Nhanh

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 đó, sao chép NSData đầu vào của bạn vào trình thông dịch và chạy nó:

Nhanh

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

Bạn có thể lấy đầu ra 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 đầu ra tùy thuộc vào kiểu máy bạn đang sử dụng.

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

Nhanh

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 cung cấp các mô hình TensorFlow Lite cho Firebase ML bằng cách nào, Firebase ML sẽ lưu trữ chúng ở định dạng protobuf được tuần tự hóa tiêu chuẩn trong bộ nhớ cục bộ.

Về 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, trên thực tế, hầu hết các mô hình đều dành riêng cho ứng dụng và bị che khuất bởi sự tối ưu hóa nên rủi ro tương tự như rủi ro của các đối thủ cạnh tranh khi tháo rời và sử dụng lại mã của bạn. Tuy nhiên, bạn nên lưu ý đến rủi ro này trước khi sử dụng mô hình tùy chỉnh trong ứng dụng của mình.