Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Use um modelo TensorFlow Lite personalizado no iOS

Se o seu aplicativo usa personalizados TensorFlow Lite modelos, você pode usar Firebase ML para implantar seus modelos. Ao implantar modelos com o Firebase, você pode reduzir o tamanho inicial do download do seu aplicativo e atualizar os modelos de ML do seu aplicativo sem lançar uma nova versão do seu aplicativo. E, com o Remote config e o teste A / B, você pode veicular dinamicamente diferentes modelos para diferentes conjuntos de usuários.

Pré-requisitos

  • O MLModelDownloader biblioteca está disponível apenas para Swift.
  • O TensorFlow Lite é executado apenas em dispositivos que usam iOS 9 e mais recente.

Modelos TensorFlow Lite

Os modelos do TensorFlow Lite são modelos de ML otimizados para execução em dispositivos móveis. Para obter um modelo TensorFlow Lite:

Antes de você começar

  1. Se você ainda não tiver adicionado Firebase ao seu aplicativo, fazê-lo seguindo os passos do guia de introdução .
  2. Inclua o Firebase em seu Podfile:

    Rápido

    pod 'Firebase/MLModelDownloader'
    pod 'TensorFlowLiteSwift'
    
    Depois de instalar ou atualizar Pods do seu projeto, certifique-se de abrir seu projeto Xcode usando seu .xcworkspace .
  3. Em seu aplicativo, importe o Firebase:

    Rápido

    import Firebase
    import TensorFlowLite
    

1. Implante seu modelo

Implante seus modelos personalizados do TensorFlow usando o Firebase console ou os SDKs Admin para Python e Node.js do Firebase. Veja implantar e gerenciar modelos personalizados .

Depois de adicionar um modelo personalizado ao seu projeto do Firebase, você pode fazer referência ao modelo em seus aplicativos usando o nome que especificou. A qualquer momento, você pode implantar um novo modelo TensorFlow Lite e baixar o novo modelo para dispositivos dos usuários chamando getModel() (veja abaixo).

2. Baixe o modelo para o dispositivo e inicialize um interpretador TensorFlow Lite

Para usar seu modelo TensorFlow Lite em seu aplicativo, primeiro use o Firebase ML SDK para fazer o download da versão mais recente do modelo para o dispositivo.

Para iniciar o download do modelo, chame o modelo de downloader getModel() método, especificando o nome atribuído o modelo quando você fizer o upload, se você deseja fazer o download sempre o último modelo, e as condições em que você deseja permitir o download.

Você pode escolher entre três comportamentos de download:

Tipo de download Descrição
localModel Obtenha o modelo local do dispositivo. Se não existe um modelo local disponível, este se comporta como latestModel . Use este tipo de download se não estiver interessado em verificar se há atualizações do modelo. Por exemplo, você está usando o Configuração remota para recuperar nomes de modelo e sempre carrega modelos com novos nomes (recomendado).
localModelUpdateInBackground Obtenha o modelo local do dispositivo e comece a atualizar o modelo em segundo plano. Se não existe um modelo local disponível, este se comporta como latestModel .
latestModel Obtenha o modelo mais recente. Se o modelo local for a versão mais recente, retorna o modelo local. Caso contrário, baixe o modelo mais recente. Este comportamento será bloqueado até que a versão mais recente seja baixada (não recomendado). Use este comportamento apenas nos casos em que você precisa explicitamente da versão mais recente.

Você deve desabilitar a funcionalidade relacionada ao modelo - por exemplo, acinzentar ou ocultar parte de sua IU - até que você confirme que o modelo foi baixado.

Rápido

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

Muitos aplicativos iniciam a tarefa de download em seu código de inicialização, mas você pode fazer isso a qualquer momento antes de precisar usar o modelo.

3. Realize inferência nos dados de entrada

Obtenha as formas de entrada e saída do seu modelo

O interpretador de modelo TensorFlow Lite pega como entrada e produz como saída uma ou mais matrizes multidimensionais. Estas matrizes contêm quer byte , int , long , ou float valores. Antes de passar dados para um modelo ou usar seu resultado, você deve saber o número e as dimensões ("forma") das matrizes que seu modelo usa.

Se você mesmo construiu o modelo, ou se o formato de entrada e saída do modelo está documentado, talvez você já tenha essas informações. Se você não sabe a forma e o tipo de dados de entrada e saída do seu modelo, pode usar o interpretador TensorFlow Lite para inspecionar seu modelo. Por exemplo:

Pitão

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

Exemplo de saída:

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

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

Execute o intérprete

Depois de determinar o formato de entrada e saída de seu modelo, obtenha seus dados de entrada e execute quaisquer transformações nos dados que sejam necessárias para obter uma entrada da forma correta para seu modelo.

Por exemplo, se o seu modelo processa as imagens, e seu modelo tem dimensões de entrada de [1, 224, 224, 3] valores de ponto flutuante, você pode ter que escalar os valores de cores da imagem a uma gama de ponto flutuante como no exemplo a seguir :

Rápido

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

Em seguida, copie sua entrada NSData para o intérprete e executá-lo:

Rápido

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

Você pode obter ouput do modelo chamando o intérprete output(at:) método. Como você usa a saída depende do modelo que você está usando.

Por exemplo, se você estiver realizando a classificação, como uma próxima etapa, você pode mapear os índices do resultado para os rótulos que eles representam:

Rápido

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

Apêndice: Segurança do modelo

Independentemente de como você disponibiliza seus modelos do TensorFlow Lite para o Firebase ML, o Firebase ML os armazena no formato protobuf serializado padrão no armazenamento local.

Em teoria, isso significa que qualquer pessoa pode copiar seu modelo. No entanto, na prática, a maioria dos modelos são tão específicos do aplicativo e ofuscados por otimizações que o risco é semelhante ao de concorrentes desmontando e reutilizando seu código. No entanto, você deve estar ciente desse risco antes de usar um modelo personalizado em seu aplicativo.