All Projects → stormy-ua → tfModelServing4s

stormy-ua / tfModelServing4s

Licence: MIT license
Reasonable API for serving TensorFlow models using Scala

Programming Languages

scala
5932 projects

Projects that are alternatives of or similar to tfModelServing4s

Seldon Core
An MLOps framework to package, deploy, monitor and manage thousands of production machine learning models
Stars: ✭ 2,815 (+9606.9%)
Mutual labels:  serving
telegram-bot-fs2
Example telegram bot implementation using fs2 and http4s client (no akka)
Stars: ✭ 41 (+41.38%)
Mutual labels:  tagless-final
tagless-final-jam
Workshop On Tagless Final Interpreters
Stars: ✭ 37 (+27.59%)
Mutual labels:  tagless-final
Ray
An open source framework that provides a simple, universal API for building distributed applications. Ray is packaged with RLlib, a scalable reinforcement learning library, and Tune, a scalable hyperparameter tuning library.
Stars: ✭ 18,547 (+63855.17%)
Mutual labels:  serving
bodywork-ml-pipeline-project
Deployment template for a continuous training pipeline.
Stars: ✭ 22 (-24.14%)
Mutual labels:  serving
endless
Scala library to describe sharded and event sourced entities using tagless-final algebras
Stars: ✭ 70 (+141.38%)
Mutual labels:  tagless-final
Keras Serving
bring keras-models to production with tensorflow-serving and nodejs + docker 🍕
Stars: ✭ 150 (+417.24%)
Mutual labels:  serving
spark-ml-serving
Spark ML Lib serving library
Stars: ✭ 49 (+68.97%)
Mutual labels:  serving
spotify-next
Small CLI app for filtering out music on Spotify.
Stars: ✭ 45 (+55.17%)
Mutual labels:  tagless-final
dingo
A Hybrid Serving & Analytical Processing Database.
Stars: ✭ 108 (+272.41%)
Mutual labels:  serving
tagless-final-example
An example of how to create services using tagless final
Stars: ✭ 25 (-13.79%)
Mutual labels:  tagless-final
slipway
Compact binary for integrating Nelson with your CI
Stars: ✭ 15 (-48.28%)
Mutual labels:  reasonable
fasttext-serving
Serve your fastText models for text classification and word vectors
Stars: ✭ 21 (-27.59%)
Mutual labels:  serving
Hydro Serving
MLOps Platform
Stars: ✭ 213 (+634.48%)
Mutual labels:  serving
workshop-edsl-in-typescript
Code template for workshop "Building eDSLs in functional TypeScript"
Stars: ✭ 49 (+68.97%)
Mutual labels:  tagless-final
Tensorflow template application
TensorFlow template application for deep learning
Stars: ✭ 1,851 (+6282.76%)
Mutual labels:  serving
Boostcamp-AI-Tech-Product-Serving
[Machine Learning Engineer Basic Guide] 부스트캠프 AI Tech - Product Serving 자료
Stars: ✭ 280 (+865.52%)
Mutual labels:  serving
zenith
⚡ Functional Scala HTTP server, client, and toolkit.
Stars: ✭ 15 (-48.28%)
Mutual labels:  tagless-final
sagemaker-sparkml-serving-container
This code is used to build & run a Docker container for performing predictions against a Spark ML Pipeline.
Stars: ✭ 44 (+51.72%)
Mutual labels:  serving
tensorflow-serving-arm
TensorFlow Serving ARM - A project for cross-compiling TensorFlow Serving targeting popular ARM cores
Stars: ✭ 75 (+158.62%)
Mutual labels:  serving

tfModelServing4s

Reasonable Scala API for serving TensorFlow models

More details about the library could be found here.

API

The core API algebra is agnostic to TensorFlow itself and could be used for binding to any TensorFlow-like library:

/**
  * Abstract model serving algebra.
  * Defines a set of operations on a pre-built model that is stored
  * somewhere on an external storage.
  *
  * @tparam F Type of the effect used by this algebra.
  */
trait ModelServing[F[_]] {

  // Model type.
  type TModel

  // Tensor type.
  type TTensor

  /**
    * Loads a model from an external source.
    *
    * @param source A source to load a model from.
    * @param tag A tag that could be used to uniquely identify
    *            a concrete computational graph inside a saved model.
    * @return A model.
    */
  def load(source: ModelSource, tag: String): F[TModel]

  /**
    * Queries a model metadata.
    *
    * @param model A model to query metadata for.
    * @return A model metadata wrapped into an effect.
    */
  def metadata(model: TModel): F[ModelMetadata]

  /**
    * Creates a tensor from its representation in the form of a different data structure
    * e.g. Array, List etc.
    *
    * @param data An instance of a data structure for building the tensor.
    * @param shape Shape of the resulting tensor.
    * @param E Tensor encoder to use.
    * @tparam TRepr Type of the data structure to build tensor from.
    * @return A tensor wrapped into an effect.
    */
  def tensor[TRepr](data: TRepr, shape: List[Long])(implicit E: TensorEncoder[TTensor, TRepr]): F[TTensor]

  /**
    * Evaluates a tensor value by feeding a set of input tensors as defined by a signature
    * into the model.
    * @param model A model to use.
    * @param output Output tensor metadata.
    * @param feed Map of a tensor metadata to the tensor to use as an input.
    * @param D Tensor decoder to use.
    * @param C Closeable type class for tensor type being used.
    * @tparam TRepr Type of the data structure to map output tensor to.
    * @return A data structure representing an output tensor calculated by feeding a set
    *         of inputs into the model.
    */
  def eval[TRepr](model: TModel, output: TensorMetadata, feed: Map[TensorMetadata, TTensor])
                 (implicit D: TensorDecoder[TTensor, TRepr], C: Closeable[TTensor]): F[TRepr]

  /**
    * Closes the model and releases all related resources.
    *
    * @param model A model to close.
    * @return Unit.
    */
  def close(model: TModel): F[Unit]
}

The binding for TensorFlow is implemented in TFModelServing.scala.

Example #1

  1. Create a TensorFlow graph and save it using Saved Model API:
import tensorflow as tf
import numpy as np

export_dir = '/tmp/saved_model_1'

builder = tf.saved_model.builder.SavedModelBuilder(export_dir=export_dir)

with tf.Graph().as_default(), tf.Session().as_default() as sess:
    x = tf.placeholder(shape=(2, 3), dtype=tf.float32, name='x')
    y = tf.Variable(np.identity(3), dtype=tf.float32)

    z = tf.matmul(x, y, name='z')

    tf.global_variables_initializer().run()

    zval = z.eval(feed_dict={x: np.random.randn(2, 3)})

    print(zval)

    x_proto_info = tf.saved_model.utils.build_tensor_info(x)
    z_proto_info = tf.saved_model.utils.build_tensor_info(z)

    prediction_signature = (
        tf.saved_model.signature_def_utils.build_signature_def(
            inputs={'x': x_proto_info},
            outputs={'z': z_proto_info},
            method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))

    builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING],
                                         signature_def_map={
                                             tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: prediction_signature
                                         })


builder.save()

The script is available here.

In this example the computational graph simply does matrix multiplication of an input [2x3] matrix and identity [3x3] matrix. The result matrix has to be equal to the input matrix. The model with all variables will be saved into /tmp/saved_model_1 dir.

  1. Load saved model in Scala, read its metadata, feed input matrix into the loaded computational graph and show the output matrix:
import scala.util.Try
import tf._
import tf.implicits._
import dsl._
import utils._
import org.tfModelServing4s.utils.show._
import org.tfModelServing4s.utils.show.implicits._

object Example1 {

  def main(args: Array[String]): Unit = {

    val serving = new TFModelServing

    val progr = for {
      _ <- use(serving.load(FileModelSource("/tmp/saved_model_1"), tag = "serve")) { model =>
        for {
          meta        <- serving.metadata(model)
          _           =  println(s"model metadata: $meta")
          signature   <- Try { meta.signatures("serving_default") }
          _           =  println(s"serving signature: $signature")
          _           =  println(s"serving signature inputs: ${signature.inputs}")
          _           =  println(s"serving signature outputs: ${signature.outputs}")

          inputArray  <- Try { Array.range(0, 6).map(_.toFloat) }
          _           =  println(s"input array = ${shows(inputArray)}")

          _ <- use(serving.tensor(inputArray, shape = List(2, 3))) { inputTensor =>
            for {
              inputDef    <- Try { signature.inputs("x") }
              outputDef   <- Try { signature.outputs("z") }
              outputArray <- serving.eval[Array[Array[Float]]](model, outputDef, Map(inputDef -> inputTensor))
              _           =  println(s"output: ${shows(outputArray)}")
            } yield ()
          }

        } yield ()
      }
    } yield ()

    println(s"Program result = $progr")

  }

}

Output:

model metadata: ModelMetadata(Map(serving_default -> SignatureMetadata(tensorflow/serving/predict,Map(x -> TensorMetadata(x:0,x,DTypeFloat,List(2, 3))),Map(z -> TensorMetadata(z:0,z,DTypeFloat,List(2, 3))))))
serving signature: SignatureMetadata(tensorflow/serving/predict,Map(x -> TensorMetadata(x:0,x,DTypeFloat,List(2, 3))),Map(z -> TensorMetadata(z:0,z,DTypeFloat,List(2, 3))))
serving signature inputs: Map(x -> TensorMetadata(x:0,x,DTypeFloat,List(2, 3)))
serving signature outputs: Map(z -> TensorMetadata(z:0,z,DTypeFloat,List(2, 3)))
input array = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
releasing TF tensor
output: [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0]]
releasing TF tensor
closing TF model
Program result = Success(())

The example sources are here.

Example #2 (Dog Breed Classification)

This repo contains the description how to build dog breed classifier using pre-trained Inception model. The final model gets exported as a "frozen" graph instead of a SavedModel format, though. This script converts frozen model to SavedModel and could be used with this library.

  1. Follow steps to build dog breed classifier as described here
  2. Convert resulting "frozen" model to SavedModel format: python -m src.freezing.frozen_to_saved_model
  3. Use the dog breed classifier saved model to classify an arbitrary dog image:
import scala.util.Try
import tf._
import tf.implicits._
import dsl._
import utils._
import org.tfModelServing4s.utils.show._
import org.tfModelServing4s.utils.show.implicits._
import java.nio.file.{Files, Paths}

object Example2 {

  private def probsToClass(probs: Array[Float]): String = {
    val classes = io.Source.fromInputStream(getClass.getResourceAsStream("/breeds.csv")).getLines().drop(1).toArray
    val top5 = probs.zip(classes).sortBy { case (prob, idx) => prob }.reverse.take(5)

    top5.mkString("\n")
  }

  def main(args: Array[String]): Unit = {

    val imagePath = args(0)
    val serving = new TFModelServing

    val progr = for {
      _ <- use(serving.load(FileModelSource("/tmp/dogs_1"), tag = "serve")) { model =>
        for {
          meta        <- serving.metadata(model)
          _           =  println(s"model metadata: $meta")
          signature   <- Try { meta.signatures("serving_default") }
          _           =  println(s"serving signature: $signature")
          _           =  println(s"serving signature inputs: ${signature.inputs}")
          _           =  println(s"serving signature outputs: ${signature.outputs}")

          inputArray  <- Try { Array.range(0, 6).map(_.toFloat) }
          _           =  println(s"input array = ${shows(inputArray)}")

          img         <- Try {
            Files.readAllBytes(Paths.get(imagePath))
          }
          _           <- use(serving.tensor(img, shape = List(1))) { inputTensor =>
            for {
              inputDef    <- Try { signature.inputs("image_raw") }
              outputDef   <- Try { signature.outputs("probs") }
              outputArray <- serving.eval[Array[Array[Float]]](model, outputDef, Map(inputDef -> inputTensor))
              _           =  println(s"output: ${shows(outputArray)}")
              clazz       <- Try { probsToClass(outputArray.flatten) }
              _           = println(clazz)
            } yield ()
          }

        } yield ()
      }
    } yield ()

    println(s"Program result = $progr")

  }

}

Here is the output for the sample dog image:

(0.9796268,3,airedale)
(0.00985535,83,otterhound)
(0.007160045,57,irish_terrier)
(0.0015072817,28,chesapeake_bay_retriever)
(8.2421233E-4,118,wire-haired_fox_terrier)

The model outputs probabilities array which gets mapped into top 5 breeds together with their probabilities.

The example source code is here.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].