Если ваше приложение использует пользовательские модели 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 или Firebase Admin Python и Node.js SDK. См. раздел Развертывание пользовательских моделей и управление ими .
После добавления пользовательской модели в проект 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 для проверки вашей модели. Например:
Питон
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 в локальном хранилище.
Теоретически это означает, что кто угодно может скопировать вашу модель. Однако на практике большинство моделей настолько специфичны для приложения и запутаны оптимизациями, что риск аналогичен риску дизассемблирования и повторного использования вашего кода конкурентами. Тем не менее, вы должны знать об этом риске, прежде чем использовать пользовательскую модель в своем приложении.