Crea una app para iOS a fin de predecir valores

1. Antes de comenzar

En este codelab, aprenderás a ejecutar una inferencia de regresión desde una app para iOS con TensorFlow Serving con REST y gRPC.

Requisitos previos

  • Conocimientos básicos del desarrollo de iOS con Swift
  • Conocimientos básicos del aprendizaje automático con TensorFlow, como la implementación y el entrenamiento
  • Conocimientos básicos de Colaboratory
  • Conocimientos básicos de terminales, Python y Docker

Qué aprenderás

  • Cómo entrenar un modelo de regresión con TensorFlow
  • Cómo compilar una app para iOS simple y realizar predicciones con el modelo entrenado mediante TensorFlow Serving (REST y gRPC).
  • Cómo mostrar el resultado en la IU

Requisitos

2. Prepárate

Para descargar el código de este codelab, haz lo siguiente:

  1. Navega al repositorio de GitHub de este codelab.
  2. Haz clic en Código > Descargar ZIP para descargar todo el código de este codelab.

a72f2bb4caa9a96.png

  1. Descomprime el archivo ZIP descargado para descomprimir una carpeta raíz codelabs con todos los recursos que necesitas.

Para este codelab, solo necesitas los archivos del subdirectorio TFServing/RegressioniOS en el repositorio, que contiene dos carpetas:

  • La carpeta starter contiene el código de inicio en el que se basa este codelab.
  • La carpeta finished contiene el código completo de la app de muestra finalizada.

3. Descarga las dependencias del proyecto

Descargue los Pods necesarios

  • En la carpeta starter/iOS, ejecuta lo siguiente:
pod install

CocoaPods instalará todas las bibliotecas necesarias y generará un nuevo archivo regression.xcworkspace.

4. Ejecuta la app de inicio

  • Haz doble clic en el archivo regression.xcworkspace para abrir Xcode.

Ejecuta y explora la app

  1. Cambiar la orientación por dispositivo a cualquier iPhone, como iPhone 13

a57198a4f21f970.png

  1. Haz clic en cacc15c5637960ed.png "Run", espera a que Xcode compile el proyecto e inicie la app de inicio en el simulador.

La IU es bastante simple. Hay un cuadro de texto en el que puedes escribir un número, que se envía al backend de TensorFlow Serving con REST o gRPC. El backend realiza una regresión sobre el valor de entrada y muestra el valor predicho a la app cliente, que muestra el resultado en la IU nuevamente.

d2976072474ce0b1.png

Si ingresas un número y haces clic en Inferir, no sucede nada porque la app aún no puede comunicarse con el backend.

5. Entrena un modelo de regresión simple con TensorFlow

La regresión es una de las tareas de AA más comunes. Su objetivo es predecir una sola cantidad continua según la entrada. Por ejemplo, según el clima de hoy, predice la temperatura más alta para mañana.

Entrena un modelo de regresión

  1. Abra este vínculo en su navegador.

Colab carga el notebook de Python.

  1. En el notebook de Python, importa las bibliotecas TensorFlow y NumPy y, luego, crea seis pares de datos de entrenamiento con xs como entrada y ys como etiquetas.

Si trazas estos datos en un gráfico, en realidad se ubican en una línea recta porque se generan a partir de la ecuación y = 2x -1.

56d05252cfc9df9d.png

  1. Usa la API de Keras para crear una red neuronal simple de dos capas a fin de predecir el valor y según la entrada x. Luego, compila y ajusta el 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]))

El modelo tarda unos segundos en entrenarse y puedes ver que el valor previsto para la entrada 10 es 18.999996, que es una predicción bastante buena, ya que la verdad fundamental es 2 * 10 -1 = 19.

  1. Exporta el 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. Comprime el modelo guardado exportado en un solo archivo regression.zip:
!zip -r regression.zip ./regression
  1. Haga clic en Entorno de ejecución > Ejecutar todo en el menú de navegación para ejecutar el notebook y, luego, espere a que se complete la ejecución.
  2. Haz clic en c55600d42359f901.png Archivos y, luego, descarga el archivo regression.zip.

bceda15d86571583.png

6. Implementa un modelo de regresión con TensorFlow Serving

  • Para implementar el modelo con TensorFlow Serving, descomprime el archivo regression.zip descargado con una herramienta de descompresión, como 7-Zip.

La estructura de carpetas debe verse de la siguiente manera:

7faeb4f03af39646.png

Puedes hacer referencia a la carpeta regression como la carpeta SavedModel. 123 es un número de versión de ejemplo. Si quieres, puedes elegir otro número.

Inicia TensorFlow Serving

  • En tu terminal, inicia TensorFlow Serving con Docker, pero reemplaza el marcador de posición PATH/TO/SAVEDMODEL por la ruta de acceso absoluta de la carpeta regression en tu computadora.
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

Docker descarga automáticamente la imagen de TensorFlow Serving primero, lo cual tarda un minuto. Luego, TensorFlow Serving debería comenzar. El registro debería verse como este fragmento 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. Conecta la app para iOS con TensorFlow Serving mediante REST

El backend está listo, por lo que puedes enviar solicitudes de clientes a TensorFlow Serving para hacer predicciones. Hay dos maneras de enviar solicitudes a TensorFlow Serving:

  • REST
  • gRPC

Envía solicitudes y recibe respuestas con REST.

Existen tres pasos sencillos:

  1. Crea la solicitud REST.
  2. Envía la solicitud de REST a TensorFlow Serving.
  3. Extrae el resultado previsto de la respuesta de REST y procesa la IU.

Debes seguir estos pasos en el archivo iOS/regression/ViewController.swift.

Crea la solicitud de REST

  1. En este momento, la función doInference() no envía la solicitud de REST a TensorFlow Serving. Debes implementar esta rama de REST para crear una solicitud de REST:
if (connectionMode[picker.selectedRow(inComponent: 0)] == "REST") {
    print("Using REST")
    // TODO: Add code to send a REST request to TensorFlow Serving.

}

TensorFlow Serving espera una solicitud POST que contiene un solo valor, por lo que debes incorporar el valor de entrada en un JSON, que es la carga útil de la solicitud.

  1. Agrega este código a la rama de 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

Envía la solicitud de REST a TensorFlow Serving

  • Agrega este código inmediatamente después del código en la rama de 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()

Cómo procesar la respuesta de REST de TensorFlow Serving

  • Agrega este código al fragmento de código anterior inmediatamente después del comentario 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])
}

Ahora, la función de procesamiento posterior extrae los valores previstos de la respuesta y muestra el resultado en la IU.

Ejecuta la app

  1. Haz clic en cacc15c5637960ed.png "Run" y, luego, espera a que Xcode inicie la app en el simulador.
  2. Ingresa un número en el cuadro de texto y haz clic en Inferir.

Ahora verá un valor previsto en la IU.

df9bcb9aa21bb30e.png

8. Conecta la app para iOS con TensorFlow Serving a través de gRPC

Además de REST, TensorFlow Serving también es compatible con gRPC.

b6f4449c2c850b0e.png

gRPC es un framework moderno de código abierto, de alto rendimiento y llamada de procedimiento remoto (RPC), que se puede ejecutar en cualquier entorno. Puede conectar servicios en centros de datos, y entre ellos, con compatibilidad conectable para balanceo de cargas, seguimiento, verificación de estado y autenticación. Se observó que gRPC tiene un mejor rendimiento que REST en la práctica.

Envía solicitudes y recibe respuestas con gRPC

Hay cuatro pasos sencillos:

  1. Genera el código de stub del cliente de gRPC (opcional).
  2. Crea la solicitud de gRPC.
  3. Envía la solicitud gRPC a TensorFlow Serving.
  4. Extrae el resultado previsto de la respuesta de gRPC y procesa la IU.

Debes seguir estos pasos en el archivo iOS/regression/ViewController.swift.

Genera el código de stub del cliente de gRPC (opcional)

Para usar gRPC con TensorFlow Serving, debes seguir el flujo de trabajo de gRPC. Para obtener más información, consulta la documentación de gRPC.

a9d0e5cb543467b4.png

TensorFlow Serving y TensorFlow definen los archivos .proto por ti. A partir de TensorFlow y TensorFlow Serving 2.8, estos archivos .proto son los necesarios:

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 generar el código auxiliar de cliente de gRPC:

  1. En tu terminal, navega a la carpeta starter/src/proto/ y, luego, genera el stub:
bash generate_grpc_stub_swift.sh

Se generará una serie de archivos .swift en la carpeta starter/src/proto/generated/import.

  1. Si todavía no se copian en tu proyecto, arrastra todos los archivos .swift generados hasta tu proyecto en Xcode.

9e65705cf6be7aac.png

Crea la solicitud de gRPC

Al igual que con la solicitud de REST, debes crear la solicitud de gRPC en la rama de gRPC.

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

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

}
  • Para crear la solicitud de gRPC, agrega este código a la rama de 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)))

Envía la solicitud de gRPC a TensorFlow Serving

  • Agrega este código a la rama de gRPC inmediatamente después del código en el fragmento de código anterior:
// Send the gRPC request.
let call = stub.predict(request, callOptions: callOptions)

Cómo procesar la respuesta de gRPC de TensorFlow Serving

  • Agrega este código inmediatamente después del código del fragmento 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)")
}

Ahora, la función de procesamiento posterior extrae los valores previstos de la respuesta y muestra el resultado en la IU.

Ejecuta la app

  1. Haz clic en cacc15c5637960ed.png "Run" en el menú de navegación y espera a que Xcode inicie la app en el simulador.
  2. Ingresa un número en el cuadro de texto y haz clic en Inferir.

Ahora verá un valor previsto en la IU.

9. Felicitaciones

Usaste TensorFlow Serving para agregar capacidades de regresión a tu app.

Más información