Serverless Image Classification with Oracle Functions and TensorFlow

Photo by Franck V. on Unsplash

Oracle Functions

What to Expect

Photo by Alan Hardman on Unsplash

The Code

Function Image Input

  • Simple data binding, like handling string input.
  • Binding JSON data types to POJOs. You can customize this because it’s internally implemented using Jackson.
  • Working with raw inputs, enabled by an abstraction of the raw Fn Java FDK events received or returned by the function.
public class LabelImageFunction { 
public String classify(byte[] image) { ...
Tensor<String> input = Tensors.create(image); ...
}
}

Machine Learning Model

  • Training: An algorithm is fed with past (historical) data in order to learn from it (derive patterns) and build a model. Very often, this process is ongoing.
  • Predicting: The generated model is then used to generate predictions or outputs in response to new inputs based on the facts that were learned during the training phase

Function Metadata

schema_version: 20180708 
name: classify
version: 0.0.1
runtime: java
memory: 1024
timeout: 120
triggers:
- name: classify
type: http
source: /classify
  • schema_version represents the version of the specification for this file.
  • name is the name and tag to which this function is pushed.
  • version represents the current version of the function. When deploying, it is appended to the image as a tag.
  • runtime represents the programming language runtime, which is java in this case.
  • memory (optional) is the maximum memory threshold for this function. If this function exceeds this limit during execution, it’s stopped and an error message is logged.
  • timeout (optional) is the maximum time that a function is allowed to run.
  • triggers (optional) is an array of trigger entities that specify triggers for the function. In this case, we’re using an HTTP trigger.

Function Dockerfile

FROM fnproject/fn-java-fdk-build:jdk9-1.0.75 as build-stage 
WORKDIR /function
ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository
ADD pom.xml /function/pom.xml
RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"]
ADD src /function/src
RUN ["mvn", "package"]
FROM fnproject/fn-java-fdk:jdk9-1.0.75
WORKDIR /function
COPY --from=build-stage /function/target/*.jar /function/app/
CMD ["com.example.fn.HelloFunction::handleRequest"]
  • Maven package and build
  • Copying (using COPY) the function JAR and dependencies to the runtime image
  • Setting the command to be executed (using CMD) when the function container is spawned
FROM fnproject/fn-java-fdk-build:jdk9-1.0.75 as build-stage 
WORKDIR /function
ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository ADD pom.xml /function/pom.xml
RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"]'
ARG TENSORFLOW_VERSION=1.12.0
RUN echo "using tensorflow version " $TENSORFLOW_VERSION RUN curl -LJO https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-$TENSORFLOW_VERSION.jar
RUN curl -LJO https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-linux-x86_64-$TENSORFLOW_VERSION.tar.gz RUN tar -xvzf libtensorflow_jni-cpu-linux-x86_64-$TENSORFLOW_VERSION.tar.gz
ADD src /function/src
RUN ["mvn", "package"]
FROM fnproject/fn-java-fdk:jdk9-1.0.75
ARG TENSORFLOW_VERSION=1.12.0
WORKDIR /function
COPY --from=build-stage /function/libtensorflow_jni.so /function/runtime/lib
COPY --from=build-stage /function/libtensorflow_framework.so /function/runtime/lib
COPY --from=build-stage /function/libtensorflow-$TENSORFLOW_VERSION.jar /function/app/
COPY --from=build-stage /function/target/*.jar /function/app/
CMD ["com.example.fn.LabelImageFunction::classify"]
  • Automates TensorFlow setup (per the instructions), extracts the TensorFlow Java SDK and the native JNI (.so) libraries
  • (as part of the second stage of the Docker build) Copies the JNI libraries to /function/runtime/lib and the SDK JAR to /function/app so that they are available to the function at runtime

Deploying to Oracle Functions

curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

Oracle Functions Context

api-url: https://functions.us-phoenix-1.oraclecloud.com oracle.compartment-id: <OCI_compartment_OCID> 
oracle.profile: <profile_name_in_OCI_config>
provider: oracle
registry: <OCI_docker_registry>

Oracle Cloud Infrastructure Configuration

[DEFAULT] 
user=ocid1.user.oc1..exampleuniqueID fingerprint=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34 key_file=~/.oci/oci_api_key.pem tenancy=ocid1.tenancy.oc1..exampleuniqueID pass_phrase=tops3cr3t region=us-ashburn-1
[ORACLE_FUNCTIONS_USER]
user=ocid1.user.oc1..exampleuniqueID fingerprint=72:00:22:7f:d3:8b:47:a4:58:05:b8:95:84:31:dd:0e key_file=/.oci/admin_key.pem tenancy=ocid1.tenancy.oc1..exampleuniqueID pass_phrase=s3cr3t region=us-phoenix-1
fn use context <context_name>

Create the Application

git clone https://github.com/abhirockzz/fn-hello-tensorflow
fn create app <app_name> --annotation oracle.com/oci/subnetIds='["<subnet_ocid>"]'
  • <app_name> is the name of the new application.
  • <subnet_ocid> is the OCID of the subnet in which to run your function.
fn create app fn-tensorflow-app --annotation oracle.com/oci/subnetIds='["ocid1.subnet.oc1.phx.exampleuniqueID","ocid1.subnet.oc1.phx.exampleuniqueID","ocid1.subnet.oc1.phx.exampleuniqueID"]'

Deploy the Function

fn deploy --app <app_name>
fn -v deploy --app fn-tensorflow-app
<dependency> 
<groupId>org.tensorflow</groupId> <artifactId>tensorflow</artifactId>
<version>1.11.0</version>
<scope>provided</scope>
</dependency>
fn -v deploy --app fn-tensorflow-app --build-arg TENSORFLOW_VERSION=<version>
fn -v deploy --app fn-tensorflow-app --build-arg TENSORFLOW_VERSION=1.11.0

Time to Classify Images!

cat <path to image> | fn invoke fn-tensorflow-app classify
cat /Users/abhishek/manwithhat.jpg | fn invoke fn-tensorflow-app classify
“366 • 9 • Gringo” (CC BY-NC-ND 2.0) by Pragmagraphr
This is a ‘sombrero’ Accuracy — 92%
cat /Users/abhishek/terrier.jpg | fn invoke fn-tensorflow-app classify
“Terrier” (CC BY-NC 2.0) by No_Water
This is a 'West Highland white terrier' Accuracy - 88%

Summary

Principal Developer Advocate at AWS | I ❤️ Databases, Go, Kubernetes

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Data Augmentation for ABSA

Source: https://pixabay.com/illustrations/network-web-digital-5113917/

What would abuelita think of machine learning?

DCNet — Denoising (DNA) Sequence With a LSTM-RNN and PyTorch

A Full-Length Machine Learning Course in Python for Free

Building Advanced Regression Techniques to Predict House Price on the Ames Dataset

Introducing FastBert — A simple Deep Learning library for BERT Models

Self-Supervised Learning for Graph Data

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Abhishek Gupta

Abhishek Gupta

Principal Developer Advocate at AWS | I ❤️ Databases, Go, Kubernetes

More from Medium

Apache Airflow: Scaling Using Celery Executor

Apache Airflow(五)Scale out with Celery Executor

Build and Deploy Machine Learning Pipelines on AWS EC2 using Flask, Docker, Kubernetes, Gunicorn…

Installing Apache Airflow using Docker on Windows In Just 5 Minutes