Catch up on everthing we announced at this year's Firebase Summit. Learn more

Use um modelo TensorFlow Lite personalizado em plataformas Apple

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 servir 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

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

Use o Swift Package Manager para instalar e gerenciar dependências do Firebase.

  1. No Xcode, com o seu projeto aplicativo aberto, navegue até Arquivo> Pacotes Swift> Adicionar pacote de dependência.
  2. Quando solicitado, adicione o repositório do SDK das plataformas Firebase Apple:
  3.   https://github.com/firebase/firebase-ios-sdk
      
  4. Escolha a biblioteca Firebase ML.
  5. Quando terminar, o Xcode começará automaticamente a resolver e baixar suas dependências em segundo plano.

Em seguida, execute algumas configurações no aplicativo:

  1. 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. Esse comportamento será bloqueado até que a versão mais recente seja baixada (não recomendado). Use esse 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 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']))

Saída de exemplo:

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.