Используйте пользовательскую модель TensorFlow Lite на платформах Apple

Если ваше приложение использует пользовательские TensorFlow Lite модели, вы можете использовать Firebase ML для развертывания моделей. Развертывая модели с помощью Firebase, вы можете уменьшить первоначальный размер загружаемого приложения и обновить модели машинного обучения своего приложения, не выпуская новую версию своего приложения. А с помощью удаленной настройки и A/B-тестирования вы можете динамически обслуживать разные модели для разных групп пользователей.

Предпосылки

  • MLModelDownloader библиотека доступна только для Swift.
  • TensorFlow Lite работает только на устройствах с iOS 9 и новее.

Модели TensorFlow Lite

Модели TensorFlow Lite — это модели машинного обучения, оптимизированные для работы на мобильных устройствах. Чтобы получить модель TensorFlow Lite:

Прежде чем вы начнете

Если вы еще не добавили Firebase в ваше приложение, сделать это, следуя инструкциям , приведенным в руководстве Приступая к работе .

Используйте Swift Package Manager для установки и управления зависимостями Firebase.

  1. В Xcode, с приложением проекта открыто, перейдите в меню Файл> Swift пакеты> Добавить пакет Завис.
  2. При появлении запроса добавьте репозиторий Firebase Apple Platform SDK:
  3.   https://github.com/firebase/firebase-ios-sdk
      
  4. Выберите библиотеку Firebase ML.
  5. По завершении Xcode автоматически начнет разрешение и загрузку ваших зависимостей в фоновом режиме.

Затем выполните некоторые настройки в приложении:

  1. В вашем приложении импортируйте Firebase:

    Быстрый

    import Firebase
    import TensorFlowLite
    

1. Разверните свою модель

Разверните свои пользовательские модели TensorFlow с помощью консоли Firebase или пакетов Firebase Admin Python и Node.js SDK. См Развертывание и управление пользовательских моделей .

После добавления пользовательской модели в проект Firebase вы можете ссылаться на модель в своих приложениях, используя указанное вами имя. В любое время вы можете развернуть новую модель TensorFlow Lite и загрузить новую модель на устройства пользователей с помощью вызова getModel() (см . Ниже)

2. Загрузите модель на устройство и инициализируйте интерпретатор TensorFlow Lite.

Чтобы использовать модель TensorFlow Lite в своем приложении, сначала используйте SDK Firebase ML, чтобы загрузить последнюю версию модели на устройство.

Для запуска модели скачать, вызовите модель DownLoader в getModel() метод, указав имя присвоенного модель , когда вы загрузили его, хотите ли вы всегда загрузить последнюю модель, а также условия , при которых вы хотите разрешить загрузку.

Вы можете выбрать один из трех способов загрузки:

Тип загрузки Описание
localModel Получите локальную модель с устройства. Если нет локальной модели доступны, это ведет себя как latestModel . Используйте этот тип загрузки, если вы не заинтересованы в проверке обновлений модели. Например, вы используете Remote Config для получения имен моделей и всегда загружаете модели под новыми именами (рекомендуется).
localModelUpdateInBackground Получите локальную модель с устройства и запустите обновление модели в фоновом режиме. Если нет локальной модели доступны, это ведет себя как latestModel .
latestModel Получите последнюю модель. Если локальная модель является последней версией, возвращает локальную модель. В противном случае загрузите последнюю модель. Это поведение будет заблокировано до тех пор, пока не будет загружена последняя версия (не рекомендуется). Используйте это поведение только в тех случаях, когда вам явно нужна последняя версия.

Вы должны отключить функции, связанные с моделью, например сделать серым или скрыть часть вашего пользовательского интерфейса, пока вы не подтвердите, что модель была загружена.

Быстрый

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 для проверки вашей модели. Например:

питон

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] значения с плавающей точкой, вы , возможно , придется масштабировать цвет значений изображения в диапазоне с плавающей точкой , как в следующем примере :

Быстрый

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 переводчику и запустить его:

Быстрый

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

Вы можете получить в выводе модели путем вызова интерпретатора output(at:) метода. То, как вы используете выходные данные, зависит от используемой модели.

Например, если вы выполняете классификацию, в качестве следующего шага вы можете сопоставить индексы результата с метками, которые они представляют:

Быстрый

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 в локальном хранилище.

Теоретически это означает, что любой может скопировать вашу модель. Однако на практике большинство моделей настолько зависят от приложения и запутаны оптимизацией, что риск аналогичен риску дизассемблирования и повторного использования вашего кода конкурентами. Тем не менее, вы должны знать об этом риске, прежде чем использовать пользовательскую модель в своем приложении.