Adicione o Firebase ao seu aplicativo iOS com tecnologia TFLite

1. Visão Geral

Metas

O Firebase ML permite que você implante seu modelo over-the-air. Isso permite que você mantenha o tamanho do aplicativo pequeno e baixe o modelo de ML apenas quando necessário, experimente vários modelos ou atualize seu modelo de ML sem precisar republicar o aplicativo inteiro.

Neste codelab, você converterá um app iOS usando um modelo TFLite estático em um app usando um modelo veiculado dinamicamente pelo Firebase. Você vai aprender como:

  1. Implante modelos TFLite no Firebase ML e acesse-os em seu aplicativo
  2. Registre métricas relacionadas ao modelo com o Analytics
  3. Selecione qual modelo é carregado por meio do Remote Config
  4. Teste A/B diferentes modelos

Pré-requisitos

Antes de iniciar este codelab, verifique se você instalou:

  • Xcode 11 (ou superior)
  • CocoaPods 1.9.1 (ou superior)

2. Crie um projeto de console do Firebase

Adicionar Firebase ao projeto

  1. Acesse o console do Firebase .
  2. Selecione Create New Project e nomeie seu projeto como "Firebase ML iOS Codelab".

3. Obtenha o Projeto de Amostra

Baixe o Código

Comece clonando o projeto de amostra e executando pod update no diretório do projeto:

git clone https://github.com/FirebaseExtended/codelab-digitclassifier-ios.git
cd codelab-digitclassifier-ios
pod install --repo-update

Se você não tiver o git instalado, também pode baixar o projeto de amostra em sua página do GitHub ou clicando neste link . Depois de baixar o projeto, execute-o no Xcode e experimente o classificador de dígitos para ter uma ideia de como ele funciona.

Configurar o Firebase

Siga a documentação para criar um novo projeto do Firebase. Assim que tiver seu projeto, baixe o arquivo GoogleService-Info.plist do seu projeto no console do Firebase e arraste-o para a raiz do projeto Xcode.

f06cb08d48de7e10.png

Adicione Firebase ao seu Podfile e execute pod install.

pod 'FirebaseMLModelDownloader', '9.3.0-beta'

No método didFinishLaunchingWithOptions do AppDelegate , importe Firebase na parte superior do arquivo

import FirebaseCore

E adicione uma chamada para configurar o Firebase.

FirebaseApp.configure()

Execute o projeto novamente para garantir que o aplicativo esteja configurado corretamente e não falhe ao iniciar.

4. Implante um modelo no Firebase ML

Implantar um modelo no Firebase ML é útil por dois motivos principais:

  1. Podemos manter o tamanho da instalação do aplicativo pequeno e baixar o modelo apenas se necessário
  2. O modelo pode ser atualizado regularmente e com um ciclo de lançamento diferente do aplicativo inteiro

Antes de podermos substituir o modelo estático em nosso aplicativo por um modelo baixado dinamicamente do Firebase, precisamos implantá-lo no Firebase ML. O modelo pode ser implantado por meio do console ou programaticamente, usando o Firebase Admin SDK. Nesta etapa, implantaremos por meio do console.

Para simplificar, usaremos o modelo TensorFlow Lite que já está em nosso aplicativo. Primeiro, abra o Firebase e clique em Machine Learning no painel de navegação esquerdo. Em seguida, navegue até "Personalizado" e clique no botão "Adicionar modelo".

Quando solicitado, dê ao modelo um nome descritivo como mnist_v1 e faça upload do arquivo do diretório do projeto do codelab.

3c3c50e6ef12b3b.png

5. Baixe o modelo do Firebase ML

Escolher quando baixar o modelo remoto do Firebase em seu aplicativo pode ser complicado, pois os modelos TFLite podem crescer relativamente grandes. Idealmente, queremos evitar carregar o modelo imediatamente quando o aplicativo for iniciado, pois se nosso modelo for usado para apenas um recurso e o usuário nunca usar esse recurso, teremos baixado uma quantidade significativa de dados sem motivo. Também podemos definir opções de download, como apenas buscar modelos quando conectado ao wi-fi. Se você deseja garantir que o modelo esteja disponível mesmo sem uma conexão de rede, também deve agrupar o modelo como parte do aplicativo como um backup.

Para simplificar, removeremos o modelo empacotado padrão e sempre baixaremos um modelo do Firebase quando o aplicativo for iniciado. Dessa forma, ao executar o reconhecimento de dígitos, você pode ter certeza de que a inferência está sendo executada com o modelo fornecido pelo Firebase.

Na parte superior de ModelLoader.swift , importe o módulo Firebase.

import FirebaseCore
import FirebaseMLModelDownloader

Em seguida, implemente o seguinte método.

static func downloadModel(named name: String,
                          completion: @escaping (CustomModel?, DownloadError?) -> Void) {
  guard FirebaseApp.app() != nil else {
    completion(nil, .firebaseNotInitialized)
    return
  }
  guard success == nil && failure == nil else {
    completion(nil, .downloadInProgress)
    return
  }
  let conditions = ModelDownloadConditions(allowsCellularAccess: false)
  ModelDownloader.modelDownloader().getModel(name: name, downloadType: .localModelUpdateInBackground, conditions: conditions) { result in
          switch (result) {
          case .success(let customModel):
                  // Download complete.
                  // The CustomModel object contains the local path of the model file,
                  // which you can use to instantiate a TensorFlow Lite classifier.
                  return completion(customModel, nil)
          case .failure(let error):
              // Download was unsuccessful. Notify error message.
            completion(nil, .downloadFailed(underlyingError: error))
          }
  }
}

No viewDidLoad de ViewController.swift , substitua a chamada de inicialização DigitClassifier pelo nosso novo método de download de modelo.

    // Download the model from Firebase
    print("Fetching model...")
    ModelLoader.downloadModel(named: "mnist_v1") { (customModel, error) in
      guard let customModel = customModel else {
        if let error = error {
          print(error)
        }
        return
      }

      print("Model download complete")
      
      // Initialize a DigitClassifier instance
      DigitClassifier.newInstance(modelPath: customModel.path) { result in
      switch result {
        case let .success(classifier):
          self.classifier = classifier
        case .error(_):
          self.resultLabel.text = "Failed to initialize."
        }
      }
    }

Execute novamente seu aplicativo. Após alguns segundos, você verá um log no Xcode indicando que o modelo remoto foi baixado com sucesso. Tente desenhar um dígito e confirme se o comportamento do aplicativo não mudou.

6. Acompanhe o feedback e a conversão do usuário para medir a precisão do modelo

Mediremos a precisão do modelo rastreando o feedback do usuário sobre as previsões do modelo. Se um usuário clicar em "sim", isso indicará que a previsão foi precisa.

Podemos registrar um evento do Analytics para rastrear a precisão do nosso modelo. Primeiro, devemos adicionar o Analytics ao Podfile antes que ele possa ser usado no projeto:

pod 'FirebaseAnalytics'

Em seguida, em ViewController.swift importe o Firebase na parte superior do arquivo

import FirebaseAnalytics

E adicione a seguinte linha de código no método correctButtonPressed .

Analytics.logEvent("correct_inference", parameters: nil)

Execute o aplicativo novamente e desenhe um dígito. Pressione o botão "Sim" algumas vezes para enviar feedback de que a inferência foi precisa.

Análise de depuração

Geralmente, os eventos registrados pelo seu aplicativo são agrupados em lotes durante o período de aproximadamente uma hora e carregados juntos. Essa abordagem economiza a bateria dos dispositivos dos usuários finais e reduz o uso de dados da rede. No entanto, para fins de validação de sua implementação de análise (e, para visualizar sua análise no relatório DebugView), você pode habilitar o modo de depuração em seu dispositivo de desenvolvimento para carregar eventos com um atraso mínimo.

Para habilitar o modo Analytics Debug em seu dispositivo de desenvolvimento, especifique o seguinte argumento de linha de comando no Xcode:

-FIRDebugEnabled

Execute o aplicativo novamente e desenhe um dígito. Pressione o botão "Sim" algumas vezes para enviar feedback de que a inferência foi precisa. Agora você pode visualizar os eventos de log quase em tempo real por meio da visualização de depuração no console do Firebase. Clique em Analytics > DebugView na barra de navegação à esquerda.

5276199a086721fd.png

7. Acompanhe o tempo de inferência com o Firebase Performance

Ao testar seu modelo, as métricas de desempenho feitas em dispositivos de desenvolvimento não são suficientes para capturar o desempenho do modelo nas mãos de seus usuários, pois é difícil dizer em qual hardware os usuários executarão seu aplicativo. Felizmente, você pode medir o desempenho do seu modelo nos dispositivos dos usuários com o Firebase Performance para obter uma imagem melhor do desempenho do seu modelo.

Para medir o tempo necessário para executar a inferência, primeiro importe o Firebase em DigitClassifier.swift:

import FirebasePerformance

Em seguida, inicie um rastreamento de desempenho no método de classificação e pare o rastreamento quando a inferência estiver concluída. Certifique-se de adicionar as seguintes linhas de código dentro do fechamento DispatchQueue.global.async e não diretamente abaixo da declaração do método.

let inferenceTrace = Performance.startTrace(name: "tflite inference")
defer {
  inferenceTrace?.stop()
}

Se estiver curioso, você pode ativar o log de depuração por meio das instruções aqui para confirmar que seus rastreamentos de desempenho estão sendo registrados. Depois de um tempo, os rastreamentos de desempenho também ficarão visíveis no Firebase Console.

8. Implante um segundo modelo no Firebase ML

Ao criar uma nova versão do seu modelo, como uma com uma arquitetura de modelo melhor ou treinada em um conjunto de dados maior ou atualizado, podemos nos sentir tentados a substituir nosso modelo atual pela nova versão. No entanto, um modelo com bom desempenho no teste não necessariamente funciona igualmente bem na produção. Portanto, vamos fazer testes A/B em produção para comparar nosso modelo original e o novo.

Ativar a API Firebase Model Management

Nesta etapa, habilitaremos a API Firebase Model Management para implantar uma nova versão do nosso modelo TensorFlow Lite usando o código Python.

Crie um bucket para armazenar seus modelos de ML

No Firebase Console, vá para Storage e clique em Começar. fbbea78f0eb3dc9f.png

Siga o diálogo para configurar seu balde.

19517c0d6d2aa14d.png

Ativar Firebase ML API

Acesse a página Firebase ML API no Console do Google Cloud e clique em Ativar.

2414fd5cced6c984.png Selecione o aplicativo Digit Classifier quando solicitado.

Agora vamos treinar uma nova versão do modelo usando um conjunto de dados maior e, em seguida, implantá-lo programaticamente diretamente do notebook de treinamento usando o Firebase Admin SDK.

Baixe a chave privada da conta de serviço

Antes de podermos usar o Firebase Admin SDK, precisamos criar uma conta de serviço. Abra o painel Service Accounts do Firebase console clicando neste link e clique no botão para criar uma nova conta de serviço para o Firebase Admin SDK. Quando solicitado, clique no botão Gerar nova chave privada. Usaremos a chave da conta de serviço para autenticar nossas solicitações do notebook colab.

c3b95de1e5508516.png

Agora podemos treinar e implantar o novo modelo.

  1. Abra este notebook colab e faça uma cópia dele em seu próprio Drive.
  2. Execute a primeira célula "Treinar um modelo melhorado do TensorFlow Lite" clicando no botão de reprodução à esquerda dela. Isso treinará um novo modelo e pode levar algum tempo.
  3. A execução da segunda célula criará um prompt de upload de arquivo. Carregue o arquivo json que você baixou do Firebase Console ao criar sua conta de serviço.

71e847c6a85423b3.png

  1. Execute as duas últimas células.

Depois de executar o notebook colab, você verá um segundo modelo no Firebase console. Certifique-se de que o segundo modelo seja denominado mnist_v2 .

c316683bb4d75d57.png

9. Selecione um modelo via Remote Config

Agora que temos dois modelos separados, adicionaremos um parâmetro para selecionar qual modelo baixar no tempo de execução. O valor do parâmetro que o cliente recebe determinará qual modelo o cliente baixa. Primeiro, abra o console do Firebase e clique no botão Remote Config no menu de navegação à esquerda. Em seguida, clique no botão "Adicionar parâmetro".

Nomeie o novo parâmetro model_name e dê a ele um valor padrão de mnist_v1 . Clique em Publicar alterações para aplicar as atualizações. Ao colocar o nome do modelo no parâmetro de configuração remota, podemos testar vários modelos sem adicionar um novo parâmetro para cada modelo que queremos testar.

Depois de adicionar o parâmetro, você deve vê-lo no Console:

699b3fd32acce887.png

Em nosso código, precisaremos adicionar uma verificação ao carregar o modelo remoto. Ao recebermos o parâmetro do Remote Config, buscaremos o modelo remoto com o nome correspondente; caso contrário, tentaremos carregar mnist_v1 . Antes de podermos usar o Remote Config, precisamos adicioná-lo ao nosso projeto especificando-o como uma dependência no Podfile:

pod 'FirebaseRemoteConfig'

Execute a instalação do pod e reabra o projeto Xcode. Em ModelLoader.swift , implemente o método fetchParameterizedModel .

static func fetchParameterizedModel(completion: @escaping (CustomModel?, DownloadError?) -> Void) {
  RemoteConfig.remoteConfig().fetchAndActivate { (status, error) in
    DispatchQueue.main.async {
      if let error = error {
        let compositeError = DownloadError.downloadFailed(underlyingError: error)
        completion(nil, compositeError)
        return
      }

      let modelName: String
      if let name = RemoteConfig.remoteConfig().configValue(forKey: "model_name").stringValue {
        modelName = name
      } else {
        let defaultName = "mnist_v1"
        print("Unable to fetch model name from config, falling back to default \(defaultName)")
        modelName = defaultName
      }
      downloadModel(named: modelName, completion: completion)
    }
  }
}

Por fim, em ViewController.swift , substitua a chamada downloadModel pelo novo método que acabamos de implementar.

// Download the model from Firebase
print("Fetching model...")
ModelLoader.fetchParameterizedModel { (customModel, error) in
  guard let customModel = customModel else {
    if let error = error {
      print(error)
    }
    return
  }

  print("Model download complete")
  
  // Initialize a DigitClassifier instance
  DigitClassifier.newInstance(modelPath: customModel.path) { result in
  switch result {
    case let .success(classifier):
      self.classifier = classifier
    case .error(_):
      self.resultLabel.text = "Failed to initialize."
    }
  }
}

Execute novamente o aplicativo e verifique se ele ainda carrega o modelo corretamente.

10. Teste A/B dos dois modelos

Por fim, podemos usar o comportamento de teste A/B integrado do Firebase para ver qual dos nossos dois modelos tem melhor desempenho. Acesse Analytics -> Events no console do Firebase. Se o evento correct_inference estiver aparecendo, marque-o como um "Evento de conversão", caso contrário, você pode ir para Analytics -> Conversion Events e clicar em "Create a New Conversion Event" e colocar correct_inference.

Agora vá para "Configuração remota no console do Firebase, selecione o botão "Teste A/B" no menu de mais opções no parâmetro "model_name" que acabamos de adicionar.

fad5ea36969d2aeb.png

No menu a seguir, aceite o nome padrão.

d7c006669ace6e40.png

Selecione seu aplicativo no menu suspenso e altere os critérios de segmentação para 50% dos usuários ativos.

6246dd7c660b53fb.png

Se você conseguiu definir o evento correct_inference como uma conversão anteriormente, use esse evento como a métrica principal a ser rastreada. Caso contrário, se não quiser esperar que o evento apareça no Analytics, você pode adicionar correct_inference manualmente.

1ac9c94fb3159271.png

Por fim, na tela Variantes, defina sua variante do grupo de controle para usar mnist_v1 e seu grupo Variante A para usar mnist_v2 .

e4510434f8da31b6.png

Clique no botão Revisar no canto inferior direito.

Parabéns, você criou com sucesso um teste A/B para seus dois modelos separados! O teste A/B está atualmente em estado de rascunho e pode ser iniciado a qualquer momento clicando no botão "Iniciar experimento".

Para uma visão mais detalhada do teste A/B, confira a documentação do teste A/B .

11. Conclusão

Neste codelab, você aprendeu a substituir um recurso tflite empacotado estaticamente em seu app por um modelo TFLite carregado dinamicamente do Firebase. Para saber mais sobre o TFLite e o Firebase, dê uma olhada em outros exemplos do TFLite e nos guias de primeiros passos do Firebase.

Ter uma questão?

Relatar problemas