Criar um app iOS para prever valores

1. Antes de começar

Neste codelab, você aprenderá a executar uma inferência de regressão a partir de um app iOS usando o TensorFlow Serving com REST e gRPC.

Prerequisites

  • Conhecimento básico de desenvolvimento para iOS com Swift
  • Conhecimento básico de machine learning com o TensorFlow, como treinamento e implantação
  • Conhecimento básico do Colaboratory
  • Noções básicas de terminais, Python e Docker

O que você aprenderá

  • Como treinar um modelo de regressão com o TensorFlow
  • Como criar um app iOS simples e fazer previsões com o modelo treinado pelo TensorFlow Serving (REST e gRPC).
  • Como exibir o resultado na IU.

Pré-requisitos

2. Começar a configuração

Para fazer o download do código para este codelab, faça o seguinte:

  1. Navegue até o repositório do GitHub deste codelab.
  2. Clique em Code > Download zip para fazer o download de todo o código para este codelab.

a72f2bb4caa9a96.png

  1. Descompacte o arquivo ZIP baixado para descompactar uma pasta raiz codelabs com todos os recursos necessários.

Neste codelab, você só precisará dos arquivos no subdiretório TFServing/RegressioniOS do repositório, que contém duas pastas:

  • A pasta starter contém o código inicial que você usará como base para este codelab.
  • A pasta finished contém o código concluído do app de exemplo finalizado.

3. Fazer o download das dependências do projeto

Faça o download dos pods necessários

  • Na pasta starter/iOS, execute:
pod install

O Cocoapods instalará todas as bibliotecas necessárias e gerará um novo arquivo regression.xcworkspace.

4. Executar o app inicial

  • Clique duas vezes no arquivo regression.xcworkspace para abrir o Xcode.

Executar e explorar o app

  1. Altere a segmentação por dispositivo para qualquer iPhone, como o iPhone 13.

a57198a4f21f970.png

  1. Clique em cacc15c5638260ed.png 'Run' e aguarde o Xcode compilar o projeto e iniciar o app inicial no Simulator.

A IU é bem direta. Há uma caixa de texto em que você pode digitar um número, que é enviado ao back-end do TensorFlow Serving com REST ou gRPC. O back-end realiza a regressão no valor de entrada e retorna o valor previsto para o app cliente, que exibe o resultado na IU novamente.

d2976072474ce0b1.png

Se você inserir um número e clicar em Inferir, nada acontecerá porque o app ainda não poderá se comunicar com o back-end.

5. Treinar um modelo de regressão simples com o TensorFlow

A regressão é uma das tarefas mais comuns. O objetivo é prever uma única quantidade contínua com base na entrada. Por exemplo, com base na previsão do tempo para hoje, faça a previsão da temperatura mais alta amanhã.

Treinar um modelo de regressão

  1. Abra este link no navegador.

O Colab carrega o notebook Python.

  1. No notebook Python, importe as bibliotecas TensorFlow e NumPy e crie seis pares de dados de treinamento com xs como entrada e ys como rótulos.

Se você plotar esses pontos de dados em um gráfico, eles serão posicionados em uma linha reta porque são gerados pela equação y = 2x -1.

56d05252cfc9df9d.png

  1. Use a API Keras para criar uma rede neural de duas camadas simples e prever o valor de y com base na entrada de x. Depois, compile e ajuste o modelo.
xs = np.array([-1.0,  0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([-3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model = tf.keras.Sequential([
   tf.keras.layers.Dense(units=10, input_shape=[1]),
   tf.keras.layers.Dense(units=1),
   ])

model.compile(optimizer='sgd',
             loss='mean_squared_error')

history = model.fit(xs, ys, epochs=500, verbose=0)

print("Finished training the model")

print(model.predict([10.0]))

O treinamento do modelo pode levar alguns segundos, e o valor previsto para a entrada 10 é 18.999996, o que é uma boa previsão, já que a verdade é 2 * 10 -1 = 19.

  1. Exporte o modelo:
model_dir = './regression/'
version = 123
export_path = os.path.join(model_dir, str(version))
model.save(export_path, save_format="tf")
print('\nexport_path = {}'.format(export_path))
!ls -l {export_path}
  1. Compacte o SavedModel exportado em um único arquivo regression.zip:
!zip -r regression.zip ./regression
  1. Clique em Runtime > Run all no menu de navegação para executar o notebook e depois esperar a execução ser concluída.
  2. Clique em c55600d42359f901.png Arquivos e faça o download do regression.zip.

bceda15d86571583.png

6. Implantar um modelo de regressão com o TensorFlow Serving

  • Para implantar o modelo com o TensorFlow Serving, descompacte o arquivo regression.zip com uma ferramenta de descompactação, como o 7-Zip.

A estrutura de pasta será semelhante a esta imagem:

7faeb4f03af39646.png

Você pode se referir à pasta regression como a pasta SavedModel. 123 é um exemplo de número da versão. Se quiser, você pode escolher outro número.

Iniciar o TensorFlow Serving

  • No seu terminal, inicie o TensorFlow Serving com o Docker, mas substitua o marcador PATH/TO/SAVEDMODEL pelo caminho absoluto da pasta regression no seu computador.
docker pull tensorflow/serving

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "PATH/TO/SAVEDMODEL:/models/regression" -e MODEL_NAME=regression tensorflow/serving

Primeiro, o Docker faz o download automático da imagem do TensorFlow Serving em um minuto. Depois disso, o TensorFlow Serving será iniciado. O registro será semelhante a este snippet de código:

2022-02-25 06:01:12.513231: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-02-25 06:01:12.585012: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3000000000 Hz
2022-02-25 06:01:13.395083: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ssd_mobilenet_v2_2/123
2022-02-25 06:01:13.837562: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 1928700 microseconds.
2022-02-25 06:01:13.877848: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ssd_mobilenet_v2_2/123/assets.extra/tf_serving_warmup_requests
2022-02-25 06:01:13.929844: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: regression version: 123}
2022-02-25 06:01:13.985848: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-02-25 06:01:13.985987: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-02-25 06:01:13.988994: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-02-25 06:01:14.033872: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

7. Conectar o app para iOS ao TensorFlow Serving por meio do REST

O back-end está pronto. Assim, você pode enviar solicitações de cliente ao TensorFlow Serving para fazer previsões. Há duas maneiras de enviar solicitações ao TensorFlow Serving:

  • REST
  • gRPC

Enviar solicitações e receber respostas com REST

Há três etapas simples:

  1. Crie a solicitação REST.
  2. Envie a solicitação REST para o TensorFlow Serving.
  3. Extraia o resultado previsto da resposta REST e renderize a IU.

Você realiza essas etapas no arquivo iOS/regression/ViewController.swift.

Criar a solicitação REST

  1. No momento, a função doInference() não envia a solicitação REST para o TensorFlow Serving. Você precisa implementar essa ramificação de REST para criar uma solicitação REST:
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
    print("Using REST")
    // TODO: Add code to send a REST request to TensorFlow Serving.

}

O TensorFlow Serving espera uma solicitação POST que contenha um valor único. Portanto, você precisa incorporar o valor de entrada em um JSON, que é o payload da solicitação.

  1. Adicione este código à ramificação REST:
//Create the REST request.
let json: [String: Any] = ["signature_name" : "serving_default", "instances" : [[value]]]

let jsonData = try? JSONSerialization.data(withJSONObject: json)

let url = URL(string: "http://localhost:8501/v1/models/regression:predict")!
var request = URLRequest(url: url)
request.httpMethod = "POST"

// Insert JSON data into the request.
request.httpBody = jsonData

Enviar a solicitação REST para o TensorFlow Serving

  • Adicione este código imediatamente após o código na ramificação REST:
// Send the REST request.
let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        print(error?.localizedDescription ?? "No data")
        return
    }

    // TODO: Add code to process the response.
}

task.resume()

Processar a resposta REST do TensorFlow Serving

  • Adicione este código ao snippet de código anterior imediatamente após o comentário TODO: Add code to process the response.:
// Process the REST response.
let results: RESTResults = try! JSONDecoder().decode(RESTResults.self, from: data)
DispatchQueue.main.async{
    self.txtOutput.text = String(results.predictions[0][0])
}

Agora, a função de pós-processamento extrai os valores previstos da resposta e exibe o resultado na IU.

Executar

  1. Clique em cacc15c5638260ed.png Run e aguarde o Xcode iniciar o app no Simulator.
  2. Insira um número na caixa de texto e clique em Inferir.

Agora você verá um valor previsto na IU.

df9bcb9aa21bb30e.png

8. Conectar o app para iOS ao TensorFlow Serving por meio do gRPC

Além do REST, o TensorFlow Serving também é compatível com o gRPC.

b6f4449c2c850b0e.png

O gRPC é um framework de chamada de procedimento remoto (RPC) moderno, de código aberto e de alta performance que pode ser executado em qualquer ambiente. Ele pode conectar serviços de forma eficiente em data centers e com compatibilidade conectável para balanceamento de carga, rastreamento, verificação de integridade e autenticação. Observamos que o gRPC tem uma performance melhor do que o REST na prática.

Enviar solicitações e receber respostas com o gRPC

Há quatro etapas simples:

  1. Opcional: gerar o código stub do cliente gRPC
  2. Criar a solicitação gRPC
  3. Enviar a solicitação gRPC para o TensorFlow Serving
  4. Extrair o resultado previsto da resposta gRPC e renderizar a IU

Você realiza essas etapas no arquivo iOS/regression/ViewController.swift.

Opcional: gerar o código stub do cliente gRPC

Para usar o gRPC com o TensorFlow Serving, é necessário seguir o fluxo de trabalho do gRPC. Caso queira saber mais, consulte a documentação do gRPC.

a9d0e5cb543467b4.png

O TensorFlow Serving e o TensorFlow definem os arquivos .proto automaticamente. No TensorFlow e no TensorFlow Serving 2.8, os seguintes arquivos .proto são necessários:

tensorflow/core/example/example.proto
tensorflow/core/example/feature.proto
tensorflow/core/protobuf/struct.proto
tensorflow/core/protobuf/saved_object_graph.proto
tensorflow/core/protobuf/saver.proto
tensorflow/core/protobuf/trackable_object_graph.proto
tensorflow/core/protobuf/meta_graph.proto
tensorflow/core/framework/node_def.proto
tensorflow/core/framework/attr_value.proto
tensorflow/core/framework/function.proto
tensorflow/core/framework/types.proto
tensorflow/core/framework/tensor_shape.proto
tensorflow/core/framework/full_type.proto
tensorflow/core/framework/versions.proto
tensorflow/core/framework/op_def.proto
tensorflow/core/framework/graph.proto
tensorflow/core/framework/tensor.proto
tensorflow/core/framework/resource_handle.proto
tensorflow/core/framework/variable.proto

tensorflow_serving/apis/inference.proto
tensorflow_serving/apis/classification.proto
tensorflow_serving/apis/predict.proto
tensorflow_serving/apis/regression.proto
tensorflow_serving/apis/get_model_metadata.proto
tensorflow_serving/apis/input.proto
tensorflow_serving/apis/prediction_service.proto
tensorflow_serving/apis/model.proto

Para gerar o código de stub do cliente gRPC:

  1. No terminal, navegue até a pasta starter/src/proto/ e gere o stub:
bash generate_grpc_stub_swift.sh

Vários arquivos .swift são gerados na pasta starter/src/proto/generated/import.

  1. Se eles ainda não foram copiados para o projeto, arraste todos os arquivos .swift gerados para o projeto no Xcode.

9e65705cf6be7aac.png

Criar a solicitação gRPC

Semelhante à solicitação REST, você cria a solicitação gRPC na ramificação gRPC.

if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {

}
else {
    print("Using gRPC")
    // TODO: add code to send a gRPC request to TF Serving

}
  • Para criar a solicitação gRPC, adicione este código à ramificação gRPC:
//Create the gRPC request.
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let channel = ClientConnection.insecure(group: group).connect(host: "localhost", port: 8500)
let stub = Tensorflow_Serving_PredictionServiceClient(channel: channel)

var modelSpec = Tensorflow_Serving_ModelSpec()
modelSpec.name = "regression"
modelSpec.signatureName = "serving_default"

// Prepare the input tensor.
var batchDim = Tensorflow_TensorShapeProto.Dim()
batchDim.size = 1
var inputDim = Tensorflow_TensorShapeProto.Dim()
inputDim.size = 1
var inputTensorShape = Tensorflow_TensorShapeProto()
inputTensorShape.dim = [batchDim, inputDim]
var inputTensor = Tensorflow_TensorProto()
inputTensor.dtype = Tensorflow_DataType.dtFloat
inputTensor.tensorShape = inputTensorShape
inputTensor.floatVal = [Float(value)]

var request = Tensorflow_Serving_PredictRequest()
request.modelSpec = modelSpec
request.inputs = ["dense_input" : inputTensor]

let callOptions = CallOptions(timeLimit: .timeout(.seconds(15)))

Enviar a solicitação gRPC para o TensorFlow Serving

  • Adicione este código à ramificação do gRPC imediatamente após o código no snippet de código anterior:
// Send the gRPC request.
let call = stub.predict(request, callOptions: callOptions)

Processar a resposta gRPC do TensorFlow Serving

  • Adicione este código imediatamente após o no snippet de código anterior:
// Process the response.
call.response.whenSuccess { response in
    let result = response.outputs["dense_1"]?.floatVal[0]
    DispatchQueue.main.async{
        self.txtOutput.text = String(describing: result!)
    }
}
call.response.whenFailure { error in
    print("Call failed with error\n\(error)")
}

Agora, a função de pós-processamento extrai os valores previstos da resposta e exibe o resultado na IU.

Executar

  1. Clique em cacc15c5638260ed.png Run no menu de navegação e aguarde o Xcode iniciar o app no Simulator.
  2. Insira um número na caixa de texto e clique em Inferir.

Agora você verá um valor previsto na IU.

9. Parabéns

Você usou o TensorFlow Serving para adicionar recursos de regressão ao seu app.

Saiba mais