Если ваше приложение использует собственные модели TensorFlow Lite , вы можете использовать Firebase ML для развертывания этих моделей. Развертывание моделей с помощью Firebase позволяет уменьшить размер первоначальной загрузки приложения и обновлять модели машинного обучения без выпуска новой версии приложения. А благодаря Remote Config и A/B Testing вы можете динамически предоставлять разные модели разным группам пользователей.
Предварительные требования
- Библиотека
MLModelDownloaderдоступна только для Swift. - TensorFlow Lite работает только на устройствах с iOS 9 и более поздними версиями.
модели TensorFlow Lite
Модели TensorFlow Lite — это модели машинного обучения, оптимизированные для работы на мобильных устройствах. Чтобы получить модель TensorFlow Lite:
- Используйте готовую модель, например, одну из официальных моделей TensorFlow Lite .
- Преобразуйте модель TensorFlow, модель Keras или конкретную функцию в формат TensorFlow Lite.
Прежде чем начать
Для использования TensorFlowLite с Firebase необходимо использовать CocoaPods, поскольку TensorFlowLite в настоящее время не поддерживает установку с помощью Swift Package Manager. Инструкции по установке MLModelDownloader см. в руководстве по установке CocoaPods .
После установки импортируйте Firebase и TensorFlowLite, чтобы использовать их.
Быстрый
import FirebaseMLModelDownloader
import TensorFlowLite
1. Разверните свою модель.
Развертывайте свои пользовательские модели TensorFlow, используя либо консоль Firebase , либо SDK Firebase Admin для Python и Node.js. См. раздел «Развертывание и управление пользовательскими моделями» .
После добавления пользовательской модели в ваш проект Firebase вы можете ссылаться на нее в своих приложениях, используя указанное вами имя. В любой момент вы можете развернуть новую модель TensorFlow Lite и загрузить ее на устройства пользователей, вызвав getModel() (см. ниже).
2. Загрузите модель на устройство и инициализируйте интерпретатор TensorFlow Lite.
Чтобы использовать модель TensorFlow Lite в своем приложении, сначала воспользуйтесь Firebase ML SDK, чтобы загрузить последнюю версию модели на устройство. Чтобы начать загрузку модели, вызовите метод 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 для проверки вашей модели. Например:
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] в виде чисел с плавающей запятой, вам может потребоваться масштабировать значения цвета изображения до диапазона чисел с плавающей запятой, как показано в следующем примере:
Быстрый
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 ..< 224 {
for col in 0 ..< 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(&bytes, &normalizedRed, elementSize)
inputData.append(&bytes, count: elementSize)
memcpy(&bytes, &normalizedGreen, elementSize)
inputData.append(&bytes, count: elementSize)
memcpy(&ammp;bytes, &normalizedBlue, elementSize)
inputData.append(&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 в локальном хранилище.
Теоретически это означает, что любой может скопировать вашу модель. Однако на практике большинство моделей настолько специфичны для конкретного приложения и завуалированы оптимизациями, что риск сопоставим с риском того, что конкуренты разберут и повторно используют ваш код. Тем не менее, вам следует помнить об этом риске, прежде чем использовать собственную модель в своем приложении.